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

NPE in clipboard copy #573

Closed
JFormDesigner opened this issue Sep 6, 2017 · 5 comments · Fixed by #590
Closed

NPE in clipboard copy #573

JFormDesigner opened this issue Sep 6, 2017 · 5 comments · Fixed by #590

Comments

@JFormDesigner
Copy link
Contributor

I get an NPE when pressing Ctrl+C, but only if the selection includes a line separator and ends at the beginning of a line.

This is a regression. Used 0.7-M3 before where it worked. So I checked out various commits to find out the commit that broke it. It is commit a2aa881. It works when I checkout the previous commit.

To reproduce, run this little app and press Ctrl+C:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.fxmisc.flowless.VirtualizedScrollPane;
import org.fxmisc.richtext.CodeArea;

public class ClipboardCopyNPE extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        CodeArea area = new CodeArea("abc\ndef\nghi");
        VirtualizedScrollPane<CodeArea> vsPane = new VirtualizedScrollPane<>(area);

        area.selectRange(2, 4);
        
        Scene scene = new Scene(vsPane, 400, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

The NPE is:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
	at org.fxmisc.richtext.model.SuperCodec$1.encodeSuper(SuperCodec.java:33)
	at org.fxmisc.richtext.model.SuperCodec$1.encodeSuper(SuperCodec.java:1)
	at org.fxmisc.richtext.model.SuperCodec.encode(SuperCodec.java:15)
	at org.fxmisc.richtext.model.StyledText$2.encode(StyledText.java:94)
	at org.fxmisc.richtext.model.StyledText$2.encode(StyledText.java:1)
	at org.fxmisc.richtext.model.SuperCodec$1.encodeSuper(SuperCodec.java:35)
	at org.fxmisc.richtext.model.SuperCodec$1.encodeSuper(SuperCodec.java:1)
	at org.fxmisc.richtext.model.SuperCodec.encode(SuperCodec.java:15)
	at org.fxmisc.richtext.model.ReadOnlyStyledDocument$3.encode(ReadOnlyStyledDocument.java:139)
	at org.fxmisc.richtext.model.ReadOnlyStyledDocument$3.encode(ReadOnlyStyledDocument.java:1)
	at org.fxmisc.richtext.model.SuperCodec$1.encodeSuper(SuperCodec.java:35)
	at org.fxmisc.richtext.model.SuperCodec$1.encodeSuper(SuperCodec.java:1)
	at org.fxmisc.richtext.model.SuperCodec.encode(SuperCodec.java:15)
	at org.fxmisc.richtext.model.ReadOnlyStyledDocument$2.encode(ReadOnlyStyledDocument.java:116)
	at org.fxmisc.richtext.model.ReadOnlyStyledDocument$2.encode(ReadOnlyStyledDocument.java:1)
	at org.fxmisc.richtext.ClipboardActions.lambda$0(ClipboardActions.java:67)
	at java.util.Optional.ifPresent(Optional.java:159)
	at org.fxmisc.richtext.ClipboardActions.copy(ClipboardActions.java:60)
	at org.fxmisc.richtext.GenericStyledAreaBehavior.lambda$28(GenericStyledAreaBehavior.java:149)
	at org.fxmisc.wellbehaved.event.template.InputMapTemplate.lambda$consume$32(InputMapTemplate.java:107)
	at org.fxmisc.wellbehaved.event.template.PatternActionTemplate.lambda$null$44(InputMapTemplate.java:242)
	at java.util.Optional.map(Optional.java:215)
	at org.fxmisc.wellbehaved.event.template.PatternActionTemplate.lambda$getInputHandlerTemplateMap$45(InputMapTemplate.java:242)
	at org.fxmisc.wellbehaved.event.template.InputHandlerTemplateMap.lambda$sequence$39(InputHandlerTemplateMap.java:25)
	at org.fxmisc.wellbehaved.event.template.InputMapTemplate$1.lambda$null$30(InputMapTemplate.java:92)
	at org.fxmisc.wellbehaved.event.template.InputHandlerTemplateMap.lambda$sequence$39(InputHandlerTemplateMap.java:24)
	at org.fxmisc.wellbehaved.event.template.InputMapTemplate$HandlerTemplateConsumer$1.lambda$accept$29(InputMapTemplate.java:36)
	at org.fxmisc.wellbehaved.event.InputHandler.handle(InputHandler.java:15)
	at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
	at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
	at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
	at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
	at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
	at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
	at javafx.event.Event.fireEvent(Event.java:198)
	at javafx.scene.Scene$KeyHandler.process(Scene.java:3964)
	at javafx.scene.Scene$KeyHandler.access$1800(Scene.java:3910)
	at javafx.scene.Scene.impl_processKeyEvent(Scene.java:2040)
	at javafx.scene.Scene$ScenePeerListener.keyEvent(Scene.java:2501)
	at com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:217)
	at com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:149)
	at java.security.AccessController.doPrivileged(Native Method)
	at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleKeyEvent$353(GlassViewEventHandler.java:248)
	at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
	at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleKeyEvent(GlassViewEventHandler.java:247)
	at com.sun.glass.ui.View.handleKeyEvent(View.java:546)
	at com.sun.glass.ui.View.notifyKey(View.java:966)
	at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
	at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
	at java.lang.Thread.run(Thread.java:748)
@JordanMartinez
Copy link
Contributor

Mm... I implemented that class in #553 as a way to make it easier for others to implement custom objects in the area. However, I later realized in #550 (which was created before #553 but merged after it) that such an approach wouldn't work because sometimes a segment is reduced to an empty one, but isn't the singleton used in that class. (This is also partly why I proposed #567: once a style is separated from a segment, one can use an empty segment as a singleton because its style isn't a part of that segment.). That's not difficult to fix, but I won't be able to get to it until tomorrow.

@JFormDesigner
Copy link
Contributor Author

Have another probably related NPE caused by commit a2aa881 (same commit as mentioned in my first post) when doing drag-and-drop text. It works when I checkout the previous commit. Currently, I can reproduce it only in Markdown Writer FX but not in JavaKeywords demo...

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
	at java.util.AbstractCollection.addAll(AbstractCollection.java:343)
	at javafx.collections.ModifiableObservableListBase.addAll(ModifiableObservableListBase.java:99)
	at org.fxmisc.richtext.StyleClassedTextArea.lambda$1(StyleClassedTextArea.java:22)
	at org.fxmisc.richtext.StyledTextArea.createStyledTextNode(StyledTextArea.java:114)
	at org.fxmisc.richtext.StyledTextArea.lambda$0(StyledTextArea.java:74)
	at org.fxmisc.richtext.ParagraphText.<init>(ParagraphText.java:116)
	at org.fxmisc.richtext.ParagraphBox.<init>(ParagraphBox.java:77)
	at org.fxmisc.richtext.GenericStyledArea.createCell(GenericStyledArea.java:1184)
	at org.fxmisc.richtext.GenericStyledArea.lambda$10(GenericStyledArea.java:645)
	at org.fxmisc.flowless.CellPool.getCell(CellPool.java:20)
	at org.fxmisc.flowless.CellListManager.cellForItem(CellListManager.java:75)
	at org.reactfx.collection.MappedList.get(MappedList.java:27)
	at org.reactfx.collection.MemoizationListImpl.get(MemoizationList.java:99)
	at org.fxmisc.flowless.CellListManager.getCell(CellListManager.java:64)
	at org.fxmisc.flowless.CellPositioner.getSizedCell(CellPositioner.java:129)
	at org.fxmisc.flowless.CellPositioner.placeStartAt(CellPositioner.java:95)
	at org.fxmisc.flowless.Navigator.fillForwardFrom0(Navigator.java:235)
	at org.fxmisc.flowless.Navigator.fillForwardFrom0(Navigator.java:217)
	at org.fxmisc.flowless.Navigator.fillTowardsSkyFrom0(Navigator.java:323)
	at org.fxmisc.flowless.Navigator.fillViewportFrom(Navigator.java:284)
	at org.fxmisc.flowless.Navigator.visit(Navigator.java:112)
	at org.fxmisc.flowless.StartOffStart.accept(TargetPosition.java:49)
	at org.fxmisc.flowless.Navigator.layoutChildren(Navigator.java:67)
	at javafx.scene.Parent.layout(Parent.java:1087)
	at org.fxmisc.flowless.VirtualFlow.layoutChildren(VirtualFlow.java:165)
	at javafx.scene.Parent.layout(Parent.java:1087)
	at javafx.scene.Parent.layout(Parent.java:1093)
	at javafx.scene.Parent.layout(Parent.java:1093)
	at javafx.scene.Parent.layout(Parent.java:1093)
	at javafx.scene.Parent.layout(Parent.java:1093)
	at javafx.scene.Parent.layout(Parent.java:1093)
	at javafx.scene.Parent.layout(Parent.java:1093)
	at javafx.scene.Parent.layout(Parent.java:1093)
	at javafx.scene.Parent.layout(Parent.java:1093)
	at javafx.scene.Scene.doLayoutPass(Scene.java:552)
	at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2397)
	at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Toolkit.java:355)
	at java.security.AccessController.doPrivileged(Native Method)
	at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:354)
	at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:381)
	at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:510)
	at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:490)
	at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$404(QuantumToolkit.java:319)
	at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
	at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
	at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
	at java.lang.Thread.run(Thread.java:748)

@JFormDesigner
Copy link
Contributor Author

After some debugging, the problem seems to be that StyledText.style is (or becomes) null, but it should be Collections$EmptyList...

@JFormDesigner
Copy link
Contributor Author

Ok, found the problem by comparing the old implementation with the new one. It is in both SegmentOpsBase.subSequence() methods:

return seg == empty || start == end
       ? empty
       : realSubSequence(seg, start, end);

The || start == end (which was not there in the old implementation) causes the problem. If this is true, then empty is returned and empty.style is null (which causes the NPEs). But the style of the resulting sequence should be Collections$EmptyList from the original segment.

So it is important to invoke realSubSequence() even if start == end.

I'll file a PR...

JFormDesigner pushed a commit to JFormDesigner/RichTextFX that referenced this issue Sep 7, 2017
JordanMartinez added a commit that referenced this issue Sep 7, 2017
@JordanMartinez
Copy link
Contributor

Closed by #578

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants