Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 16254

Summary: setVisible() slams previously set focus.
Product: [Eclipse Project] Platform Reporter: Tod Creasey <Tod_Creasey>
Component: SWTAssignee: Steve Northover <snorthov>
Status: RESOLVED WONTFIX QA Contact:
Severity: major    
Priority: P3    
Version: 2.0   
Target Milestone: ---   
Hardware: PC   
OS: Windows 2000   
Whiteboard:
Bug Depends on:    
Bug Blocks: 16240    

Description Tod Creasey CLA 2002-05-17 10:41:58 EDT
If you have a shell where you want to make one control no longer visible and 
make another shell visible the setFocus() method in Composite sets the focus on 
the first widget no matter if focus was previously set 

	for (int i=0; i<children.length; i++) {
		Control child = children [i];
		if (child.setFocus ()) return true;

The problem is that if one the children already has focus set previously it it 
cleared out. A check for all of them to see if anyone hasFocus would be better 
first so that if there already is one with focus focus does not get slammed.
Comment 1 Mike Wilson CLA 2002-05-17 11:07:50 EDT
If the shell was invisible, then none of its children had focus, so unless 
we remember this ourselves (we may, I haven't checked, but typically 
doing things like that gets you in trouble), we can't do what you want.

SN to comment.
Comment 2 Tod Creasey CLA 2002-05-17 12:23:36 EDT
The problem is not that the previous one was invisible - it was that setVisible
(false) was sent to the one we want to get rid of. As a result it will setFocus 
on the first widget of the remaining one whether it is visible or not.
Comment 3 Steve Northover CLA 2002-05-17 13:29:17 EDT
Right, setFocus sets the focus.  It doesn't restore previous saved focus 
widgets or anything like that.  Otherwise, it could never be used to set focus 
to a widget.

I'm pretty tired so I may not quite understand.  Could you code a short 
example?  We (VI and me) have recently played with "setVisible(false) 
reassigning focus if the focus was in the widget tree" and this could be a 
change that is burning you.
Comment 4 Tod Creasey CLA 2002-05-30 12:43:32 EDT
Here is an example

If you press the open with composite focus button the focus will be on the 
first (incorrect) widget.
If you press the open without composite focus button the focus will be on the 
last (correct widget).


import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;

public class WindowFocusTest {

	public static void main(String[] args) {
		final Display display = new Display();
		Shell shell = new Shell(display);
		
		GridLayout layout = new GridLayout();
		shell.setLayout(layout);

		Button labelButton = new Button(shell,SWT.PUSH);
		labelButton.setText("Open Window With Composite Focus");
		labelButton.addSelectionListener(
			new SelectionListener(){
				public void widgetSelected(SelectionEvent e){
					openWindow(display,true);
				};
				
				public void widgetDefaultSelected
(SelectionEvent e){}
		
				});
				
		Button labelButton2 = new Button(shell,SWT.PUSH);
		labelButton2.setText("Open Window Without Composite Focus");
		labelButton2.addSelectionListener(
			new SelectionListener(){
				public void widgetSelected(SelectionEvent e){
					openWindow(display,false);
				};
				
				public void widgetDefaultSelected
(SelectionEvent e){}
		
				});
				
		shell.setBounds(0,0,300,100);
		labelButton.setVisible(true);
		labelButton.pack();
		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
		display.dispose();
	}
	
	/*
	 * Open a window for a editing text
	 */
	
	public static void openWindow(Display display, boolean focusComposite){
		
		Shell shell = new Shell(display);
		Composite composite = new Composite(shell, SWT.BORDER);
		composite.setVisible(false);
		
		GridLayout layout = new GridLayout();
		layout.numColumns = 3;
		composite.setLayout(layout);
		GridData data = new GridData(GridData.FILL_BOTH);
		data.grabExcessHorizontalSpace = true;
		composite.setLayoutData(data);
		
		composite.setVisible(true);
		
		for(int i = 0; i < 6; i ++){
			Text text = new Text(composite,SWT.NULL);
			if (i ==5)
				text.setFocus();
		}		
		
		composite.pack();
			
		
		shell.setBounds(0,0,500,500);
		shell.open();
		if(focusComposite)
			composite.setFocus();	
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}	
	}
	
	
}
Comment 5 Nick Edgar CLA 2002-06-02 22:49:10 EDT
This one's pretty annoying and is easily encountered.
See bug 16780.
Comment 6 Steve Northover CLA 2002-06-03 13:38:54 EDT
This is working as designed.  When you setFocus() to a composite, it finds the 
first child that will take focus and assigns focus there.  It does not see if a 
child already has focus and do nothing.  Am I missing something?

I ran the code on Motif and it has the same behavior.
Comment 7 Tod Creasey CLA 2002-06-03 13:46:34 EDT
The problem is that if you have setFocus on widget before it is made visible 
the focus is slammed into the first widget in the children even if you tried to 
give focus on a different one. Checking if a child had focus before slamming 
the first one who can take it would solve this.

This makes it hard for wizard developers as we do not give them the first page 
and they will have to reset focus.
Comment 8 Steve Northover CLA 2002-06-03 14:04:35 EDT
Not a bug so I won't fix it.