forgive me for a possible misleading title, but the problem is a bit hard to describe.
I'm currently trying to create a basic texteditor using a JTextPane in Java and I've run into an issue.
As you know in most texteditors you can put your caret/cursor behind a piece of styled text (for example text which is bold) and then you can continue typing in that same style (Eg. append more bold characters).
Luckely this is present by default in the JTextPane, but I want to disable it for a certain style. Mainly the URL-style I coded (basicly this one just sets the HTML.Attribute.HREF attribute in the style to an URL).
So if I would put my caret behind a word (or piece of text) which is an URL, I want to ensure that the next characters which will be added, will not be in the URL-style.
Eg. I think tinymce has this behaviour:
You select text
Click on the Insert URL button
Insert the URL
Place the cursor right after the URL and start typing again in normal style
Is there a way to enforce this behaviour in a JTextPane?
I was thinking about something like this:
Adding a listener for content changes in the document
Check if the added characters were placed right behind a piece of text with the URLstyle
If that was the case => remove the "href" attribute from the style of those characters
The code i use for setting the URL-style to the selected text can be found below. "dot" and "mark" are retrieved from the caret.
SimpleAttributeSet attr = new SimpleAttributeSet(doc.getCharacterElement(dot).getAttributes());
StyleConstants.setUnderline(attr, true);
StyleConstants.setForeground(attr, Color.BLUE);
attr.addAttribute(HTML.Attribute.HREF, url);
doc.setCharacterAttributes((dot < mark) ? dot : mark, length, attr, true);
(Note: To be able to tell the difference between normal "blue underlined" text and an URL, the HREF attribute is used for an URL.)
PS: This is my first question here, so hopefully I gave enough information. ;)
Language: Java, JDK 1.7
Thanks in advance.
Add a CaretListener to detect move and check whether current caret position needs the style reset. If it's detected use
StyledEditorKit's method
public MutableAttributeSet getInputAttributes()
Here just remove the attributes you don't need (URL, blue, underline).
I thought I'd share my solution to the problem (found with the help of StanislavL's answer - thanks again for putting me on the right track).
The following method is called from within a caretlistener, passing the attributes found via the "getInputAttributes"-function and the dot and mark of the caret.
private void blockURLTyping(MutableAttributeSet inputAttr, int dot, int mark)
{
StyledDocument doc = getStyledDocument();
int begin = (dot < mark) ? dot - 1 : mark - 1;
if(begin >= 0)
{
Element dotEl = doc.getCharacterElement(begin);
Element markEl = doc.getCharacterElement((dot < mark) ? mark : dot);
AttributeSet dotAttr = dotEl.getAttributes();
AttributeSet markAttr = markEl.getAttributes();
if(dotAttr.isDefined(HTML.Attribute.HREF)) // Ensure atleast one of them isn't null
{
if(dotAttr.getAttribute(HTML.Attribute.HREF) == markAttr.getAttribute(HTML.Attribute.HREF))
{
inputAttr.addAttribute(HTML.Attribute.HREF, dotAttr.getAttribute(HTML.Attribute.HREF));
inputAttr.addAttribute(StyleConstants.Foreground, Color.BLUE);
inputAttr.addAttribute(StyleConstants.Underline, true);
return;
}
}
}
if(inputAttr.isDefined(HTML.Attribute.HREF)) // In all other cases => remove
{
inputAttr.removeAttribute(HTML.Attribute.HREF);
inputAttr.removeAttribute(StyleConstants.Foreground);
inputAttr.removeAttribute(StyleConstants.Underline);
}
}
Important note; The inputAttributes do not update when the caretposition changes but stays within the same element.
So: when the caret is positioned at the end of the URL, behind the last character => you remove the three attributes you can see in the code above => However when the caret is moved to another position within the URL, the attribute stays removed because the set does not update.
So in practice this means that when you remove attributes from the attributeset, they will stay removed untill the StyledEditorKit updates the inputattributes.
To work around this problem I decided to add the attributes again if the caret is in the middle of an URL, allowing you to insert characters in the middle of the URL - but not append or prepend characters (like I wanted).
The code can probably be optimized a bit more because in most cases dot==mark, but I wanted to share this solution.
PS: The comparison of the HREF-attributes is to deal with the situation where two different URLs are positioned next to eachother in a text. It basicly should check if they are both different instances of a certain object even if the URL itself might be the same.
Code that calls this function:
#Override
protected void fireCaretUpdate(CaretEvent e)
{
super.fireCaretUpdate(e);
MutableAttributeSet attr = getStyledEditorKit().getInputAttributes();
int dot = e.getDot();
int mark = e.getMark();
blockURLTyping(attr, dot, mark);
...
}
Related
Im pretty pretty new to Dynamic-Jasper, but due to work i had to add a new feature to our already implemented solution.
My Problem
The Goal is to add a Column to a report that consists only out of a background-color based on some Information. I managed to do that, but while testing I stumbled upon a Problem. While all my Columns in the html and pdf view had the right color, the Excel one only colored the fields in the last Color.
While debugging i noticed, that the same colored Fields had the same templateId, but while all Views run through mostly the same Code the Excel one showed different behavior and had the same ID in all fields.
My Code where I manipulate the template
for(JRPrintElement elemt : jasperPrint.getPages().get(0).getElements()) {
if(elemt instanceof JRTemplatePrintText) {
JRTemplatePrintText text = (JRTemplatePrintText) elemt;
(...)
if (text.getFullText().startsWith("COLOR_IDENTIFIER")) {
String marker = text.getFullText().substring(text.getFullText().indexOf('#') + 1);
text.setText("ID = " + ((JRTemplatePrintText) elemt).getTemplate().getId());
int rgb = TypeConverter.string2int(Integer.parseInt(marker, 16) + "", 0);
((JRTemplatePrintText) elemt).getTemplate().setBackcolor(new Color(rgb));
}
}
}
The html view
The Excel view
Temporary Conclusion
The same styles uses the same Objects in the background and the JR-Excel export messes something up by assigning the same Object to all the Fields that I manipulated there. If anyone knows of a misstake by me or potential Solutions to change something different to result the same thing please let me know.
Something different I tried earlier, was trying to set the field in an evaluate Method that was called by Jasper. In that method we assign the textvalue of each field. It contained a map with JRFillFields, but unfortunatelly the Map-Implementation denied access to them and just retuned the Value of those. The map was provided by dj and couldn't be switched with a different one.
Edit
We are using JasperReports 6.7.1
I found a Solution, where I replaced each template with a new one that was supposed to look exactly alike. That way every Field has its own ID guaranteed and its not up to chance, how JasperReports handles its Data internaly.
JRTemplateElement custom =
new JRTemplateText(((JRTemplatePrintText) elemt).getTemplate().getOrigin(),
((JRTemplatePrintText) elemt).getTemplate().getDefaultStyleProvider());
custom.setBackcolor(new Color(rgb));
custom.setStyle(((JRTemplatePrintText) elemt).getTemplate().getStyle());
((JRTemplatePrintText) elemt).setTemplate(custom);
Okay, this is very strange.
All I am having is a Hyperlink in my menu:
Hyperlink eventCalendar= new Hyperlink("Eventkalender", "eventCalendar=" + store.getId());
and I am listening to the ValueChangeEvent in the MainViewPresenter. Please notice that I am not doing anything. Right before the creation of the listener I am setting a SimplePanel to be the display for the ActivityManager:
App.activityManager.setDisplay(this.mainView.getMainContentContainer());
History.addValueChangeHandler(new ValueChangeHandler<String>() {
#Override
public void onValueChange(ValueChangeEvent<String> event) {
String historyToken = event.getValue();
GWT.log("onValueChange() historyToken " + historyToken);
}
});
But if I click the link what happens is this:
First, for the blink of an eye I can see the browser URL change to
http://localhost:8080/#eventCalendar=1
but it changes immediately back to
http://localhost:8080/#
which causes my landing page to get loaded inside the SimplePanel which I declared as display (see above).
Does anybody have an idea what could cause this behavior because this does not make sense to me? Why does the URL get changed again? Am I using History or Hyperlink wrong?
Most probably your PlaceHistoryMapper returns null for the eventCalendar=1 token, so it's replaced with the default place you gave to the PlaceHistoryHandler. If you're using GWT.create() based on PlaceTokenizers, with a factory and/or #WithTokenizers, that means either you don't have a PlaceTokenizer for the empty-string prefix (#Prefix("")), or that one tokenizer returns null.
That being said, you probably should rather try to use places directly rather than going through the history. That means using a ClickHandler on some widget and calling PlaceController#goTo with the appropriate place. Ideally, that widget would be an Anchor whose href is computed from the result of getToken from your PlaceHistoryMapper with the given place (how the href actually looks depends on your Historian; if you stick to the default behavior, then just prepend a # to the returned token).
I have an xml which Text looks like this :
<LINE>here is some text, it is going,going, and then return is pressed
and the text is going from the next line</LINE>
now when I do :
XmlPullParcer xpp;
//then all the parcing, try/catch stuff, finding needed tag
String s=xpp.getText();
myTextView.setText(s);
(of course, I cut all the code, but you got the idea)
what I see on the screen is not one solid line with no formatting as I wish, but the same two-line text
So, what I see on the screen is :
here is some text, it is going,going, and then return is pressed
and the text is going from the next line
and I want :
here is some text, it is going,going, and then return is pressed and but text is going in one line
please tell me how can I process my String s so it can be shown in a TextView in one line
It looks like the line in XML itself is having a line feed or carriage return. So try to replace them with empty string via String replace method. You can refer to link below for more details:
http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html#sum
Also make sure the TextView in layout has singleline attribute set to true and layout_width set to match_parent.
So I've been working on a Password Strength Checker and the way it works is that the user enters some random text into a textfield and then instantaneous visual feedback (breakdown of points) is displayed. I've also added a checkbox, which on being selected, should hide the password i.e. replace all the chars with asterisks, while preserving the actual text input by the user. A document listener is being used to keep track of changes inside the textfield. (each char on entry gets analyzed and then scored)
So, my question is, how exactly do I mask the user input with asterisks preserving its original value?
Here's what the GUI looks like:
http://speedcap.net/sharing/screen.php?id=files/51/2f/512f9abb3f92a25add7c593e9d80e9e4.png
How exactly do I mask the user input with asterisks preserving its original value?
Use the JPasswordField which has nice function jPasswordField.getPassword(); to get the password as char[] to work with.
Use jPasswordField1.setEchoChar('*') to mask the password characters with *.
If you wish to see the value you are inserting use jPasswordField1.setEchoChar((char)0); Setting a value of 0 indicates that you wish to see the text as it is typed, similar to the behavior of a standard JTextField.
Tutorial and Reference:
How to use Password Fields
setEchoChar(char)
Use Password Field Instead of using textfield
ok thanks for tutorialnya,
and ex,
action chechbox / double click
private void lihatActionPerformed(java.awt.event.ActionEvent evt) {
if (lihat.isSelected()) {
password.setEchoChar((char)0); //password = JPasswordField
} else {
password.setEchoChar('*');
}
}
I solved it as follows:
if ( jPasswordField.getEchoChar() != '\u0000' ) {
jPasswordField.setEchoChar('\u0000');
} else {
jPasswordField.setEchoChar((Character) UIManager.get("PasswordField.echoChar"));
}
I want to create a special Password Dialog for my eclipse product, which is used with an on screen keyboard.
It would be very nice, if i could use a component like the IPhone Password field. In this field, the added character is shown for a second and after the second it is converted into the '*' character for hiding the complete password.
Did a jar/library exists, this is implemented in AWT or SWT?
Edit:
I could trying to implement it from scratch (SWT), but for these i would have to create a very special and complicated KeyListener for the password Text component. I would have to catch the keyReleased event and set the characters manually into the field.
So far i was not able to find any libraries in the web. Suggestion how this can be implemented are welcome too.
This is not really a full answer, rather than a discussion starter and I don't know of any out-of-the-box widgets which can do that.
My first idea was to inheriting the swt Text widget and overriding setEchoChar et al., but after looking at the code this doesn't really seem feasible, because this method is merely a wrapper around:
OS.SendMessage (handle, OS.EM_SETPASSWORDCHAR, echo, 0);
If anyone would know the OS specific low-level implementation, that might be helpful.
Anyway, on to a different approach. I would avoid the KeyListener and use a ModifyListener on the Text-Widget.
void addModifyListener(ModifyListener listener)
You could then build a wrapper which catches the entered text using this listener, appends it to a locally held string/stringbuffer (or e.g. the Eclipse Preferencestore) and send a modified full text to the Text widget using setText(String s), replacing all characters except the last by an echo character (e.g. *).
myText.setText((s.substring(0, s.length()-1)).replaceAll("[\\s\\S]","*")+s.charAt(s.length()-1));
This is a bit of a kludge, but it should work.
The not so straightforward bit is the 1 second timing, without stalling the whole view...
Depending on what Jules said the following code is some kind of working.
The code is quick and fast and i would like to have a more thread safe solution.
originalString = new StringBuffer();
passwordField.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
synchronized (passwordField) {
String s = passwordField.getText();
String newS = s.replaceAll("[\\s\\S]", "*");
if (newS.equals(s)) {
while (originalString.length() > s.length()) {
originalString = originalString.deleteCharAt(originalString.length() - 1);
}
usernameField.setText(originalString.toString());
return;
}
if (originalString.length() < s.length()) {
originalString.append(s.charAt(s.length() - 1));
}
try {
Thread.sleep(500);
} catch (InterruptedException e1) {
}
passwordField.setText(newS);
}
passwordField.redraw();
passwordField.setSelection(passwordField.getText().length());
}
});
Key Events are cached, so you can add more characters, also when the Thread is waiting.
Another Problem is the Cursor handling. the Cursor always moves to the first position, when you set the Text.
I think when this is working it is very near to the iphone solution.