IPhone password field in AWT/SWT? - java

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.

Related

Selenium made a sendKeys for two fields instead of one for some reason

I made a pretty simple selenium test, where I want to open web page, clear field value, start entering text for this field, select first value from the hint drop down.
Web site is aviasales.com (I just found some site with a lot of controls, this is not an advertisement)
I did
DriverFactory.getDriver().findElement(By.id("flights-origin-prepop-whitelabel_en")).clear();
and it was working perfectly, I also checked via console that this is the only one object on a page like:
document.getElementById('flights-origin-prepop-whitelabel_en')
So, in next line I'm sending value:
DriverFactory.getDriver().findElement(By.id("flights-origin-prepop-whitelabel_en")).sendKeys("LAX");
but it send LAX value for both "flights-origin-prepop-whitelabel_en" and "flights-destination-prepop-whitelabel_en" for some reason, then i tried
DriverFactory.getDriver().findElement(By.id("//input[#id='flights-destination-prepop-whitelabel_en'][#placeholder='Destination']")).sendKeys(destinationAirport);
but I got the same result:
What could be a reason and how to fix this?
Thank you!
Yep... there's some weird behavior going on there. The site is copying whatever is entered into the first field into the second for reason I don't understand. I gave up trying to understand it and found a way around it.
Whenever I write code that I know I'm going to reuse, I put them into functions. Here's the script code
driver.navigate().to(url);
setOrigin("LAX");
setDestination("DFW");
...and since you are likely to use these repeatedly, the support functions.
public static void setOrigin(String origin)
{
WebElement e = driver.findElement(By.id("flights-origin-prepop-whitelabel_en"));
e.click();
e.clear();
e.sendKeys(origin);
e.sendKeys(Keys.TAB);
}
public static void setDestination(String dest)
{
WebElement e = driver.findElement(By.id("flights-destination-prepop-whitelabel_en"));
e.click();
e.clear();
e.sendKeys(dest);
e.sendKeys(Keys.TAB);
}
You can see the functions but basically I click in the field, clear the text (because usually there's something already in there), send the text, and then press to move out of the field and choose the default (first choice).
The reason of your issue is the ORIGIN and DESTINATION inputbox binded keyboard event which used to supply an autocomplete list according to your typed characters.
The binded keyborad event breaks the normal sendKeys() functionality. I met similar case in my projects and questions on StackOverFlow.
I tried input 'GSO' into DESTINATION by sendKeys('GSO'), but I get 'GGSSOO' on page after the sendKeys() complete.
To resolve your problem, we can't use sendKeys(), we have to use executeScript() to set the value by javascript in backgroud. But executeScript() won't fire keyborad event so you won't get the autocomplete list. So we need find out a way to fire keyborady event after set value by javascript.
Below code snippet worked on chrome when i tested on aviasales.com:
private void inputAirport(WebElement targetEle, String city) {
String script = "arguments[0].value = arguments[1]";
// set value by javascript in background
((JavascriptExecutor) driver).executeScript(script, targetEle, city + "6");
// wait 1s
Thread.sleep(1000);
// press backspace key to delete the last character to fire keyborad event
targetEle.sendKeys(Keys.BACK_SPACE);
// wait 2s to wait autocomplete list pop-up
Thread.sleep(2000);
// choose the first item of autocomplete list
driver.findElement(By.cssSelector("ul.mewtwo-autocomplete-list > li:nth-child(1)")).click();
}
public void inputOrigin(String city) {
WebElement target = driver.findElement(By.id("flights-origin-prepop-whitelabel_en"));
return inputAirport(target, city);
}
public void inputDestination(String city) {
WebElement target = driver.findElement(By.id("flights-origin-prepopflights-destination-prepop-whitelabel_en"));
return inputAirport(target, city);
}

Sendkeys dropping letters inconsistently

I'm using (new Actions(driver).sendKeys(String).perform() to send input to webdriver. However, I keep getting inconsistent results. Sometimes String is sent in perfectly, sometimes missing one or the other letter, even when the string itself is just a few characters in length.
I even tried sending the string one character at a time (using a for loop) and I'm still getting the same inconsistent behaviour - it's dropping keys less than before, but still not 100% accurate.
What could be possible reason for this, and how to solve this issue?
I'm using Chromedriver, Java/JUnit and the keyboard layout is set to US.
I'm still unclear exactly what was causing this - I see inconsistent failure to send all keys to some extjs components. I'm not sure if this is extjs doing something wierd or selenium being a bit flaky. We weren't doing anything odd in making the string or in calling send keys (except the additional wait to check the element is enabled and displayed) though so it doesn't feel like its something in our code.
My solution was to repeatedly send the keys until they visibly stick. I've wrapped the selenium api for a number of reasons so all calls to WebElements are routed through a class called WrappedElement which has the send keys method:
public void SendKeys(string text)
{
Func<string> errorMessage = () => string.Format("couldn't send keys {0} entered either {1} or {2}", text, Text, Value);
Action actionToTry = () =>
{
_element.Clear();
RawSendKeys(text);
};
Wait.RepeatedlyTry(actionToTry, () => Text == text || Value == text, errorMessage);
}
public void RawSendKeys(string text)
{
_element.SendKeys(text);
}
A simplified version of the wait method looks like this:
public void RepeatedlyTry(Action actionToTry, Func<bool> completed, Func<string> errorMessage)
{
Wait.Until(d =>
{
actionToTry();
return completed();
});
}
Where Until just calls Until on a configured DefaultWait

ContentProposalAdapter prevent new line on select proposal

I use the ContentProposalAdapter to provide content assist to my StyledText fields. I wrote an adapter that implements IControlContentAdapter, IControlContentAdapter2 to support the StyledText. My problem is that, when I press return to insert the proposal the return key is inserted into the StyledText and after that the proposal is inserted.
Why are the UP and DOWN arrows not traversed, but the return key is.
How to prevent the return key from begin inserted into the StyledText field when used to select a proposal.
maybe the question is old, but as I googled and this Post nearly covered my problem, but without a solution, I thought to provide my solution I found now.
My Problem was exactly the same but the newline got inserted after the selected proposal.
Selecting the proposal via double click works just fine so I agreed with you that it´s probably the StyledTextWidget that gets notified about the Enter...
First I tried setPropagateKeys(false) on my ContentProposalAdapter, as the doc says it "indicates whether key events (including auto-activation characters) received by the content proposal popup should also be propagated to the adapted control when the proposal popup is open". But this does not work either.
What actually worked for me is the following:
I added an VerifyKeyListener to the StyledTextWidget and just filtered the Enter Event when the ProposalPopup is open. I thought that maybe wouldn´t work as the newline gets inserted after the proposal but on my program it works fine so it seems the closure of the proposal popup is done after the Enter Key is passed to the StyledTextWidget.
Heres the code:
styledText.addVerifyKeyListener(new VerifyKeyListener() {
#Override
public void verifyKey(VerifyEvent arg0) {
try {
KeyStroke k = KeyStroke.getInstance("Enter");
if(k.getNaturalKey() == arg0.keyCode && contentProposalAdapter.isProposalPopupOpen()) {
arg0.doit = false;
}
} catch (ParseException e) {
e.printStackTrace();
}
} });
I don't know how did you implement IControlContentAdapter, IControlContentAdapter2 in your code. Did you try this? I use that in my custom StyledText implementation. But all of them are SWT.SINGLE Text fields. I hope it may help you.

How to both start a file download and close a (jQuery) dialog in Wicket?

In a Wicket app, I have a modal dialog that contains a simple form and a button. User enters values (report parameters), and then clicks the button which starts the download of a report file (typically a PDF). (All form values are required, and Wicket's validation mechanism is used to make sure user entered them before the download can start.)
Maybe this is better explained with a picture:
I'm using here a jQuery UI Dialog (instead of Wicket's ModalWindow which felt a lot clumsier and uglier from user's perspective).
Everything is pretty much working, except closing the dialog when/after clicking the download button.
Current version (irrelevant bits omitted):
public class ReportDownloadLink extends Link {
public ReportDownloadLink(String id, ReportDto report) {
super(id);
this.report = report;
}
#Override
public void onClick() {
IResourceStream resourceStream = new AbstractResourceStreamWriter() {
#Override
public void write(OutputStream output) {
try {
reportService.generateReport(output, report);
} catch (ReportGenerationException e) {
// ...
}
}
#Override
public String getContentType() {
// ...
}
};
ResourceStreamRequestTarget target =
new ResourceStreamRequestTarget(resourceStream, report.getFileName());
getRequestCycle().setRequestTarget(target);
}
The dialog is a Wicket Panel (which makes use of ReportDownloadLink above), which we put in a certain div, and then when a report is selected in a list, the dialog is opened from an AjaxLink's onClick() quite simply like this:
target.appendJavascript(String.format("showReportExportDialog('%s')", ... ));
Which calls this JS function:
function showReportExportDialog(dialogTitle) {
$("#reportExportPanelContainer").dialog(
{modal:true, draggable:true, width: 320, height: 330, title: dialogTitle}
);
}
Some options:
Make ReportDownloadLink extend something else than Link, perhaps, and/or find an appropriate method to override which would allow me to execute the tiny bit of JavaScript needed to close the jQuery Dialog.
Investigate jQuery + Wicket libraries (such as jqwicket or wiquery) that supposedly make these two work better together.
Latest thing I tried was overriding method getOnClickScript() in ReportDownloadLink which seemed promising (according to the Javadocs, it returns "Any onClick JavaScript that should be used"):
#Override
protected CharSequence getOnClickScript(CharSequence url) {
return "closeDownloadDialog()";
}
Thing is, this causes onClick() not to be called at all, i.e., the download doesn't start.
Could I perhaps override some more "ajaxy" class from Wicket (than Link) to combine these things: first init the download, then call the JS for closing the dialog?
Any recommendations or experiences from similar cases? Note that I want to keep using the jQuery dialog here, even though it makes things like these more complicated. Using a DownloadLink (see related question) is fine too in case that makes things easier.
NB: if you recommend JQWicket or wiQuery, please provide an example of how to do this.
Maybe you can try to bind the close modal code to the button "click" event using only JQuery, in your modal panel page, add something similar to ${"#mySubmit").click(myCloseModalFunction). It should keep Wicket default's behavior and add modal closing in the mix.
The other way is to override the getOnClickScript(...) method but the javascript has to return true in order for the browser to call the continue link evaluation and load the corresponding href. If you return false, the evaluation stops. I would suggest something like
#Override
protected CharSequence getOnClickScript(CharSequence url) {
return "closeDownloadDialog();return true;";
}
Hope it helps...
See https://cwiki.apache.org/WICKET/ajax-update-and-file-download-in-one-blow.html for inspiration.

Hide certain actions from Swing's undo manager

I am trying to write a JTextPane which supports some sort of coloring: as the user is typing the text, I am running some code that colors the text according to a certain algorithm. This works well.
The problem is that the coloring operations is registered with the undo manager (a DefaultDocumentEvent with EventType.CHANGE). So when the user clicks undo the coloring disappears. Only at the second undo request the text itself is rolled back.
(Note that the coloring algorithm is somewhat slow so I cannot color the text as it is being inserted).
If I try to prevent the CHANGE events from reaching the undo manager I get an exception after several undo requests: this is because the document contents are not conforming to what the undoable-edit object expects.
Any ideas?
You could intercept the CHANGE edits and wrap each one in another UndoableEdit whose isSignificant() method returns false, before adding it to the UndoManager. Then each Undo command will undo the most recent INSERT or REMOVE edit, plus every CHANGE edit that occurred since then.
Ultimately, I think you'll find that the styling mechanism provided by JTextPane/StyledDocument/etc. is too limited for this kind of thing. It's slow, it uses too much memory, and it's based on the same Element tree that's used to keep track of the lexical structure of the document. It's okay (I guess) for applications in which the styles are applied by the user, like word processors, but not for a syntax highlighter that has to update the styles constantly as the user types.
There are several examples out there of syntax-highlighting editors based on custom implementations of the Swing JTextComponent, View and Document classes. Some, like JEdit, re-implement practically the whole javax.swing.text package, but I don't think you need to go that far.
How are you trying to prevent the CHANGE events from reaching the undo manager?
Can you not send the UndoManager a lastEdit().die() call immediately after the CHANGE is queued?
I can only assume how you are doing the text colouring. If you are doing it in the StyledDocuments change character attribute method you can get the undo listener and temporarily deregister it from the document for that operation and then once the colour change has finshed then you can reregister the listener.
Should be fine for what you are trying to do there.
hope that helps
I have just been through this problem. Here is my solution:
private class UndoManagerFix extends UndoManager {
private static final long serialVersionUID = 5335352180435980549L;
#Override
public synchronized void undo() throws CannotUndoException {
do {
UndoableEdit edit = editToBeUndone();
if (edit instanceof AbstractDocument.DefaultDocumentEvent) {
AbstractDocument.DefaultDocumentEvent event = (AbstractDocument.DefaultDocumentEvent) edit;
if (event.getType() == EventType.CHANGE) {
super.undo();
continue;
}
}
break;
} while (true);
super.undo();
}
#Override
public synchronized void redo() throws CannotRedoException {
super.redo();
int caretPosition = getCaretPosition();
do {
UndoableEdit edit = editToBeRedone();
if (edit instanceof AbstractDocument.DefaultDocumentEvent) {
AbstractDocument.DefaultDocumentEvent event = (AbstractDocument.DefaultDocumentEvent) edit;
if (event.getType() == EventType.CHANGE) {
super.redo();
continue;
}
}
break;
} while (true);
setCaretPosition(caretPosition);
}
}
It is an inner class in my custom JTextPane, so I can fix the caret position on redo.

Categories