SideBySide2: Replace system scrollbar with one on the overview

Draw the viewport as a semi-transparent box on top of the overview bar
on the right side of SideBySide2.  This allows the reader to see how
much of the visible file content is currently displayed.

Handle drag events on this box and translate them into scroll events
on the CM3 instances.  This allows the reader to grab the viewport
representation with the mouse and move it over another section.

Make the height of each edit insert, delete or edit region related to
the number of lines impacted.  Regions that touch more lines will take
up more vertical space on the overview bar.

Remove the scrollbar from the B CM3.  Rely on keyboard up/down, page
up/down, mouse wheel, and dragging the viewport widget placed in the
overview bar area.

Change-Id: Ica0355a4b5f4a350b2db6c8557186fbb4758a24f
This commit is contained in:
Shawn Pearce
2014-01-13 17:35:26 -08:00
parent e79006600f
commit 13f9a60c3e
14 changed files with 257 additions and 165 deletions

View File

@@ -14,6 +14,10 @@
package com.google.gerrit.client.diff; package com.google.gerrit.client.diff;
import static com.google.gerrit.client.diff.OverviewBar.MarkType.DELETE;
import static com.google.gerrit.client.diff.OverviewBar.MarkType.EDIT;
import static com.google.gerrit.client.diff.OverviewBar.MarkType.INSERT;
import com.google.gerrit.client.diff.DiffInfo.Region; import com.google.gerrit.client.diff.DiffInfo.Region;
import com.google.gerrit.client.diff.DiffInfo.Span; import com.google.gerrit.client.diff.DiffInfo.Span;
import com.google.gerrit.client.rpc.Natives; import com.google.gerrit.client.rpc.Natives;
@@ -143,11 +147,11 @@ class ChunkManager {
private void addGutterTag(Region region, int startA, int startB) { private void addGutterTag(Region region, int startA, int startB) {
if (region.a() == null) { if (region.a() == null) {
sidePanel.addGutter(cmB, startB, OverviewBar.GutterType.INSERT); sidePanel.add(cmB, startB, region.b().length(), INSERT);
} else if (region.b() == null) { } else if (region.b() == null) {
sidePanel.addGutter(cmA, startA, OverviewBar.GutterType.DELETE); sidePanel.add(cmA, startA, region.a().length(), DELETE);
} else { } else {
sidePanel.addGutter(cmB, startB, OverviewBar.GutterType.EDIT); sidePanel.add(cmB, startB, region.b().length(), EDIT);
} }
} }

View File

@@ -15,7 +15,6 @@
package com.google.gerrit.client.diff; package com.google.gerrit.client.diff;
import com.google.gerrit.client.changes.CommentInfo; import com.google.gerrit.client.changes.CommentInfo;
import com.google.gerrit.client.diff.OverviewBar.GutterWrapper;
import com.google.gwt.event.dom.client.MouseOutEvent; import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler; import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent; import com.google.gwt.event.dom.client.MouseOverEvent;
@@ -34,7 +33,7 @@ abstract class CommentBox extends Composite {
} }
private final CommentGroup group; private final CommentGroup group;
private GutterWrapper gutterWrapper; private OverviewBar.MarkHandle mark;
private FromTo fromTo; private FromTo fromTo;
private TextMarker rangeMarker; private TextMarker rangeMarker;
private TextMarker rangeHighlightMarker; private TextMarker rangeHighlightMarker;
@@ -80,8 +79,12 @@ abstract class CommentBox extends Composite {
return group.getCommentManager(); return group.getCommentManager();
} }
void setGutterWrapper(GutterWrapper wrapper) { OverviewBar.MarkHandle getMark() {
gutterWrapper = wrapper; return mark;
}
void setMark(OverviewBar.MarkHandle mh) {
mark = mh;
} }
void setRangeHighlight(boolean highlight) { void setRangeHighlight(boolean highlight) {
@@ -106,10 +109,6 @@ abstract class CommentBox extends Composite {
} }
} }
GutterWrapper getGutterWrapper() {
return gutterWrapper;
}
CodeMirror getCm() { CodeMirror getCm() {
return group.getCm(); return group.getCm();
} }

View File

@@ -157,10 +157,10 @@ class CommentManager {
getPatchSetIdFromSide(side), getPatchSetIdFromSide(side),
info); info);
group.add(box); group.add(box);
box.setGutterWrapper(host.diffTable.overview.addGutter( box.setMark(host.diffTable.overview.add(
host.getCmFromSide(side), host.getCmFromSide(side),
Math.max(0, info.line() - 1), Math.max(0, info.line() - 1), 1,
OverviewBar.GutterType.COMMENT)); OverviewBar.MarkType.COMMENT));
published.put(info.id(), box); published.put(info.id(), box);
} }
} }
@@ -220,10 +220,10 @@ class CommentManager {
} }
group.add(box); group.add(box);
box.setGutterWrapper(host.diffTable.overview.addGutter( box.setMark(host.diffTable.overview.add(
host.getCmFromSide(side), host.getCmFromSide(side),
Math.max(0, info.line() - 1), Math.max(0, info.line() - 1), 1,
OverviewBar.GutterType.DRAFT)); OverviewBar.MarkType.DRAFT));
return box; return box;
} }

View File

@@ -58,11 +58,15 @@ limitations under the License.
} }
.table td { padding: 0 } .table td { padding: 0 }
.a, .b { width: 50% } .a, .b { width: 50% }
.overview { width: 10px }
/* Hide left side scrollbar, right side controls both views. */ .overview {
.a .CodeMirror-scroll { padding-right: 0; } width: 10px;
.a .CodeMirror-vscrollbar { display: none !important; } vertical-align: top;
}
/* Hide scrollbars, OverviewBar controls both views. */
.difftable .CodeMirror-scroll { padding-right: 0; }
.difftable .CodeMirror-vscrollbar { display: none !important; }
.showLineNumbers .b { border-left: none; } .showLineNumbers .b { border-left: none; }
.b { border-left: 1px solid #ddd; } .b { border-left: 1px solid #ddd; }

View File

@@ -233,7 +233,7 @@ class DraftBox extends CommentBox {
getCommentManager().setUnsaved(this, false); getCommentManager().setUnsaved(this, false);
setRangeHighlight(false); setRangeHighlight(false);
clearRange(); clearRange();
getGutterWrapper().remove(); getMark().remove();
getCommentGroup().remove(this); getCommentGroup().remove(this);
getCm().focus(); getCm().focus();
} }

View File

@@ -15,28 +15,34 @@
package com.google.gerrit.client.diff; package com.google.gerrit.client.diff;
import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler; import com.google.gwt.dom.client.Element;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.resources.client.CssResource; import com.google.gwt.resources.client.CssResource;
import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import net.codemirror.lib.CodeMirror; import net.codemirror.lib.CodeMirror;
import net.codemirror.lib.LineCharacter; import net.codemirror.lib.LineCharacter;
import net.codemirror.lib.ScrollInfo;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
/** Displays overview of all edits and comments in this file. */ /** Displays overview of all edits and comments in this file. */
class OverviewBar extends Composite { class OverviewBar extends Composite implements ClickHandler {
interface Binder extends UiBinder<HTMLPanel, OverviewBar> {} interface Binder extends UiBinder<HTMLPanel, OverviewBar> {}
private static final Binder uiBinder = GWT.create(Binder.class); private static final Binder uiBinder = GWT.create(Binder.class);
@@ -47,136 +53,199 @@ class OverviewBar extends Composite {
String draft(); String draft();
String insert(); String insert();
String delete(); String delete();
String viewportDrag();
} }
enum GutterType { enum MarkType {
COMMENT, DRAFT, INSERT, DELETE, EDIT COMMENT, DRAFT, INSERT, DELETE, EDIT
} }
@UiField @UiField Style style;
Style style; @UiField Label viewport;
private List<GutterWrapper> gutters; private final List<MarkHandle> diff;
private final Set<MarkHandle> comments;
private CodeMirror cmB; private CodeMirror cmB;
private boolean dragging;
private int startY;
private double ratio;
OverviewBar() { OverviewBar() {
initWidget(uiBinder.createAndBindUi(this)); initWidget(uiBinder.createAndBindUi(this));
gutters = new ArrayList<GutterWrapper>(); diff = new ArrayList<MarkHandle>();
comments = new HashSet<MarkHandle>();
addDomHandler(this, ClickEvent.getType());
} }
GutterWrapper addGutter(CodeMirror cm, int line, GutterType type) { void init(CodeMirror cmB) {
Label gutter = new Label(); this.cmB = cmB;
GutterWrapper info = new GutterWrapper(this, gutter, cm, line, type); }
adjustGutter(info);
gutter.addStyleName(style.gutter()); void refresh() {
update(cmB.getScrollInfo());
}
void update(ScrollInfo si) {
double viewHeight = si.getClientHeight();
double r = ratio(si);
com.google.gwt.dom.client.Style style = viewport.getElement().getStyle();
style.setTop(si.getTop() * r, Unit.PX);
style.setHeight(Math.max(10, viewHeight * r), Unit.PX);
getElement().getStyle().setHeight(viewHeight, Unit.PX);
for (MarkHandle info : diff) {
info.position(r);
}
for (MarkHandle info : comments) {
info.position(r);
}
}
@Override
protected void onUnload() {
super.onUnload();
if (dragging) {
DOM.releaseCapture(viewport.getElement());
}
}
@Override
public void onClick(ClickEvent e) {
if (e.getY() < viewport.getElement().getOffsetTop()) {
CodeMirror.handleVimKey(cmB, "<PageUp>");
} else {
CodeMirror.handleVimKey(cmB, "<PageDown>");
}
cmB.focus();
}
@UiHandler("viewport")
void onMouseDown(MouseDownEvent e) {
if (cmB != null) {
dragging = true;
ratio = ratio(cmB.getScrollInfo());
startY = e.getY();
viewport.addStyleName(style.viewportDrag());
DOM.setCapture(viewport.getElement());
e.preventDefault();
e.stopPropagation();
}
}
@UiHandler("viewport")
void onMouseMove(MouseMoveEvent e) {
if (dragging) {
int y = e.getRelativeY(getElement()) - startY;
cmB.scrollToY(Math.max(0, y / ratio));
e.preventDefault();
e.stopPropagation();
}
}
@UiHandler("viewport")
void onMouseUp(MouseUpEvent e) {
if (dragging) {
dragging = false;
DOM.releaseCapture(viewport.getElement());
viewport.removeStyleName(style.viewportDrag());
e.preventDefault();
e.stopPropagation();
}
}
private double ratio(ScrollInfo si) {
double barHeight = si.getClientHeight();
double contentHeight = si.getHeight();
return barHeight / contentHeight;
}
MarkHandle add(CodeMirror cm, int line, int height, MarkType type) {
MarkHandle mark = new MarkHandle(cm, line, height);
switch (type) { switch (type) {
case COMMENT: case COMMENT:
gutter.addStyleName(style.comment()); mark.addStyleName(style.comment());
comments.add(mark);
break; break;
case DRAFT: case DRAFT:
gutter.addStyleName(style.draft()); mark.addStyleName(style.draft());
gutter.setText("*"); mark.getElement().setInnerText("*");
comments.add(mark);
break; break;
case INSERT: case INSERT:
gutter.addStyleName(style.insert()); mark.addStyleName(style.insert());
diff.add(mark);
break; break;
case DELETE: case DELETE:
gutter.addStyleName(style.delete()); mark.addStyleName(style.delete());
diff.add(mark);
break; break;
case EDIT: case EDIT:
gutter.addStyleName(style.insert()); mark.edit = DOM.createDiv();
Label labelLeft = new Label(); mark.edit.setClassName(style.halfGutter());
labelLeft.addStyleName(style.halfGutter()); mark.getElement().appendChild(mark.edit);
gutter.getElement().appendChild(labelLeft.getElement()); mark.addStyleName(style.insert());
diff.add(mark);
break;
} }
((HTMLPanel) getWidget()).add(gutter); if (cmB != null) {
gutters.add(info); mark.position(ratio(cmB.getScrollInfo()));
return info;
}
void adjustGutters(CodeMirror cmB) {
this.cmB = cmB;
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
for (GutterWrapper info : gutters) {
adjustGutter(info);
}
}
});
}
private void adjustGutter(GutterWrapper wrapper) {
if (cmB == null) {
return;
} }
final CodeMirror cm = wrapper.cm; ((HTMLPanel) getWidget()).add(mark);
final int line = wrapper.line; return mark;
Label gutter = wrapper.gutter; }
final double height = cm.heightAtLine(line, "local");
final double scrollbarHeight = cmB.getScrollbarV().getClientHeight(); void clearDiffMarkers() {
double top = height / cmB.getSizer().getClientHeight() * for (MarkHandle mark : diff) {
scrollbarHeight + mark.removeFromParent();
cmB.getScrollbarV().getAbsoluteTop();
if (top == 0) {
top = -10;
} }
gutter.getElement().getStyle().setTop(top, Unit.PX); diff.clear();
wrapper.replaceClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
cm.setCursor(LineCharacter.create(line));
cm.scrollToY(height - 0.5 * scrollbarHeight);
cm.focus();
}
});
} }
void removeGutter(GutterWrapper wrapper) { class MarkHandle extends Widget implements ClickHandler {
gutters.remove(wrapper); private static final int MIN_HEIGHT = 3;
}
@SuppressWarnings("incomplete-switch") private final CodeMirror cm;
void clearDiffGutters() { private final int line;
for (Iterator<GutterWrapper> i = gutters.iterator(); i.hasNext();) { private final int height;
GutterWrapper wrapper = i.next(); private Element edit;
switch (wrapper.type) {
case INSERT:
case DELETE:
case EDIT:
wrapper.gutter.removeFromParent();
i.remove();
}
}
}
static class GutterWrapper { MarkHandle(CodeMirror cm, int line, int height) {
private OverviewBar host;
private Label gutter;
private CodeMirror cm;
private int line;
private HandlerRegistration regClick;
private GutterType type;
GutterWrapper(OverviewBar host, Label anchor, CodeMirror cm, int line,
GutterType type) {
this.host = host;
this.gutter = anchor;
this.cm = cm; this.cm = cm;
this.line = line; this.line = line;
this.type = type; this.height = height;
setElement(DOM.createDiv());
setStyleName(style.gutter());
addDomHandler(this, ClickEvent.getType());
} }
private void replaceClickHandler(ClickHandler newHandler) { void position(double ratio) {
if (regClick != null) { double y = cm.heightAtLine(line, "local");
regClick.removeHandler(); getElement().getStyle().setTop(y * ratio, Unit.PX);
if (height > 1) {
double e = cm.heightAtLine(line + height, "local");
double h = Math.max(MIN_HEIGHT, (e - y) * ratio);
getElement().getStyle().setHeight(h, Unit.PX);
if (edit != null) {
edit.getStyle().setHeight(h, Unit.PX);
}
} }
regClick = gutter.addClickHandler(newHandler); }
@Override
public void onClick(ClickEvent event) {
double y = cm.heightAtLine(line, "local");
double viewport = cm.getScrollInfo().getClientHeight();
cm.setCursor(LineCharacter.create(line));
cm.scrollToY(y - 0.5 * viewport);
cm.focus();
} }
void remove() { void remove() {
gutter.removeFromParent(); removeFromParent();
host.removeGutter(this); comments.remove(this);
} }
} }
} }

View File

@@ -17,22 +17,27 @@ limitations under the License.
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' <ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'> xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:style type='com.google.gerrit.client.diff.OverviewBar.Style'> <ui:style type='com.google.gerrit.client.diff.OverviewBar.Style'>
.overview {
position: relative;
}
.gutter { .gutter {
cursor: pointer; cursor: pointer;
position: fixed; position: absolute;
height: 3px; height: 3px;
width: 10px; width: 6px;
border: 1px solid black; border: 1px solid grey;
margin-left: 1px;
} }
.halfGutter { .halfGutter {
cursor: pointer; cursor: pointer;
position: fixed; position: absolute;
height: 3px; height: 3px;
width: 5px; width: 3px;
background-color: #faa; background-color: #faa;
} }
.comment, .draft { .comment, .draft {
background-color: #e5ecf9; background-color: #fcfa96;
z-index: 2;
} }
.draft { .draft {
text-align: center; text-align: center;
@@ -47,6 +52,20 @@ limitations under the License.
.insert { .insert {
background-color: #9f9; background-color: #9f9;
} }
.viewport {
position: absolute;
background-color: rgba(128, 128, 128, 0.50);
border: 1px solid #444;
width: 8px;
cursor: default;
z-index: 3;
border-radius: 4px;
}
.viewportDrag {
cursor: move;
}
</ui:style> </ui:style>
<g:HTMLPanel/> <g:HTMLPanel styleName='{style.overview}'>
</ui:UiBinder> <g:Label ui:field='viewport' styleName='{style.viewport}'/>
</g:HTMLPanel>
</ui:UiBinder>

View File

@@ -22,6 +22,7 @@ import net.codemirror.lib.ScrollInfo;
class ScrollSynchronizer { class ScrollSynchronizer {
private DiffTable diffTable; private DiffTable diffTable;
private LineMapper mapper; private LineMapper mapper;
private OverviewBar overview;
private ScrollCallback active; private ScrollCallback active;
ScrollSynchronizer(DiffTable diffTable, ScrollSynchronizer(DiffTable diffTable,
@@ -29,6 +30,7 @@ class ScrollSynchronizer {
LineMapper mapper) { LineMapper mapper) {
this.diffTable = diffTable; this.diffTable = diffTable;
this.mapper = mapper; this.mapper = mapper;
this.overview = diffTable.overview;
cmA.on("scroll", new ScrollCallback(cmA, cmB, DisplaySide.A)); cmA.on("scroll", new ScrollCallback(cmA, cmB, DisplaySide.A));
cmB.on("scroll", new ScrollCallback(cmB, cmA, DisplaySide.B)); cmB.on("scroll", new ScrollCallback(cmB, cmA, DisplaySide.B));
@@ -73,6 +75,7 @@ class ScrollSynchronizer {
if (active == this) { if (active == this) {
ScrollInfo si = src.getScrollInfo(); ScrollInfo si = src.getScrollInfo();
updateScreenHeader(si); updateScreenHeader(si);
overview.update(si);
dst.scrollTo(si.getLeft(), align(si.getTop())); dst.scrollTo(si.getLeft(), align(si.getTop()));
state = 0; state = 0;
} }

View File

@@ -64,7 +64,6 @@ import net.codemirror.lib.CodeMirror.BeforeSelectionChangeHandler;
import net.codemirror.lib.CodeMirror.GutterClickHandler; import net.codemirror.lib.CodeMirror.GutterClickHandler;
import net.codemirror.lib.CodeMirror.LineClassWhere; import net.codemirror.lib.CodeMirror.LineClassWhere;
import net.codemirror.lib.CodeMirror.LineHandle; import net.codemirror.lib.CodeMirror.LineHandle;
import net.codemirror.lib.CodeMirror.Viewport;
import net.codemirror.lib.Configuration; import net.codemirror.lib.Configuration;
import net.codemirror.lib.KeyMap; import net.codemirror.lib.KeyMap;
import net.codemirror.lib.LineCharacter; import net.codemirror.lib.LineCharacter;
@@ -228,7 +227,7 @@ public class SideBySide2 extends Screen {
} }
}); });
setLineLength(prefs.lineLength()); setLineLength(prefs.lineLength());
diffTable.overview.adjustGutters(cmB); diffTable.overview.refresh();
if (startLine == 0 && diff.meta_b() != null) { if (startLine == 0 && diff.meta_b() != null) {
DiffChunkInfo d = chunkManager.getFirst(); DiffChunkInfo d = chunkManager.getFirst();
@@ -294,7 +293,6 @@ public class SideBySide2 extends Screen {
cm.on("beforeSelectionChange", onSelectionChange(cm)); cm.on("beforeSelectionChange", onSelectionChange(cm));
cm.on("cursorActivity", updateActiveLine(cm)); cm.on("cursorActivity", updateActiveLine(cm));
cm.on("gutterClick", onGutterClick(cm)); cm.on("gutterClick", onGutterClick(cm));
cm.on("viewportChange", adjustGutters(cm));
cm.on("focus", updateActiveLine(cm)); cm.on("focus", updateActiveLine(cm));
cm.addKeyMap(KeyMap.create() cm.addKeyMap(KeyMap.create()
.on("'a'", upToChange(true)) .on("'a'", upToChange(true))
@@ -466,6 +464,7 @@ public class SideBySide2 extends Screen {
cmA = newCM(diff.meta_a(), diff.text_a(), DisplaySide.A, diffTable.cmA); cmA = newCM(diff.meta_a(), diff.text_a(), DisplaySide.A, diffTable.cmA);
cmB = newCM(diff.meta_b(), diff.text_b(), DisplaySide.B, diffTable.cmB); cmB = newCM(diff.meta_b(), diff.text_b(), DisplaySide.B, diffTable.cmB);
diffTable.overview.init(cmB);
chunkManager = new ChunkManager(this, cmA, cmB, diffTable.overview); chunkManager = new ChunkManager(this, cmA, cmB, diffTable.overview);
skipManager = new SkipManager(this, commentManager); skipManager = new SkipManager(this, commentManager);
@@ -606,6 +605,7 @@ public class SideBySide2 extends Screen {
public void run() { public void run() {
skipManager.removeAll(); skipManager.removeAll();
skipManager.render(context, diff); skipManager.render(context, diff);
diffTable.overview.refresh();
} }
}); });
} }
@@ -636,21 +636,6 @@ public class SideBySide2 extends Screen {
} }
} }
private Runnable adjustGutters(final CodeMirror cm) {
return new Runnable() {
@Override
public void run() {
Viewport fromTo = cm.getViewport();
int size = fromTo.getTo() - fromTo.getFrom() + 1;
if (cm.getOldViewportSize() == size) {
return;
}
cm.setOldViewportSize(size);
diffTable.overview.adjustGutters(cmB);
}
};
}
private Runnable updateActiveLine(final CodeMirror cm) { private Runnable updateActiveLine(final CodeMirror cm) {
final CodeMirror other = otherCm(cm); final CodeMirror other = otherCm(cm);
return new Runnable() { return new Runnable() {
@@ -789,7 +774,7 @@ public class SideBySide2 extends Screen {
int height = getCodeMirrorHeight(); int height = getCodeMirrorHeight();
cmA.setHeight(height); cmA.setHeight(height);
cmB.setHeight(height); cmB.setHeight(height);
diffTable.overview.adjustGutters(cmB); diffTable.overview.refresh();
} }
private int getCodeMirrorHeight() { private int getCodeMirrorHeight() {
@@ -886,7 +871,7 @@ public class SideBySide2 extends Screen {
public void run() { public void run() {
skipManager.removeAll(); skipManager.removeAll();
chunkManager.reset(); chunkManager.reset();
diffTable.overview.clearDiffGutters(); diffTable.overview.clearDiffMarkers();
setShowIntraline(prefs.intralineDifference()); setShowIntraline(prefs.intralineDifference());
render(diff); render(diff);
skipManager.render(prefs.context(), diff); skipManager.render(prefs.context(), diff);

View File

@@ -17,7 +17,13 @@ limitations under the License.
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' <ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui' xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:d='urn:import:com.google.gerrit.client.diff'> xmlns:d='urn:import:com.google.gerrit.client.diff'>
<g:FlowPanel> <ui:style>
.sbs2 {
margin-left: -5px;
margin-right: -5px;
}
</ui:style>
<g:FlowPanel styleName='{style.sbs2}'>
<d:Header ui:field='header'/> <d:Header ui:field='header'/>
<d:DiffTable ui:field='diffTable'/> <d:DiffTable ui:field='diffTable'/>
</g:FlowPanel> </g:FlowPanel>

View File

@@ -132,6 +132,7 @@ class SkipBar extends Composite {
void expandBefore(int cnt) { void expandBefore(int cnt) {
expandSideBefore(cnt); expandSideBefore(cnt);
otherBar.expandSideBefore(cnt); otherBar.expandSideBefore(cnt);
manager.getOverviewBar().refresh();
} }
private void expandSideBefore(int cnt) { private void expandSideBefore(int cnt) {
@@ -183,6 +184,7 @@ class SkipBar extends Composite {
expandSideAll(); expandSideAll();
otherBar.expandSideAll(); otherBar.expandSideAll();
manager.remove(this, otherBar); manager.remove(this, otherBar);
manager.getOverviewBar().refresh();
} }
@UiHandler("upArrow") @UiHandler("upArrow")
@@ -195,6 +197,7 @@ class SkipBar extends Composite {
void onExpandAfter(ClickEvent e) { void onExpandAfter(ClickEvent e) {
expandAfter(); expandAfter();
otherBar.expandAfter(); otherBar.expandAfter();
manager.getOverviewBar().refresh();
cm.focus(); cm.focus();
} }
} }

View File

@@ -38,6 +38,10 @@ class SkipManager {
this.commentManager = commentManager; this.commentManager = commentManager;
} }
OverviewBar getOverviewBar() {
return host.diffTable.overview;
}
void render(int context, DiffInfo diff) { void render(int context, DiffInfo diff) {
if (context == AccountDiffPreference.WHOLE_FILE_CONTEXT) { if (context == AccountDiffPreference.WHOLE_FILE_CONTEXT) {
return; return;
@@ -106,6 +110,7 @@ class SkipManager {
for (SkipBar bar : skipBars) { for (SkipBar bar : skipBars) {
bar.expandSideAll(); bar.expandSideAll();
} }
getOverviewBar().refresh();
skipBars = null; skipBars = null;
line0 = null; line0 = null;
} }

View File

@@ -168,14 +168,6 @@ public class CodeMirror extends JavaScriptObject {
return this.getViewport(); return this.getViewport();
}-*/; }-*/;
public final native int getOldViewportSize() /*-{
return this.state.oldViewportSize || 0;
}-*/;
public final native void setOldViewportSize(int lines) /*-{
this.state.oldViewportSize = lines;
}-*/;
public final native void operation(Runnable thunk) /*-{ public final native void operation(Runnable thunk) /*-{
this.operation(function() { this.operation(function() {
thunk.@java.lang.Runnable::run()(); thunk.@java.lang.Runnable::run()();

View File

@@ -16,19 +16,22 @@ package net.codemirror.lib;
import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JavaScriptObject;
/** {left, top, width, height, clientWidth, clientHeight} objects returned by /** Returned by {@link CodeMirror#getScrollInfo()}. */
* getScrollInfo(). */
public class ScrollInfo extends JavaScriptObject { public class ScrollInfo extends JavaScriptObject {
public static ScrollInfo create() {
return createObject().cast();
}
public final native double getLeft() /*-{ return this.left; }-*/; public final native double getLeft() /*-{ return this.left; }-*/;
public final native double getTop() /*-{ return this.top; }-*/; public final native double getTop() /*-{ return this.top; }-*/;
public final native double getWidth() /*-{ return this.width; }-*/;
/**
* Pixel height of the full content being scrolled. This may only be an
* estimate given by CodeMirror. Line widgets further down in the document may
* not be measured, so line heights can be incorrect until drawn.
*/
public final native double getHeight() /*-{ return this.height; }-*/; public final native double getHeight() /*-{ return this.height; }-*/;
public final native double getClientWidth() /*-{ return this.clientWidth; }-*/; public final native double getWidth() /*-{ return this.width; }-*/;
/** Visible height of the viewport, excluding scrollbars. */
public final native double getClientHeight() /*-{ return this.clientHeight; }-*/; public final native double getClientHeight() /*-{ return this.clientHeight; }-*/;
public final native double getClientWidth() /*-{ return this.clientWidth; }-*/;
protected ScrollInfo() { protected ScrollInfo() {
} }