How do I get a GWT menu popup to stay within the browser window? - gwt

My GWT app uses a DockLayoutPanel for primary layout and the page itself does not scroll. I have a PopupPanel with a MenuBar and sometimes when a MenuItem is selected the sub menu bar goes off the bottom of the screen abruptly forcing a new scroll bar into the browser and messing up the layout.
How do I get the menu popup to behave nicely and reposition itself upward when the default positioning would put it out of the browser viewport (the way that PopupPanel.showRelativeTo(uiTarget) positioning works)?
In looking at the MenuBar source, it looks like all the layout is done in private methods, so I can't fix it in subclass, and I don't see any events I can listen to that would allow me to do the repositioning myself.

Take a look at http://groups.google.com/group/Google-Web-Toolkit/browse_thread/thread/6185225fec64c091/4954d91d1461c71f?lnk=gst&q=context+menu#4954d91d1461c71f.
We've been using this strategy quite successfully for a while now.
Update: There is a bit more to be done. Specifically:
Create a reposition() method, which:
Determines the max width of all the menu items
Checks the left edge of the menu + the max width; if greater than the Window's width, use "DOM.setStyleAttribute(elem, "left", left + "px");" to move the menu
Get the height of the menu; if top of the menu + height of the menu > Window's height, use "DOM.setStyleAttribute(elem, "top", top + "px");" to move it up.
In the onAttach() method, use a deferred command to invoke the reposition() method.

You can intercept the popup just before it is shown, but after its size has been created. This way you have the width of the popup and could move it to another position:
#Override
public void onContextMenu(ContextMenuEvent evt) {
int x = evt.getNativeEvent().getClientX();
int y = evt.getNativeEvent().getClientY();
popupMenu.setPopupPositionAndShow(new PositionCallback() {
#Override
public void setPosition(int offsetWidth, int offsetHeight) {
if (x + offsetWidth > Window.getClientWidth()) {
x = Window.getClientWidth() - offsetWidth;
}
//use same technique for height if you want for y, then
setPosition(x, y);
}
});
}
(I know this is an old question, but still comes up if you search for this, so I thought of providing present solution)

Emm...
It is an interesting question...
Looking at the MenuBar source code... especially the method openPopup
private void openPopup(final MenuItem item) {
// Only the last popup to be opened should preview all event
if (parentMenu != null && parentMenu.popup != null) {
parentMenu.popup.setPreviewingAllNativeEvents(false);
}
// Create a new popup for this item, and position it next to
// the item (below if this is a horizontal menu bar, to the
// right if it's a vertical bar).
popup = new DecoratedPopupPanel(true, false, "menuPopup") {
{
setWidget(item.getSubMenu());
setPreviewingAllNativeEvents(true);
item.getSubMenu().onShow();
}
#Override
protected void onPreviewNativeEvent(NativePreviewEvent event) {
// Hook the popup panel's event preview. We use this to keep it from
// auto-hiding when the parent menu is clicked.
if (!event.isCanceled()) {
switch (event.getTypeInt()) {
case Event.ONMOUSEDOWN:
// If the event target is part of the parent menu, suppress the
// event altogether.
EventTarget target = event.getNativeEvent().getEventTarget();
Element parentMenuElement = item.getParentMenu().getElement();
if (parentMenuElement.isOrHasChild(Element.as(target))) {
event.cancel();
return;
}
super.onPreviewNativeEvent(event);
if (event.isCanceled()) {
selectItem(null);
}
return;
}
}
super.onPreviewNativeEvent(event);
}
};
popup.setAnimationType(AnimationType.ONE_WAY_CORNER);
popup.setAnimationEnabled(isAnimationEnabled);
popup.setStyleName(STYLENAME_DEFAULT + "Popup");
String primaryStyleName = getStylePrimaryName();
if (!STYLENAME_DEFAULT.equals(primaryStyleName)) {
popup.addStyleName(primaryStyleName + "Popup");
}
popup.addPopupListener(this);
shownChildMenu = item.getSubMenu();
item.getSubMenu().parentMenu = this;
// Show the popup, ensuring that the menubar's event preview remains on top
// of the popup's.
popup.setPopupPositionAndShow(new PopupPanel.PositionCallback() {
public void setPosition(int offsetWidth, int offsetHeight) {
// depending on the bidi direction position a menu on the left or right
// of its base item
if (LocaleInfo.getCurrentLocale().isRTL()) {
if (vertical) {
popup.setPopupPosition(MenuBar.this.getAbsoluteLeft() - offsetWidth
+ 1, item.getAbsoluteTop());
} else {
popup.setPopupPosition(item.getAbsoluteLeft()
+ item.getOffsetWidth() - offsetWidth,
MenuBar.this.getAbsoluteTop() + MenuBar.this.getOffsetHeight()
- 1);
}
} else {
if (vertical) {
popup.setPopupPosition(MenuBar.this.getAbsoluteLeft()
+ MenuBar.this.getOffsetWidth() - 1, item.getAbsoluteTop());
} else {
popup.setPopupPosition(item.getAbsoluteLeft(),
MenuBar.this.getAbsoluteTop() + MenuBar.this.getOffsetHeight()
- 1);
}
}
}
});
}
It is interesting to point the snippet as
...
popup.setPopupPositionAndShow(new PopupPanel.PositionCallback() {
public void setPosition(int offsetWidth, int offsetHeight) {
// depending on the bidi direction position a menu on the left or right
// of its base item
if (LocaleInfo.getCurrentLocale().isRTL()) {
if (vertical) {
popup.setPopupPosition(MenuBar.this.getAbsoluteLeft() - offsetWidth
+ 1, item.getAbsoluteTop());
} else {
popup.setPopupPosition(item.getAbsoluteLeft()
+ item.getOffsetWidth() - offsetWidth,
MenuBar.this.getAbsoluteTop() + MenuBar.this.getOffsetHeight()
- 1);
}
} else {
if (vertical) {
popup.setPopupPosition(MenuBar.this.getAbsoluteLeft()
+ MenuBar.this.getOffsetWidth() - 1, item.getAbsoluteTop());
} else {
popup.setPopupPosition(item.getAbsoluteLeft(),
MenuBar.this.getAbsoluteTop() + MenuBar.this.getOffsetHeight()
- 1);
}
}
}
});
...
... so I may suppose there is a sense to play around MenuItem object especially its UIObject inherited methods like getAbsoluteLeft() and getAbsoluteTop(), of course ...
I would recommend to extend MenuItem something in this way
//not tested
public class MyMenuItem extends MenuItem
{
private MenuBar aSubMenuBar;//ItemMenu's submenu
//...
#Override
public int getAbsoluteTop() {
// TODO Auto-generated method stub
return super.getAbsoluteTop()+movePopupTo();
}
private int movePopupTo()
{
int moveTo=0;
int bottom=RootPanel.getBodyElement().getAbsoluteBottom();
int rest=bottom -(super.getAbsoluteTop()+this.getaSubMenuBar().getOffsetHeight());
if(rest<0)
{
moveTo=rest;
}
return moveTo;
}
public MenuBar getaSubMenuBar() {
return aSubMenuBar;
}
public void setaSubMenuBar(MenuBar aSubMenuBar) {
this.aSubMenuBar = aSubMenuBar;
}
//...
}
It is not the final solution but a basic conception.
Report if that helped
Good luck

Related

How to get Menu or MenuItem width in JavaFX?

I am extending the default Menu and MenuItem class to add some animated effects to it.
The problem is that I need to know the width and height of the Menu and MenuItem I'm working on. This classes doesn't extend Node or Region so there are no public methods to get their size. The size is composed by the text size inside the MenuItem plus the corresponding default padding, I can calculate how much space the text takes, but I can't get how much padding the MenuItem has neither.
There is a method called impl_styleableGetNode() that returns a Node but it always returns null for me.
Is there anyway to get the size? MenuBar also doesn't seems to expose any helpful method for this.
EDIT:
Here is my class, I'm trying to implement this material design button into the Menu class. Basically I render all the button using the setGraphic() method. It's working perfectly but I'm using the Pane width which doesn't take into account the padding of the Menu so the effect is not complete.
public class MaterialDesignMenu extends Menu {
private Pane stackPane = new Pane();
private Label label = new Label();
private Circle circleRipple;
private Rectangle rippleClip = new Rectangle();
private Duration rippleDuration = Duration.millis(250);
private double lastRippleHeight = 0;
private double lastRippleWidth = 0;
private Color rippleColor = new Color(1, 0, 0, 0.3);
public MaterialDesignMenu() {
init("");
}
public MaterialDesignMenu(String text) {
init(text);
}
public MaterialDesignMenu(String text, Node graphic) {
init(text);
}
private void init(String text){
label.setText(text);
createRippleEffect();
stackPane.getChildren().addAll(circleRipple, label);
setGraphic(stackPane);
}
private void createRippleEffect() {
circleRipple = new Circle(0.1, rippleColor);
circleRipple.setOpacity(0.0);
// Optional box blur on ripple - smoother ripple effect
//circleRipple.setEffect(new BoxBlur(3, 3, 2));
// Fade effect bit longer to show edges on the end of animation
final FadeTransition fadeTransition = new FadeTransition(rippleDuration, circleRipple);
fadeTransition.setInterpolator(Interpolator.EASE_OUT);
fadeTransition.setFromValue(1.0);
fadeTransition.setToValue(0.0);
final Timeline scaleRippleTimeline = new Timeline();
final SequentialTransition parallelTransition = new SequentialTransition();
parallelTransition.getChildren().addAll(
scaleRippleTimeline,
fadeTransition
);
// When ripple transition is finished then reset circleRipple to starting point
parallelTransition.setOnFinished(event -> {
circleRipple.setOpacity(0.0);
circleRipple.setRadius(0.1);
});
stackPane.addEventHandler(MouseEvent.MOUSE_PRESSED, event -> {
parallelTransition.stop();
// Manually fire finish event
parallelTransition.getOnFinished().handle(null);
circleRipple.setCenterX(event.getX());
circleRipple.setCenterY(event.getY());
// Recalculate ripple size if size of button from last time was changed
if (stackPane.getWidth() != lastRippleWidth || stackPane.getHeight() != lastRippleHeight) {
lastRippleWidth = stackPane.getWidth();
lastRippleHeight = stackPane.getHeight();
rippleClip.setWidth(lastRippleWidth);
rippleClip.setHeight(lastRippleHeight);
/*
// try block because of possible null of Background, fills ...
try {
rippleClip.setArcHeight(stackPane.getBackground().getFills().get(0).getRadii().getTopLeftHorizontalRadius());
rippleClip.setArcWidth(stackPane.getBackground().getFills().get(0).getRadii().getTopLeftHorizontalRadius());
circleRipple.setClip(rippleClip);
} catch (Exception e) {
e.printStackTrace();
}*/
circleRipple.setClip(rippleClip);
// Getting 45% of longest button's length, because we want edge of ripple effect always visible
double circleRippleRadius = Math.max(stackPane.getHeight(), stackPane.getWidth()) * 0.45;
final KeyValue keyValue = new KeyValue(circleRipple.radiusProperty(), circleRippleRadius, Interpolator.EASE_OUT);
final KeyFrame keyFrame = new KeyFrame(rippleDuration, keyValue);
scaleRippleTimeline.getKeyFrames().clear();
scaleRippleTimeline.getKeyFrames().add(keyFrame);
}
parallelTransition.playFromStart();
});
}
public void setRippleColor(Color color) {
circleRipple.setFill(color);
}
}
First you have to listen to parentPopupProperty changes of MenuItem. When you get the instance of parent popup than register listener for skinProperty of ContextMenu (parentPopup). When you get the skin then you can get MenuItemContainer which is Node equivalent of MenuItem and you can listen to widthProperty or heightProperty changes of MenuItemContainer.
Note: skinProperty change is fired just before ContextMenu is shown on the screen.
Custom class extending MenuItem class:
public class CstMenuItem extends MenuItem {
public CstMenuItem() {
// Create custom menu item listener.
new CstMenuItemListener(this);
}
/*
* Returns MenuItemContainer node associated with this menu item
* which can contain:
* 1. label node of type Label for displaying menu item text,
* 2. right node of type Label for displaying accelerator text,
* or an arrow if it's a Menu,
* 3. graphic node for displaying menu item icon, and
* 4. left node for displaying either radio button or check box.
*
* This is basically rewritten impl_styleableGetNode() which
* should not be used since it's marked as deprecated.
*/
public ContextMenuContent.MenuItemContainer getAssociatedNode() {
ContextMenu contextMenu = getParentPopup();
ContextMenuSkin skin = (ContextMenuSkin) contextMenu.getSkin();
ContextMenuContent content = (ContextMenuContent) skin.getNode();
// Items container contains MenuItemContainer nodes and Separator nodes.
Parent itemsContainer = content.getItemsContainer();
List<Node> children = itemsContainer.getChildrenUnmodifiable();
for (Node child : children) {
if (child instanceof ContextMenuContent.MenuItemContainer) {
ContextMenuContent.MenuItemContainer menuItemContainer =
(ContextMenuContent.MenuItemContainer) child;
if (menuItemContainer.getItem() == this) {
return menuItemContainer;
}
}
}
return null;
}
}
Custom MenuItem listener class:
public class CstMenuItemListener implements ChangeListener {
private CstMenuItem menuItem;
private ContextMenu parentPopup;
private Region menuItemContainer;
public CstMenuItemListener(CstMenuItem menuItem) {
this.menuItem = menuItem;
menuItem.parentPopupProperty().addListener(this);
}
#Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
if (observable == menuItem.parentPopupProperty()) {
parentPopup = (ContextMenu) newValue;
parentPopup.skinProperty().addListener(this);
} else if (observable == parentPopup.skinProperty()) {
menuItemContainer = menuItem.getAssociatedNode();
menuItemContainer.widthProperty().addListener(this);
menuItemContainer.heightProperty().addListener(this);
} else if (observable == menuItemContainer.widthProperty()) {
System.out.println("width: " + (double) newValue);
} else if (observable == menuItemContainer.heightProperty()) {
System.out.println("height: " + (double) newValue);
}
}
}

In Gwt Drag and Drop, how to drop a widget into a right position of a VerticalPanel that already has many labels on it?

Ok, let say, you got a label, you got a VerticalPanel that has many labels on it. See this code:
// Make the widget draggable.
Label w = new Label("OutSide Label");
w.getElement().setDraggable(Element.DRAGGABLE_TRUE);
// Add a DragStartHandler.
w.addDragStartHandler(new DragStartHandler() {
#Override
public void onDragStart(DragStartEvent event) {
// Required: set data for the event.
event.setData("text", "Hello World");
// Optional: show a copy of the widget under cursor.
event.getDataTransfer().setDragImage(w.getElement(), 10, 10);
}
});
VerticalPanel vp=nw VerticalPanel();
vp.add(new Label("l1");
vp.add(new Label("l2");
vp.add(new Label("l3");
vp.addDomHandler(new DragOverHandler() {
public void onDragOver(DragOverEvent event) {
vp.getElement().getStyle().setBackgroundColor("#ffa");
}
}, com.google.gwt.event.dom.client.DragOverEvent.getType());
vp.addDomHandler(new DropHandler() {
#Override
public void onDrop(com.google.gwt.event.dom.client.DropEvent event) {
// TODO Auto-generated method stub
event.preventDefault();
// Get the data out of the event.
String data = event.getData("text");
//Window.alert(data);
/// WE NEED TO FILL IN THE MISSING CODE HERE
/// WE NEED TO FILL IN THE MISSING CODE HERE
}
}, DropEvent.getType());
how to code so that when user drag the outside label into the area of VerticalPanel, if the outside label was dragged between the existing widgets, it will be inserted into the between of existing labels on VerticalPanel, Ex if the outside label was drag between "l1" & "l2", the vp will show:
l1
OutSide Label
l2
l3
Something like the following should theoretically work, although not tested:
p.addDomHandler(new DropHandler() {
#Override
public void onDrop(DropEvent event) {
// Get the target event.
EventTarget eventTarget = event.getNativeEvent().getEventTarget();
// Safe check for casting to Element.
if (Element.is(eventTarget)) {
Element elementTarget = Element.as(eventTarget);
// Loop through VerticalPanel's children to find our target.
for (int i = 0; i < p.getWidgetCount(); ++i) {
if (p.getWidget(i).getElement().isOrHasChild(elementTarget)) {
// Insert a new Label with the DataTransfer's data,
// and remove the old one.
p.insert(new Label(event.getData("text")), i);
oldLabelContainer.remove(oldLabel);
break;
}
}
}
}
}, DropEvent.getType());
Of course, if you have a lot of labels that loop should be avoided.

How to add a JDialog in to desktop pane or just call from an internal frame

I am working on a project that uses MDI form in java. I have created a frame and then added a desktop pane to it. My project uses lot of internal frames. Also those internal frames require to show custom dialogs that i have created on my own. for it to be clear, i say, one jdialog has a table asking the user to select one row. but the problem is when i call the jdialog from the internal frame (with modality=true), the dialog is show on the top of main frame and not just on the top of internal frame. This makes it impossible to minimize the window when the jdialog is showing.
In my view there are 2 possible solutions (which may not possible!!).. Either the jdialog should be shown inside the dektop pane or i should create an internal frame instead of jdialog and make it appear to be modal to the parent internal frame. i.e, when i want to show the dialog, i may disable the internal frame and set the form unable to focus and then show a new internal frame on the top of this internal frame. I have been searching the forums for weeks.. but i couldn't find an answer. I hope you would have a solution. Thanks in advance, sir.
I also had the same problem, while working on a java project that works quite fine in java 6 but shown the same problem when changed to java7.
I found a solution.
I added a
dialog.setVisible(false) followed by a dialog.setVisible(true).
Then the dialog is responding to keyboard.
I am also working on an MDI app that uses a lof internal frames which show custom dialogs. I make my dialogs non-modal so that the internal frames can be iconified and/or the whole desktoppane can be minimized while the dialogs remain visible.
If you absolutely need modal behavior (i.e., you want to require the user to interact with a dialog before doing anything else) perhaps you can leave the dialog modeless but code in de facto modality.
Also, have you looked at the behavior of
setModalityType(java.awt.Dialog.ModalityType.DOCUMENT_MODAL);
?
Wow!! I got the answer from webbyt... Just avoid using internal frames.. try using the class ModalityInternalFrame (subclass of JinternalFrame).. and everything works fine.. Here is the class
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
/**
* An extended
* <code>JInternalFrame</code> that provides modality in a child/parent
* hierarchy
*
* #author webbyit
*/
public class ModalityInternalFrame extends JInternalFrame {
protected JDesktopPane desktopPane;
protected JComponent parent;
protected ModalityInternalFrame childFrame;
protected JComponent focusOwner;
private boolean wasCloseable;
public ModalityInternalFrame() {
init(); // here to allow netbeans to use class in gui builder
}
public ModalityInternalFrame(JComponent parent) {
this(parent, null);
}
public ModalityInternalFrame(JComponent parent, String title) {
this(parent, title, false);
}
public ModalityInternalFrame(JComponent parent, String title, boolean resizable) {
this(parent, title, resizable, false);
}
public ModalityInternalFrame(JComponent parent, String title, boolean resizable, boolean closeable) {
this(parent, title, resizable, closeable, false);
}
public ModalityInternalFrame(JComponent parent, String title, boolean resizable, boolean closeable,
boolean maximizable) {
this(parent, title, resizable, closeable, maximizable, false);
}
public ModalityInternalFrame(JComponent parent, String title, boolean resizable, boolean closeable,
boolean maximizable,
boolean iconifiable) {
super(title, resizable, closeable, maximizable, iconifiable);
setParentFrame(parent);
//setFocusTraversalKeysEnabled(false);
if (parent != null && parent instanceof ModalityInternalFrame) {
((ModalityInternalFrame) parent).setChildFrame(ModalityInternalFrame.this);
/*
* set focus to the new frame and show the frame Code added by Jasir
*/
try {
((ModalityInternalFrame) parent).setSelected(false);
setSelected(true);
setVisible(true);
} catch (PropertyVetoException ex) {
Logger.getLogger(ModalityInternalFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
// Add glass pane
ModalityInternalGlassPane glassPane = new ModalityInternalGlassPane(this);
setGlassPane(glassPane);
// Add frame listeners
addFrameListener();
// Add frame veto listenr
addFrameVetoListener();
init();
// calculate size and position
}
private void setParentFrame(JComponent parent) {
desktopPane = JOptionPane.getDesktopPaneForComponent(parent);
this.parent = parent == null ? JOptionPane.getDesktopPaneForComponent(parent) : parent; // default to desktop if no parent given
}
public JComponent getParentFrame() {
return parent;
}
public void setChildFrame(ModalityInternalFrame childFrame) {
this.childFrame = childFrame;
}
public ModalityInternalFrame getChildFrame() {
return childFrame;
}
public boolean hasChildFrame() {
return (childFrame != null);
}
protected void addFrameVetoListener() {
addVetoableChangeListener(new VetoableChangeListener() {
public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException {
if (evt.getPropertyName().equals(JInternalFrame.IS_SELECTED_PROPERTY)
&& evt.getNewValue().equals(Boolean.TRUE)) {
if (hasChildFrame()) {
//childFrame.setSelected(true);
if (childFrame.isIcon()) {
childFrame.setIcon(false);
}
throw new PropertyVetoException("no!", evt);
}
}
}
});
}
/**
* Method to control the display of the glass pane, dependant on the frame
* being active or not
*/
protected synchronized void addFrameListener() {
addInternalFrameListener(new InternalFrameAdapter() {
#Override
public void internalFrameActivated(InternalFrameEvent e) {
if (hasChildFrame() == true) {
getGlassPane().setVisible(true);
grabFocus();
} else {
getGlassPane().setVisible(false);
}
}
#Override
public void internalFrameOpened(InternalFrameEvent e) {
getGlassPane().setVisible(false);
try {
setSelected(true);
} catch (PropertyVetoException ex) {
Logger.getLogger(ModalityInternalFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void internalFrameClosing(InternalFrameEvent e) {
if (parent != null && parent instanceof ModalityInternalFrame) {
((ModalityInternalFrame) parent).childClosing();
}
}
});
}
/**
* Method to handle child frame closing and make this frame available for
* user input again with no glass pane visible
*/
protected void childClosing() {
setClosable(wasCloseable);
getGlassPane().setVisible(false);
if (focusOwner != null) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
moveToFront();
setSelected(true);
focusOwner.grabFocus();
} catch (PropertyVetoException ex) {
}
}
});
focusOwner.grabFocus();
}
getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
setChildFrame(null);
getDesktopPane().setSelectedFrame(this);
System.out.println(getDesktopPane().getSelectedFrame());
}
/*
* Method to handle child opening and becoming visible.
*/
protected void childOpening() {
// record the present focused component
wasCloseable = isClosable();
setClosable(false);
focusOwner = (JComponent) getMostRecentFocusOwner();
grabFocus();
getGlassPane().setVisible(true);
getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
#Override
public void show() {
if (parent != null && parent instanceof ModalityInternalFrame) {
// Need to inform parent its about to lose its focus due
// to child opening
((ModalityInternalFrame) parent).childOpening();
}
calculateBounds();
super.show();
}
protected void init() {
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 394, Short.MAX_VALUE));
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 274, Short.MAX_VALUE));
pack();
}
public void calculateBounds() {
Dimension frameSize = getPreferredSize();
Dimension parentSize = new Dimension();
Dimension rootSize = new Dimension(); // size of desktop
Point frameCoord = new Point();
if (desktopPane != null) {
rootSize = desktopPane.getSize(); // size of desktop
frameCoord = SwingUtilities.convertPoint(parent, 0, 0, desktopPane);
parentSize = parent.getSize();
}
//setBounds((rootSize.width - frameSize.width) / 2, (rootSize.height - frameSize.height) / 2, frameSize.width, frameSize.height);
// We want dialog centered relative to its parent component
int x = (parentSize.width - frameSize.width) / 2 + frameCoord.x;
int y = (parentSize.height - frameSize.height) / 2 + frameCoord.y;
// If possible, dialog should be fully visible
int ovrx = x + frameSize.width - rootSize.width;
int ovry = y + frameSize.height - rootSize.height;
x = Math.max((ovrx > 0 ? x - ovrx : x), 0);
y = Math.max((ovry > 0 ? y - ovry : y), 0);
setBounds(x, y, frameSize.width, frameSize.height);
}
/**
* Glass pane to overlay. Listens for mouse clicks and sets selected on
* associated modal frame. Also if modal frame has no children make class
* pane invisible
*/
class ModalityInternalGlassPane extends JComponent {
private ModalityInternalFrame modalFrame;
public ModalityInternalGlassPane(ModalityInternalFrame frame) {
modalFrame = frame;
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (modalFrame.isSelected() == false) {
try {
modalFrame.setSelected(true);
if (modalFrame.hasChildFrame() == false) {
setVisible(false);
}
} catch (PropertyVetoException e1) {
//e1.printStackTrace();
}
}
}
});
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(new Color(255, 255, 255, 100));
g.fillRect(0, 0, getWidth(), getHeight());
}
}
}
But there are some problems still with focus and something else..

why doesn't this right-click capture in GWT work in IE?

I'm trying to capture right-clicks on a widget, to popup my own context menu instead of the browser's. There are a couple references on this, but the most popular one here is a little dated, although some of the comments contain more recent code snippets.
I've pieced together bits and I've got it working in Chrome and FF but not IE. In IE it doesn't display the default browser context menu, but it doesn't display my menu. I'm just getting into GWT so I'm assuming I'm not doing something right with the right kinds of handlers or events. I'm also using the gwt-graphics module, that's where the Rectangle class that I'm extending comes from, in case that's relevant.
Here's my code:
public class RectangleRightClickable extends Rectangle {
public RectangleRightClickable(int x, int y, int width, int height) {
super(x, y, width, height);
sinkEvents(Event.ONCONTEXTMENU);
}
public void onBrowserEvent(Event event) {
GWT.log("onBrowserEvent");
event.stopPropagation();
event.preventDefault();
GWT.log("event type : " + DOM.eventGetType(event));
switch(DOM.eventGetType(event)) {
case Event.ONCONTEXTMENU:
if (DOM.eventGetButton(event) == Event.BUTTON_RIGHT) {
GWT.log("Event.BUTTON_RIGHT", null);
showMenu();
}
break;
default:
GWT.log(event.toString());
break;
}
}
protected void showMenu() {
final RectangleRightClickable parent = this;
final PopupMenu popMenu = new PopupMenu();
popMenu.addMenuItem(new Label("Add thing"));
popMenu.setPopupPositionAndShow(new PopupPanel.PositionCallback() {
public void setPosition(int offsetWidth, int offsetHeight) {
int left = parent.getX() + parent.getWidth();
int top = parent.getY() + parent.getWidth();
popMenu.setPopupPosition(left, top);
}
});
}
}
Got this response on the GWT google groups list, which worked:
addDomHandler(new ContextMenuHandler()
{
#Override
public void onContextMenu(ContextMenuEvent event)
{
showMenu();
event.preventDefault();
}
}, ContextMenuEvent.getType());

GWT resizable panel

Is there any way to have a 'Resizable' panel in GWT.
By resizable I mean that if you you drag on the edge of Panel it can be resized accordingly.
Figured it out myself, here is an example:
public class DraggablePanel extends VerticalPanel {
private boolean isBeingDragged = false;
private boolean isBeingMoved = false;
private Element movingPanelElement;
public void setMovingPanelElement(Element movingPanelElement) {
this.movingPanelElement = movingPanelElement;
}
public DraggablePanel() {
super();
DOM.sinkEvents(getElement(), Event.ONMOUSEDOWN | Event.ONMOUSEMOVE
| Event.ONMOUSEUP | Event.ONMOUSEOVER);
}
#Override
public void onBrowserEvent(Event event) {
final int eventType = DOM.eventGetType(event);
if (Event.ONMOUSEOVER == eventType) {
if (isCursorResize(event)) {
getElement().getStyle().setProperty("cursor", "s-resize");
} else if (isCursorMove(event)) {
getElement().getStyle().setProperty("cursor", "move");
} else {
getElement().getStyle().setProperty("cursor", "default");
}
}
if (Event.ONMOUSEDOWN == eventType) {
if (isCursorResize(event)) {
if (!isBeingDragged) {
isBeingDragged = true;
DOM.setCapture(getElement());
}
} else if (isCursorMove(event)) {
DOM.setCapture(getElement());
isBeingMoved = true;
}
} else if (Event.ONMOUSEMOVE == eventType) {
if (!isCursorResize(event) && !isCursorMove(event)) {
getElement().getStyle().setProperty("cursor", "default");
}
if (isBeingDragged) {
int currentY = event.getClientY();
int originalY = getElement().getAbsoluteTop();
if (currentY > originalY) {
Integer height = currentY - originalY;
this.setHeight(height + "px");
}
} else if (isBeingMoved) {
RootPanel.get().setWidgetPosition(this,
event.getClientX(), event.getClientY());
}
} else if (Event.ONMOUSEUP == eventType) {
if (isBeingMoved) {
isBeingMoved = false;
DOM.releaseCapture(getElement());
}
if (isBeingDragged) {
isBeingDragged = false;
DOM.releaseCapture(getElement());
}
}
}
protected boolean isCursorResize(Event event) {
int cursor = event.getClientY();
int initial = getAbsoluteTop();
int height = getOffsetHeight();
return initial + height - 20 < cursor && cursor <= initial + height;
}
protected boolean isCursorMove(Event event) {
int cursor = event.getClientY();
int initial = movingPanelElement.getAbsoluteTop();
int height = movingPanelElement.getOffsetHeight();
return initial <= cursor && cursor <= initial + height;
}
}
Just look here: http://code.google.com/p/resizepanel/
There is a fully functional example for FF/IE/GChrome
In modern browsers, you can solve this independently of GWT. Much easier and cleaner. Just use the CSS3 resize property, and specify an overflow value other than the default (visible).
Note that you'll probably want to override the resize property for child elements so they don't all inherit resize-handles.
In my case, I have something like this in my .ui.xml file:
<g:HTMLPanel addStyleNames="myTableContainer">
<g:ScrollPanel>
<g:FlexTable ui:field="myTable"></g:FlexTable>
</g:ScrollPanel>
</g:HTMLPanel>
And something like this in my stylesheet (GWT adds some extra divs, so you may need to adjust selectors to work for your case):
.myTableContainer div {
resize: vertical;
overflow: auto;
}
.myTableContainer div div {
resize: none;
overflow: visible;
}
This gives my FlexTable a resize handle in the bottom-right corner, like this:
Users can drag the handle down to vertically resize the panel containing my FlexTable. Of course, instead of vertical, you can also allow resizing to be horizontal or both.
If you prefer doing things programmatically to the UiBinder way, I'm sure you can adapt it by simply adding the appropriate styles to your elements in the code.
Downsides? Doesn't work in IE/Edge (hey, I said modern browsers... and CSS3), but in most others.
It looks like the GWT-Ext widget extensions contains what you want in its Resizable Panel
For the code above in onBrowserEvent(...) dont forget inserting
event.preventDefault();
or you will have troubles with firefox image dragging!