TW: Bad Code
I have a custom Form ConfirmForm that shows up everytime before a process gets executed, so a User can review their input and give their final okay.
I have designed this Form to be easily adaptable for my needs, which is why I'd like to keep it.
The problem I've encountered though is, that with my current code, the ActionListeners get stacked everytime a process is executed.
menu.getMenuOpenIPs().addActionListener(e -> {
simpleChoosingForm.getPasswordsCheckBox().setEnabled(false);
simpleChoosingForm.getPasswordsCheckBox().setSelected(false);
simpleChoosingForm.getPasswords().setEnabled(false);
simpleChoosingFrame.setVisible(true);
});
simpleChoosingForm.getStartSetupButton().addActionListener(e1 -> {
setup.prepareSimpleSetup(simpleChoosingForm.getIpAddresses().getText(), simpleChoosingForm.getPasswords().getText());
if(setup.polishSimpleInput(false, false, false, SimpleSetupWorker.OPEN_IN_BROWSER)) {
simpleChoosingFrame.setEnabled(false);
confirmFrame.setMinimumSize(new Dimension(450, 250));
confirmFrame.setVisible(true);
} else {
simpleChoosingFrame.setEnabled(false);
errorFrame.pack();
errorFrame.setVisible(true);
errorForm.getOKButton().addActionListener(e2 -> {
simpleChoosingFrame.setEnabled(true);
simpleChoosingFrame.requestFocus();
});
}
confirmForm.getOKButton().addActionListener(e2 -> {
new SimpleSetupWorker(setup, SimpleSetupWorker.OPEN_IN_BROWSER);
//simpleSetupWorker.start(SimpleSetupWorker.OPEN_IN_BROWSER);
simpleChoosingFrame.dispose();
confirmFrame.dispose();
setupFrame.setEnabled(true);
setupFrame.requestFocus();
simpleChoosingFrame.setEnabled(true);
for(ActionListener al : confirmForm.getOKButton().getActionListeners()) {
confirmForm.getOKButton().removeActionListener(al);
}
});
confirmForm.getCancelButton().addActionListener(e2 -> {
confirmFrame.dispose();
simpleChoosingFrame.setEnabled(true);
simpleChoosingFrame.requestFocus();
for(ActionListener al : confirmForm.getOKButton().getActionListeners()) {
confirmForm.getOKButton().removeActionListener(al);
}
});
});
Here is an example of the way I've been doing things so far. The structure is the same for almost all tasks I have so far. I've realised the error in my logic way too late since I was only ever testing one feature at a time, so I never noticed what happened until way to late.
Now I need to find a way to fix this entire class.
EDIT: As seen in the example, I tried removing all the ActionListeners from the Button each time it's executed, but this approach did not work
A sincere apology and my deepest condolences for everyone that had to look at this question.
So, the reason why my first approach was not working is, because of course you need to remove ALL relevant ActionListeners
I forgot to remove one of them so the Task that were executed still stacked.
I've done some major restructuring. If anyone should ever have a similar problem, check which ActionListeners you added need to be removed again. You might've overlooked one.
For anyone interested, here is the class now
Related
I am having a weird problem on my Vaadin app. I have a screen with two separate unbuffered grids.
The user is able to edit the data in those two grids and then click a "Save" button to save the changes made.
My problem is that I want to close the editors when the user clicks on "Save".
I tried the following code:
private void closeEditors() {
if (tab1.getEditor().isOpen()) {
tab1.getEditor().closeEditor();
}
if (tab2.getEditor().isOpen()) {
tab2.getEditor().closeEditor();
}
}
I don't understand why this code doesn't work, editors stay opened. I also tried calling the cancel method but in vain.
I am using Vaadin 14.
I am posting this here with not much hope of finding an answer, this problem seems really precise.
But with any luck, maybe someone has experienced a similar issue ?
Maybe there is another glitchier way of forcing my editors to close ?
Any suggestion would be of great help, thanks in advance for anything you could think of !
EDIT: a little more code
This is the grids:
private Grid<Map<String, String>> tab1;
private Grid<Map<String, List<String>>> tab2;
This is the save function
public void saveData() {
saveDataFromTab1();
saveDataFromTab2();
try {
ServicesProxyImpl.getInstance().updateInBD(someObject);
saveButton.setEnabled(false);
cancelButton.setEnabled(false);
closeEditors();
Dialog dialog = VaadinComponentUtils.generateDialog(Constantes.MSG_SAVE_OK);
dialog.open();
} catch (JAXBException e) {
e.printStackTrace();
Dialog dialog = VaadinComponentUtils.generateDialog(Constantes.MSG_SAVE_KO);
dialog.open();
}
}
And this is the save button:
public Button getSaveButton() {
Button saveButton= VaadinComponentUtils.generateButton("Save",
VaadinIcon.CHECK_CIRCLE_O, null, true);
saveButton.setEnabled(false);
saveButton.addClickListener(event -> saveData());
return saveButton;
}
EDIT 2:
I have noticed something, when I click on an element of one of my two grids, I want the editor to open for that specific element and I want to close the editor on the other grid (the one not concerned by the modification). This works ! My grids behave like I want. It seems I am only losing control over my editors after I have actually modified one of the cells and clicked on my save button.
The isOpen function returns false on both grids after I call my closeEditors function, so it seems the grid thinks its editor is closed but it is still opened on my UI.
EDIT 3: I have found a workaround
Well, I have solved my problem by adding a close event listener on both my grids and calling resetGrids when the close event is fired. This function simply removes the grids from the UI, fetches the data to be displayed and then adds the grid one again, both editors being closed. I guess it solves my problem but I would have wanted to understand what was going on...
private void closeEditors() {
tableauHoraires.getEditor().addCloseListener(e -> resetGrids());
tableauRamassagePorteAPorte.getEditor().addCloseListener(e -> resetGrids());
if (tableauRamassagePorteAPorte.getEditor().isOpen()) {
tableauRamassagePorteAPorte.getEditor().closeEditor();
}
if (tableauHoraires.getEditor().isOpen()) {
tableauHoraires.getEditor().closeEditor();
tableauHoraires.getEditor().refresh();
}
}
Make sure that the objects in your grid have proper equals and hashcode methods and that the field(s) being edited do not influence them.
I use the PK from the database.
I am trying to limit the number of rows that a user can add in an ajaxformloop.
Short example:
For example, the loop found in the tapestry 5 documentation here: http://tapestry.apache.org/5.3/apidocs/org/apache/tapestry5/corelib/components/AjaxFormLoop.html
If for example I would only like the user to be able to enter 3 phone numbers, how can that be done?
What I have tried:
1) I tried returning null from the onAddRow event, this causes an exception and the exception report page to display - these events shouldn't return null I don't think.
2) I tried adding my own add row button like this:
<p:addRow>
<t:addrowlink>Add another</t:addrowlink>
</p:addRow>
And then putting a t:if around it, like this:
<t:if test="canAddMorePhones()">
<p:addRow>
<t:addrowlink>Add another</t:addrowlink>
</p:addRow>
</t:if>
In this case, the "add another" reverts to the default "Add row" button and my add row link doesn't show.
3)I tried moving that t:if inside the , this had similar results.
--------------------------
I am sure that this is a fairly common aim, is there any simple way to do it? Perhaps someone can provide an example, and if possible this can help to go in the documentation as i'm sure i'm not going to be the only one trying to do this.
Note: I did also ask on the T5 users mailing list and had one answer but I can't seem to get it working after the response from Lance (Which I am sure is probably correct, but i'm not sure how to use the AjaxResponseRenderer as per my reply last week, this is probably due to my own technical limitations or understanding of some parts of T5).
http://apache-tapestry-mailing-list-archives.1045711.n5.nabble.com/Ajaxformloop-add-row-link-max-size-tt5730840.html
I also tried using ajaxResponseRenderer.addRender as you did in your mailing list code, but it doesn't work because it seems that Tapestry has some problems dealing with updating a component that's busy updating another component. However, AjaxResponseRenderer also supports execution of JavaScript. Taking this approach on the AjaxFormLoop example in the docs, specify the addrowlink as follows:
<p:addrow>
<t:if test="canAddMorePhones()">
<t:addrowlink id="addRowLink" t:id="addRowLink">Add another</t:addrowlink>
</t:if>
</p:addrow>
Then add the following code right before return phone; in onAddRowFromPhones():
ajaxResponseRenderer.addCallback(new JavaScriptCallback() {
public void run(JavaScriptSupport javascriptSupport) {
if (!canAddMorePhones()) {
javascriptSupport.addScript("document.getElementById('addRowLink').style.display = 'none';");
}
}
});
This example was tested successfully in Tapestry 5.3.7.
we have the following problem:
In our Eclipse RCP 4 application there are multiple parts and the parts are closable. When the user is closing a part there should be a custom pop-up (depending on some internal part state) which is asking the user if he really wants to close the part or not.
It seems to be not that easy to implement in Eclipse RCP 4 or we have just totally overseen something.
I'll just give you a short brieifing about the things we tried:
Use dirtable with a #persist method in the part. Though the problem is, we don't want this standard eclipse save dialog. So is there a way to override this?
public int promptToSaveOnClose(): This seemed to be promising but not for Eclipse 4 or is there a way to integrate it that way? Compare: http://e-rcp.blogspot.de/2007/09/prevent-that-rcp-editor-is-closed.html
Our last try was to integrate a custom part listener, simple example shown in the following:
partService.addPartListener(new IPartListener() {
public void partVisible(MPart part) {
}
public void partHidden(MPart part) {
partService.showPart(part, PartState.ACTIVATE);
}
public void partDeactivated(MPart part) {
}
public void partBroughtToTop(MPart part) {
}
public void partActivated(MPart part) {
}
});
The problem with this was we are running into a continuous loop. Something similar is posted over here in the last comment: Detect tab close in Eclipse editor
So I could write some more about this problem, but I think that's enough for the moment. If you need some more input just give me a hint.
Thanks for helping.
The save prompt is generated by the ISaveHandler registered in the context of the MWindow containing the MPart. You can write your own ISaveHandler and set it in the window context to replace the default.
You might also want to look at the IWindowCloseHandler also in the window context.
Thanks greg, this has helped and I was able to achieve changing the pop-up when the user closes a part. Here's a short description of what I've done:
Use the MDirtyable for marking the part as dirty whenever it's needed.
Create a custom save handler which implements ISaveHandler (when a part got closed the save method is called). Add the additional logic to this handler (e.g. a custom message dialog)
Register this handler at application start-up (I just chose a method which is called at the start-up):
#Inject
private MWindow window;
...
ISaveHandler saveHandler = new CustomSaveHandler(shell);
window.getContext().set(ISaveHandler.class, saveHandler);
Note that the registration via a model processor was sadly not that easy because the model processor is called too early. (Take a look at: http://www.eclipse.org/forums/index.php/t/369989/)
The IWindowCloseHandler is just needed when the complete window is closed, though this was not an requirement for us :).
In a Java Swing application that uses several own UI's (e.g. for JTabbedPane) sometimes right after startup, the Look and Feel (L&F) of the entire application changes back to the default. It quickly shows everything correct and then after a second or less the entire application changes to the ugly default.
Unfortunately, this is difficult to reproduce. It happens very rarely and so far only under Ubuntu when I start it directly from within Eclipse using java-1.6.0-openjdk-amd64. I have a newer java version installed too, but I use 1.6 to test compatibility.
Since it happens either for all or for no component, it looks like it does not matter how I I derive the UI. It even changes back this little change where no custom UI is used:
JTextField textField = new JTextField();
textField.setBorder(null);
So if it happens, then the border will show up.
Since this is difficult to reproduce, I can not give a code example where it always happens. Actually, the one above is already an example, but it does not happen always. But I hope to find someone who run into a similar issue where the L&F or any changes to it suddenly and unwanted changed back to the default. If so, I would appreciate if you could share your experience and hopefully a solution.
---------------- Edit:
I found two workaraounds:
For the border problem, I simply use textField.setBorder(new EmptyBorder()); instead of setting it to null.
For the reset of the UI, which was indeed caused by unwanted calls to updateUI, I created for my customized swing objects subclasses that override updateUI(), e.g.:
public class JTabbedPaneNoHeads extends JTabbedPane {
public JTabbedPaneNoHeads() {
setUI(new GUITabbedPaneNoHeadsUI());
}
#Override
public GUITabbedPaneNoHeadsUI getUI() {
return (GUITabbedPaneNoHeadsUI) ui;
}
#Override
public void updateUI() {
/* This was to find out who is calling updateUI:
StackTraceElement[] _stackTrace = Thread.currentThread().getStackTrace();
for (StackTraceElement element : _stackTrace ){
System.out.print(element + " -- ");
}
System.out.println();
*/
setUI(new GUITabbedPaneNoHeadsUI());
}
}
Now everything works fine.
btw: the calls to updateUI had the following stack trace (generated by the commented block in the code above):
livedocket.GUI.design.JTabbedPaneNoHeads.updateUI(JTabbedPaneNoHeads.java:22)
javax.swing.SwingUtilities.updateComponentTreeUI0(SwingUtilities.java:1230)
.... many more of these updateComponentTreeUI0 ...
javax.swing.SwingUtilities.updateComponentTreeUI0(SwingUtilities.java:1245)
javax.swing.SwingUtilities.updateComponentTreeUI(SwingUtilities.java:1221)
javax.swing.plaf.metal.MetalLookAndFeel$AATextListener.updateWindowUI(MetalLookAndFeel.java:2329)
javax.swing.plaf.metal.MetalLookAndFeel$AATextListener.updateAllUIs(MetalLookAndFeel.java:2342)
javax.swing.plaf.metal.MetalLookAndFeel$AATextListener.access$200(MetalLookAndFeel.java:2295)
javax.swing.plaf.metal.MetalLookAndFeel$AATextListener$1.run(MetalLookAndFeel.java:2370)
java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:226)
java.awt.EventQueue.dispatchEventImpl(EventQueue.java:673)
java.awt.EventQueue.access$300(EventQueue.java:96)
java.awt.EventQueue$2.run(EventQueue.java:634)
java.awt.EventQueue$2.run(EventQueue.java:632)
java.security.AccessController.doPrivileged(Native Method)
java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:108)
java.awt.EventQueue.dispatchEvent(EventQueue.java:643)
java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:275)
java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:200)
java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:185)
java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:177)
java.awt.EventDispatchThread.run(EventDispatchThread.java:138)
As I mentioned before, these calls happen only very rarely and only on Java 1.6.
I have seen similar symptoms in an application with threading problems - if I were you I would double-check if all of the GUI is constructed on the Event Dispatch Thread.
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.