I have an editor application with a main editor area in SmartGwt. I handle some native events - keypresses as keyboard shortcuts. I want to disable executing these when there's one or more Window shown on the screen. How to detect if there are any Window descendants shown? /I don't mean browser windows, but SmartGwt Window descendants/
It would be perfectly enough to detect modal windows.
Is there a SmartGwt API way of doing this, or I have to create my own system for registering my windows and query their visible state?
FYI - there seems to be no other way of doing this than creating a common ancestor for my windows and keep track of the visibility changes.
Then call getVisibleCount() when needed.
public class WindowBase extends Window {
private static ArrayList<Window> visibleWindows = new ArrayList<Window>();
VisibilityChangedHandler handlervc = new VisibilityChangedHandler() {
public void onVisibilityChanged(com.smartgwt.client.widgets.events.VisibilityChangedEvent event) {
if ( event.getIsVisible() ) {
if ( !visibleWindows.contains( event.getSource() ) )
visibleWindows.add( (Window)event.getSource() );
} else
visibleWindows.remove( event.getSource() );
}
};
#Override
public void show() {
if ( !visibleWindows.contains( this ) )
visibleWindows.add( this );
addVisibilityChangedHandler( handlervc );
super.show();
}
public static int getVisibleCount() {
return visibleWindows.size();
}
}
Related
I have written this Fantom class
using gfx
using fwt
class Test {
Window window := Window {
size = Size( 400, 320 )
SashPane {
Combo {
items = Month.vals
onModify.add( |e| { echo( "items.size is ${e->widget->items->size}" ) } )
},
},
}
Void main() {
window.open
}
}
when I run it, it produces this output:
items.size is 12
items.size is 12
which means that the modify event is being triggered twice. It occurs at the same time the window pops up on the screen, without me having any chance to modify anything on the Combo widget. Why?
This is causing issues in a real class that uses multiple Combo widgets, some of them related and causing a cascade of events that produces unexpected results.
Is there any way this can be prevented, please?
I can confirm that this is an issue.
Looking at the Java source code for the FWT Combo, it's pretty small and doesn't seem to do anything wrong, which leads me to believe that it's a issue with the SWT Combo Widget.
That doesn't help you any, so I had a quick play with the example and found this work around...
...add the onModify event listener after the window has been opened, and the widgets constructed. Do this by using the Window.onOpen() event:
using gfx
using fwt
class Testy {
Void main() {
Window {
size = Size( 400, 320 )
combo := null as Combo
onOpen.add {
combo.onModify.add { echo("Hello Mum!") }
}
SashPane {
combo = Combo { items = Month.vals },
},
}.open
}
}
Now you should only get a Hello Mum! when the combo is actually modified.
SWT Text has a method called setMessage which can be used with SWT.SEARCH to put an initial faded-out message in the text box.
Can something similar be done with SWT Combo? It seems it does not have the setMessage() method, so it seems like some other trick needs to be applied here.
You are right, the Combo does not have regular API to set a message like the text widget does.
You could try to use a PaintListener to draw the message text while the Combo text is empty.
combo.addPaintListener( new PaintListener() {
#Override
public void paintControl( PaintEvent event ) {
if( combo.getText().isEmpty() ) {
int x = ...; // indent some pixels
int y = ...; // center vertically
event.gc.drawText( "enter something", x, y );
}
}
} );
In addition, you would need several listeners that redraw the Combo after its native appearance was updated.
combo.addListener( SWT.Modify, event -> combo.redraw() );
A modify listener is certainly required to show/hide the message but there are probably more listeners necessary to redraw the message when it is invalidated. This answer may give further hints which events are necessary to capture: How to display a hint message in an SWT StyledText
Note, however, that drawing onto controls other than Canvas is unsupported and may not work on all platforms.
A simpler alternative to the paint listener that worked for my purposes involves programatically setting the text and text color using a FocusListener. Here is an example:
final String placeholder = "Placeholder";
combo.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_GRAY));
combo.setText(placeholder);
combo.addFocusListener(new FocusListener() {
#Override
public void focusLost(FocusEvent e) {
String text = combo.getText();
if(text.isEmpty()) {
combo.setText(placeholder);
combo.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_GRAY));
}
}
#Override
public void focusGained(FocusEvent e) {
String text = combo.getText();
if(text.equals(placeholder)) {
combo.setText("");
combo.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
}
}
});
I am using the 3.x-4.x compatibility layer and I'm attempting to open and use editors. Our existing code looks like this in the class that implements IPartListener2:
public void partOpened(IWorkbenchPartReference partRef) {
if (partRef instanceof IEditorReference) {
//force editor area visible
partRef.getPage().setEditorAreaVisible(true);
// if the editors are currently minimimized and we try to maximize them, then we'll cause a bug.
if (partRef.getPage().getPartState(partRef) == IWorkbenchPage.STATE_MINIMIZED) {
return; // so exit here
}
//check preferences
final boolean maximized = EnterpriseManager.isMaximized();
if (maximized) {
partRef.getPage().setPartState(partRef, 1);
}
}
}
The problem is now whenever an editor is opened in Mars, it doesn't open maximized as a tab on the page layout as before, but in a much smaller window size.
Also, selecting the Restore Icon on an open editor's rule bar causes erratic positioning of the editor with one section of the editor in one part of the layout and other sections displaying in other areas of the page layout.
How am I to implement correct, predictable usage of editors with the compatibility layer?
Just guessing but it may be that Eclipse 4 does not like the setEditorAreaActive and setPartState methods being called while partOpened is being processed. You could try using Display.asyncExec to delay calling these until after the partOpened code has completed.
Something like:
public void partOpened(final IWorkbenchPartReference partRef) {
Display.getDefault().asyncExec(new Runnable()
{
#Override
public void run()
{
if (partRef instanceof IEditorReference) {
//force editor area visible
partRef.getPage().setEditorAreaVisible(true);
// if the editors are currently minimimized and we try to maximize them, then we'll cause a bug.
if (partRef.getPage().getPartState(partRef) == IWorkbenchPage.STATE_MINIMIZED) {
return; // so exit here
}
//check preferences
final boolean maximized = EnterpriseManager.isMaximized();
if (maximized) {
partRef.getPage().setPartState(partRef, IWorkbenchPage.STATE_MAXIMIZED);
}
}
}
});
}
I want to disable the button maximize/minimize, below I post image to explain
this is my code :
public class ProjectWizardPageOne extends WizardPage {
private String platform;
public ProjectWizardPageOne(String title) {
super(title);
this.setTitle(title);
this.setMessage("Configure Project Name and Location");
}
#Override
public void createControl(Composite parent) {
Composite container = new Composite(parent,SWT.NONE);
setPageComplete(false);
setControl(container);
Canvas leftPanel = new Canvas(container, SWT.NONE);
leftPanel.setBackgroundImage(new Image(leftPanel.getDisplay(), this
.getClass().getClassLoader()
.getResourceAsStream("/icons/mypicture.png")));
leftPanel.setBounds(0, 0, 183, 282);
Composite rightContainer = new Composite(container, SWT.NONE);
rightContainer.setBackground(new Color(null, 255, 255, 255));
rightContainer.setBounds(181, 0, 399, 282);
}
public String getPlatform() {
return platform;
}
public void setPlatform(String platform) {
this.platform = platform;
}
}
I tried to get the Composite's Shell like this "container.getShell();"
but I don't understand How I can set these parameters "SWT.SHELL_TRIM | SWT.TOOL"!
Thanks
Controlling the Window/Shell is not the responsibility of a WizardPage, it can not do that. It's the responsibility of the WizardDialog or the code that creates it. In fact, there is no guarantee that a Wizard and its WizardPages will even be contained in a WizardDialog; anything can implement the IWizardContainer interface to present wizards in a different way.
Is it a File -> New wizard or a custom wizard that is programatically launched. If it is custom, you would have to create WizardDialog and then pass Wizard instance to it. When creating WizardDialog, you would also create Shell, for which you can send the argument without SWT.RESIZE. For File -> New, since the dialog is not created by you, I dont think you can control resize option there. The resize can only be passed in the constructor of Shell.
In case of dialogs, I have observed that I need to explicitly specify that I need min, max buttons at upper-right corner. For that I need to call the below method in a constructor:
setShellStyle(getShellStyle() | SWT.MAX | SWT.MIN | SWT.RESIZE);
Since Wizard is also a dialog, I can call the above method to reset the shellStyle not to include max, min, and other buttons (see above code). The wizard by default might be adding these buttons. But I think you can override this by recalling at the end of wizard creation. Hope this helps.
public class InstallerWizard extends Wizard{
...
main()
{
WizardDialog dialog = new DisableMax(shell, new InstallerWizard());
dialog.open();
}
}
public class DisableMax extends WizardDialog {
public DisableMax(Shell parentShell, IWizard newWizard) {
super(parentShell, newWizard);
setShellStyle(SWT.CLOSE | SWT.MIN | SWT.RESIZE | getDefaultOrientation());
}
}
If i have a GWT composite widget with three text boxes like for SSN, and i need to fire change event only when focus is lost from the widget as a whole, not from individual text boxes how to go about doing that?
If you want just the event when your whole widget loses focus (not the text boxes), then make the top level of your widget be a FocusPanel, and expose the events that it gives you.
You need to implement the Observer Pattern on your composite, and trigger a new notification everytime:
the focus is lost on a specific text box AND
the focus was not transferred to any of the other text boxes.
Couldn't you use a timer? On lost focus from a text box, start a 5ms (or something small) timer that when it hits, will check focus on all 3 TextBox instances. If none have focus, then you manually notify your observers. If one has focus, do nothing.
Put this in your Composite class:
private Map<Widget, Boolean> m_hasFocus = new HashMap<Widget, Boolean>();
And then add this to each one of your TextBox instances:
new FocusListener() {
public void onFocus(Widget sender) {
m_hasFocus.put(sender, Boolean.TRUE);
}
public void onLostFocus(Widget sender) {
m_hasFocus.put(sender, Boolean.FALSE);
new Timer() {
public void run() {
for (Boolean bool : m_hasFocus.values()) {
if (bool) { return; }
}
notifyObservers();
}
};
}
};