RTextScrollPane appears incompatible with JXLayer/JLayer

Questions on using RSyntaxTextArea should go here.

Moderator: robert

RTextScrollPane appears incompatible with JXLayer/JLayer

Postby preditcon » Fri Oct 18, 2013 11:08 am

I just tried to make a text editor feature which blurs the text of an RSytaxTextArea wrapped in an RTextScrollPane, but have failed to do so on the first try. The latter seems to insist that components passed to it's setViewportView() method be subclasses of RTextArea. Why is that?

A JXLayer (and it's spawn JLayer, part of JDK7) are meant to wrap components in order to decorate them (paint over them, capture events, etc.). It's mighty useful. I wanted to decorate RSTA but that means I now have to pass the decorator to the scroll pane instead of RSTA itself. Which cannot be done as it seems, unfortunately.

Have you ever given any thought to supporting situations like these?

http://docs.oracle.com/javase/7/docs/api/javax/swing/JLayer.html
preditcon
 
Posts: 27
Joined: Wed Jan 25, 2012 10:09 am

Re: RTextScrollPane appears incompatible with JXLayer/JLayer

Postby robert » Fri Oct 18, 2013 1:07 pm

RTextScrollPane needs an RSyntaxTextArea in it because it needs information from the text area to render the Gutter correctly (line numbers and code folding, etc.).

What is the best way to allow for support of JXLayer/JLayer? RSTA only requires Java 5, so we cannot reference the Java 7 JLayer class directly. If I added an interface for your layer implementations to also implement (yuck, I know), that gave access to the contained RSTA instance, would that work? Something like this:

java code:

public interface RTextScrollPaneView {

public RSyntaxTextArea getTextArea();

}


Any other ideas?
User avatar
robert
 
Posts: 802
Joined: Sat May 10, 2008 5:16 pm

Re: RTextScrollPane appears incompatible with JXLayer/JLayer

Postby preditcon » Sat Oct 19, 2013 9:28 am

I believe you could simply go down the component hierarchy in order to check for possible wrapping components, without actually caring what they are. This would work for possible other cases that may appear in the future. All you'd need to do is the opposite of what SwingUtilities.getAncestorOfClass(Class<?>, Component) does (http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingUtilities.html#getAncestorOfClass%28java.lang.Class,%20java.awt.Component%29). That is, search for a suitable descendant. It would also work for multiple wrappings done this way.

An interface would do the same thing, practically speaking. More hassle for client code though.

java code:

/**
* Finds first descendant or self of a component that may be cast
* to the class in argument.
*
* @param c class to match
* @param comp ancestor
* @return
*/
public static Component getFirstDescendantOrSelfOfClass(
Class<?> c, Component comp) {
// breadth first search
Deque<Component> queue = new ArrayDeque<Component>();
queue.add(comp);
while (!queue.isEmpty()) {
Component current = queue.poll();
if (c.isInstance(current)) {
return current;
}
if (current instanceof Container) {
Container container = (Container) current;
queue.addAll(Arrays.asList(container.getComponents()));
}
}
return null;
}

This works for a JScrollPane, JXLayer and a JTextArea.
preditcon
 
Posts: 27
Joined: Wed Jan 25, 2012 10:09 am

Re: RTextScrollPane appears incompatible with JXLayer/JLayer

Postby preditcon » Tue Oct 22, 2013 12:36 pm

I took the liberty of cloning your Git repo for rsyntaxtextarea and modifying to code to my needs. I changed the RTextScrollPane.java as denoted by the following diff:

java code:

@@ -9,11 +9,14 @@
*/
package org.fife.ui.rtextarea;

import java.awt.Color;
import java.awt.Component;
+import java.awt.Container;
import java.awt.Font;
+import java.util.Arrays;
+import java.util.Stack;
import javax.swing.JScrollPane;


/**
* An extension of <code>javax.swing.JScrollPane</code> that will only take
@@ -221,17 +224,50 @@ public class RTextScrollPane extends JScrollPane {
* @param view The new view.
* @see #getTextArea()
*/

@Override
public void setViewportView(Component view) {
+ RTextArea rstaCandidate = null;
if (!(view instanceof RTextArea)) {
- throw new IllegalArgumentException("view must be an RTextArea");
- }
+ rstaCandidate =
+ (RTextArea) getFirstDescendantOrSelfOfClass(RTextArea.class, view);
+ if (rstaCandidate == null) {
+ throw new IllegalArgumentException("view must be or contain an RTextArea");
+ }
+ } else {
+ rstaCandidate = (RTextArea)view;
+ }
super.setViewportView(view);
- textArea = (RTextArea)view;
+ textArea = rstaCandidate;
if (gutter!=null) {
gutter.setTextArea(textArea);
}
}

-
+ /**
+ * Finds first descendant or self of a component that may be cast to the
+ * class in argument.
+ *
+ * This should be moved to a proper utility class.
+ *
+ * @param c class to match
+ * @param comp ancestor
+ * @return
+ */
+ private Component getFirstDescendantOrSelfOfClass(
+ Class<?> c, Component comp) {
+ // breadth first search
+ Stack<Component> queue = new Stack<Component>();
+ queue.add(comp);
+ while (!queue.isEmpty()) {
+ Component current = queue.pop();
+ if (c.isInstance(current)) {
+ return current;
+ }
+ if (current instanceof Container) {
+ Container container = (Container) current;
+ queue.addAll(Arrays.asList(container.getComponents()));
+ }
+ }
+ return null;
+ }
}
\ No newline at end of file


Guess what? It works like a charm. :D

P.S: I was too hasty. Mouse wheel doesn't scroll properly, but it's the same for a regular JScrollPane and a JTextArea. Must have missed some JXLayer property.

P.P.S: Yes. I needed to configure JXLayer, so it doesn't mask any events. Apparently it does so by default.
preditcon
 
Posts: 27
Joined: Wed Jan 25, 2012 10:09 am

Re: RTextScrollPane appears incompatible with JXLayer/JLayer

Postby robert » Tue Oct 22, 2013 1:21 pm

So just to be clear - this does work for you, is that correct?

If so I'll play with it and JDK7's JLayer, and commit it if things look OK.

Thanks for contributing!
User avatar
robert
 
Posts: 802
Joined: Sat May 10, 2008 5:16 pm

Re: RTextScrollPane appears incompatible with JXLayer/JLayer

Postby preditcon » Tue Oct 22, 2013 1:47 pm

Yes, it does work.

If you have trouble with some events getting masked, check this. I had to call a corresponding method of JXLayer with a value of "0".
preditcon
 
Posts: 27
Joined: Wed Jan 25, 2012 10:09 am

Re: RTextScrollPane appears incompatible with JXLayer/JLayer

Postby robert » Thu Oct 31, 2013 3:50 am

This was just added to Git in fix #28.

And yes, JLayer is pretty cool! I'm trying to make up an excuse to use it in projects now.
User avatar
robert
 
Posts: 802
Joined: Sat May 10, 2008 5:16 pm


Return to Help

Who is online

Users browsing this forum: No registered users and 2 guests

cron