Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix scrollbar jump #918

Merged
merged 3 commits into from
Mar 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,21 @@ public void all_par_to_visible_par_index_is_correct() {
assertEquals(Optional.of(area.getVisibleParagraphs().size() - 1), area.allParToVisibleParIndex(LAST_PAR_INDEX));
}

@Test
public void all_par_to_visible_par_index_after_replace() {
interact(() -> {
area.clear();
area.replaceText( "123\nabc" );
});

interact(() -> area.replaceText( "123\nxyz" ));

interact(() -> {
assertEquals(Optional.of(1), area.allParToVisibleParIndex(1));
assertEquals(Optional.of(0), area.allParToVisibleParIndex(0));
});
}

@Test
public void visible_par_to_all_par_index_is_correct() {
interact(() -> area.showParagraphAtTop(0));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,37 @@
package org.fxmisc.richtext.api;

import org.fxmisc.richtext.InlineCssTextAreaAppTest;
import static org.junit.Assert.assertEquals;
import org.junit.Test;

public class ReplaceTextTests extends InlineCssTextAreaAppTest {

@Test
public void replaceText_does_not_cause_index_out_of_bounds_exception()
{
interact( () ->
{
String test = "abc\n";
area.replaceText( test );
area.insertText( 0, test +"def\n" );

// An IndexOutOfBoundsException occurs when trimming MaterializedListModification
// in GenericEditableStyledDocumentBase.ParagraphList.observeInputs()
area.replaceText( test );
assertEquals( test, area.getText() );

area.clear();
area.replaceText( test );
area.appendText( test +"def" );

// An IndexOutOfBoundsException occurs when trimming MaterializedListModification
// in GenericEditableStyledDocumentBase.ParagraphList.observeInputs()
area.replaceText( test +"def" );
assertEquals( test +"def", area.getText() );
});

}

@Test
public void deselect_before_replaceText_does_not_cause_index_out_of_bounds_exception()
{
Expand Down
21 changes: 10 additions & 11 deletions richtextfx/src/main/java/org/fxmisc/richtext/GenericStyledArea.java
Original file line number Diff line number Diff line change
Expand Up @@ -864,10 +864,15 @@ public final Optional<Integer> allParToVisibleParIndex(int allParIndex) {
getParagraphs().size() - 1, allParIndex)
);
}
Paragraph<PS, SEG, S> p = getParagraph(allParIndex);
for (int index = 0; index < getVisibleParagraphs().size(); index++) {
if (getVisibleParagraphs().get(index) == p) {
return Optional.of(index);
List<Cell<Paragraph<PS, SEG, S>, ParagraphBox<PS, SEG, S>>> visibleList = virtualFlow.visibleCells();
int firstVisibleParIndex = visibleList.get( 0 ).getNode().getIndex();
int targetIndex = allParIndex - firstVisibleParIndex;

if ( allParIndex >= firstVisibleParIndex && targetIndex < visibleList.size() )
{
if ( visibleList.get( targetIndex ).getNode().getIndex() == allParIndex )
{
return Optional.of( targetIndex );
}
}
return Optional.empty();
Expand All @@ -884,13 +889,7 @@ public final int visibleParToAllParIndex(int visibleParIndex) {
getVisibleParagraphs().size() - 1, visibleParIndex)
);
}
Paragraph<PS, SEG, S> visibleP = getVisibleParagraphs().get(visibleParIndex);
for (int index = 0; index < getParagraphs().size(); index++) {
if (getParagraph(index) == visibleP) {
return index;
}
}
throw new AssertionError("Unreachable code");
return virtualFlow.visibleCells().get( visibleParIndex ).getNode().getIndex();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ protected Subscription observeInputs() {
return parChangesList.subscribe(list -> {
ListChangeAccumulator<Paragraph<PS, SEG, S>> accumulator = new ListChangeAccumulator<>();
for (MaterializedListModification<Paragraph<PS, SEG, S>> mod : list) {
mod = trim(mod);
try { mod = mod.trim(); } catch ( IndexOutOfBoundsException EX ) {}

// add the quasiListModification itself, not as a quasiListChange, in case some overlap
accumulator.add(QuasiListModification.create(mod.getFrom(), mod.getRemoved(), mod.getAddedSize()));
Expand Down Expand Up @@ -221,72 +221,4 @@ private void updateMulti(
});
}

/**
* Copy of org.reactfx.collection.MaterializedListModification.trim()
* that uses reference comparison instead of equals().
*/
private MaterializedListModification<Paragraph<PS, SEG, S>> trim(MaterializedListModification<Paragraph<PS, SEG, S>> mod) {
return commonPrefixSuffixLengths(mod.getRemoved(), mod.getAdded()).map((pref, suff) -> {
if(pref == 0 && suff == 0) {
return mod;
} else {
return MaterializedListModification.create(
mod.getFrom() + pref,
mod.getRemoved().subList(pref, mod.getRemovedSize() - suff),
mod.getAdded().subList(pref, mod.getAddedSize() - suff));
}
});
}

/**
* Copy of org.reactfx.util.Lists.commonPrefixSuffixLengths()
* that uses reference comparison instead of equals().
*/
private static Tuple2<Integer, Integer> commonPrefixSuffixLengths(List<?> l1, List<?> l2) {
int n1 = l1.size();
int n2 = l2.size();

if(n1 == 0 || n2 == 0) {
return Tuples.t(0, 0);
}

int pref = commonPrefixLength(l1, l2);
if(pref == n1 || pref == n2) {
return Tuples.t(pref, 0);
}

int suff = commonSuffixLength(l1, l2);

return Tuples.t(pref, suff);
}

/**
* Copy of org.reactfx.util.Lists.commonPrefixLength()
* that uses reference comparison instead of equals().
*/
private static int commonPrefixLength(List<?> l, List<?> m) {
ListIterator<?> i = l.listIterator();
ListIterator<?> j = m.listIterator();
while(i.hasNext() && j.hasNext()) {
if(i.next() != j.next()) {
return i.nextIndex() - 1;
}
}
return i.nextIndex();
}

/**
* Copy of org.reactfx.util.Lists.commonSuffixLength()
* that uses reference comparison instead of equals().
*/
private static int commonSuffixLength(List<?> l, List<?> m) {
ListIterator<?> i = l.listIterator(l.size());
ListIterator<?> j = m.listIterator(m.size());
while(i.hasPrevious() && j.hasPrevious()) {
if(i.previous() != j.previous()) {
return l.size() - i.nextIndex() - 1;
}
}
return l.size() - i.nextIndex();
}
}