0N/A/*
3147N/A * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
0N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
1472N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1472N/A *
1472N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
0N/A * or visit www.oracle.com if you need additional information or have any
0N/A * questions.
0N/A */
1879N/Apackage sun.awt.X11;
1879N/A
1879N/Aimport java.awt.*;
1879N/Aimport java.awt.peer.*;
1879N/Aimport java.awt.event.*;
1879N/A
1879N/Aimport java.awt.image.BufferedImage;
1879N/Aimport java.awt.geom.Point2D;
1879N/A
1879N/Aimport java.util.Vector;
1879N/Aimport sun.util.logging.PlatformLogger;
1879N/A
1879N/Apublic class XMenuWindow extends XBaseMenuWindow {
1879N/A
0N/A /************************************************
0N/A *
0N/A * Data members
0N/A *
0N/A ************************************************/
0N/A
0N/A private static PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XMenuWindow");
0N/A
0N/A /*
0N/A * Primary members
0N/A */
0N/A private XMenuPeer menuPeer;
0N/A
0N/A /*
0N/A * dimension constants
0N/A */
0N/A private final static int WINDOW_SPACING_LEFT = 2;
0N/A private final static int WINDOW_SPACING_RIGHT = 2;
0N/A private final static int WINDOW_SPACING_TOP = 2;
0N/A private final static int WINDOW_SPACING_BOTTOM = 2;
2230N/A private final static int WINDOW_ITEM_INDENT = 15;
2230N/A private final static int WINDOW_ITEM_MARGIN_LEFT = 2;
2230N/A private final static int WINDOW_ITEM_MARGIN_RIGHT = 2;
0N/A private final static int WINDOW_ITEM_MARGIN_TOP = 2;
0N/A private final static int WINDOW_ITEM_MARGIN_BOTTOM = 2;
0N/A private final static int WINDOW_SHORTCUT_SPACING = 10;
2230N/A
2230N/A /*
2230N/A * Checkmark
2230N/A */
2230N/A private static final int CHECKMARK_SIZE = 128;
2230N/A private static final int[] CHECKMARK_X = new int[] {1, 25,56,124,124,85, 64}; // X-coords
2230N/A private static final int[] CHECKMARK_Y = new int[] {59,35,67, 0, 12,66,123}; // Y-coords
2230N/A
2230N/A /************************************************
2230N/A *
2230N/A * Mapping data
2230N/A *
2230N/A ************************************************/
2230N/A
2230N/A static class MappingData extends XBaseMenuWindow.MappingData {
2230N/A /**
2230N/A * Rectangle for the caption
2230N/A * Necessary to fix 6267144: PIT: Popup menu label is not shown, XToolkit
2230N/A */
2230N/A private Rectangle captionRect;
0N/A
0N/A /**
0N/A * Desired size of menu window
0N/A */
0N/A private Dimension desiredSize;
0N/A
4321N/A /**
0N/A * Width of largest checkmark
4321N/A * At the same time the left origin
0N/A * of all item's text
0N/A */
0N/A private int leftMarkWidth;
0N/A
0N/A /**
0N/A * Left origin of all shortcut labels
0N/A */
0N/A private int shortcutOrigin;
4321N/A
0N/A /**
0N/A * The origin of right mark
0N/A * (submenu's arrow)
0N/A */
4321N/A private int rightMarkOrigin;
0N/A
0N/A MappingData(XMenuItemPeer[] items, Rectangle captionRect, Dimension desiredSize, int leftMarkWidth, int shortcutOrigin, int rightMarkOrigin) {
4321N/A super(items);
4321N/A this.captionRect = captionRect;
0N/A this.desiredSize = desiredSize;
0N/A this.leftMarkWidth = leftMarkWidth;
0N/A this.shortcutOrigin = shortcutOrigin;
0N/A this.rightMarkOrigin = rightMarkOrigin;
4321N/A }
0N/A
0N/A /**
4321N/A * Constructs MappingData without items
4321N/A * This constructor should be used in case of errors
0N/A */
4321N/A MappingData() {
4321N/A this.desiredSize = new Dimension(0, 0);
0N/A this.leftMarkWidth = 0;
0N/A this.shortcutOrigin = 0;
0N/A this.rightMarkOrigin = 0;
0N/A }
0N/A
0N/A public Rectangle getCaptionRect() {
0N/A return this.captionRect;
0N/A }
0N/A
0N/A public Dimension getDesiredSize() {
0N/A return this.desiredSize;
4321N/A }
4321N/A
4321N/A public int getShortcutOrigin() {
4321N/A return this.shortcutOrigin;
4321N/A }
0N/A
0N/A public int getLeftMarkWidth() {
0N/A return this.leftMarkWidth;
4321N/A }
4321N/A
4321N/A public int getRightMarkOrigin() {
4321N/A return this.rightMarkOrigin;
4321N/A }
4321N/A
4321N/A }
4321N/A
4321N/A
4321N/A /************************************************
4321N/A *
4321N/A * Construction
4321N/A *
4321N/A ************************************************/
4321N/A
4321N/A /**
4321N/A * Constructs XMenuWindow for specified XMenuPeer
4321N/A * null for XPopupMenuWindow
4321N/A */
4321N/A XMenuWindow(XMenuPeer menuPeer) {
4321N/A if (menuPeer != null) {
4321N/A this.menuPeer = menuPeer;
4321N/A this.target = menuPeer.getContainer().target;
4321N/A // Get menus from the target.
4321N/A Vector targetItemVector = null;
4321N/A targetItemVector = getMenuTargetItems();
4321N/A reloadItems(targetItemVector);
4321N/A }
4321N/A }
4321N/A
4321N/A /************************************************
4321N/A *
4321N/A * Initialization
4321N/A *
4321N/A ************************************************/
4321N/A /*
4321N/A * Overriden initialization
4321N/A */
4321N/A void postInit(XCreateWindowParams params) {
4321N/A super.postInit(params);
4321N/A //Fixed 6267182: PIT: Menu is not visible after
4321N/A //showing and disposing a file dialog, XToolkit
4321N/A //toFront() is called on every show
4321N/A }
4321N/A
4321N/A /************************************************
4321N/A *
4321N/A * Implementation of abstract methods
4321N/A *
4321N/A ************************************************/
4321N/A
4321N/A /**
4321N/A * @see XBaseMenuWindow.getParentMenuWindow()
4321N/A */
4321N/A protected XBaseMenuWindow getParentMenuWindow() {
4321N/A return (menuPeer != null) ? menuPeer.getContainer() : null;
4321N/A }
4321N/A
4321N/A /**
4321N/A * @see XBaseMenuWindow.map()
4321N/A */
4321N/A protected MappingData map() {
4321N/A //TODO:Implement popup-menu caption mapping and painting and tear-off
4321N/A int itemCnt;
4321N/A if (!isCreated()) {
4321N/A MappingData mappingData = new MappingData(new XMenuItemPeer[0], new Rectangle(0, 0, 0, 0), new Dimension(0, 0), 0, 0, 0);
4321N/A return mappingData;
4321N/A }
4321N/A XMenuItemPeer[] itemVector = copyItems();
4321N/A itemCnt = itemVector.length;
4321N/A //We need maximum width of components before calculating item's bounds
4321N/A Dimension captionSize = getCaptionSize();
4321N/A int maxWidth = (captionSize != null) ? captionSize.width : 0;
4321N/A int maxLeftIndent = 0;
4321N/A int maxRightIndent = 0;
4321N/A int maxShortcutWidth = 0;
4321N/A XMenuItemPeer.TextMetrics[] itemMetrics = new XMenuItemPeer.TextMetrics[itemCnt];
4321N/A for (int i = 0; i < itemCnt; i++) {
4321N/A XMenuItemPeer item = itemVector[i];
4321N/A itemMetrics[i] = itemVector[i].getTextMetrics();
4321N/A Dimension dim = itemMetrics[i].getTextDimension();
4321N/A if (dim != null) {
4321N/A if (itemVector[i] instanceof XCheckboxMenuItemPeer) {
4321N/A maxLeftIndent = Math.max(maxLeftIndent, dim.height);
4321N/A } else if (itemVector[i] instanceof XMenuPeer) {
4321N/A maxRightIndent = Math.max(maxRightIndent, dim.height);
4321N/A }
4321N/A maxWidth = Math.max(maxWidth, dim.width);
4321N/A maxShortcutWidth = Math.max(maxShortcutWidth, itemMetrics[i].getShortcutWidth());
4321N/A }
4321N/A }
4321N/A //Calculate bounds
4321N/A int nextOffset = WINDOW_SPACING_TOP;
4321N/A int shortcutOrigin = WINDOW_SPACING_LEFT + WINDOW_ITEM_MARGIN_LEFT + maxLeftIndent + maxWidth;
0N/A if (maxShortcutWidth > 0) {
0N/A shortcutOrigin = shortcutOrigin + WINDOW_SHORTCUT_SPACING;
0N/A }
0N/A int rightMarkOrigin = shortcutOrigin + maxShortcutWidth;
0N/A int itemWidth = rightMarkOrigin + maxRightIndent + WINDOW_ITEM_MARGIN_RIGHT;
0N/A int width = WINDOW_SPACING_LEFT + itemWidth + WINDOW_SPACING_RIGHT;
0N/A //Caption rectangle
0N/A Rectangle captionRect = null;
0N/A if (captionSize != null) {
0N/A captionRect = new Rectangle(WINDOW_SPACING_LEFT, nextOffset, itemWidth, captionSize.height);
0N/A nextOffset += captionSize.height;
0N/A } else {
0N/A captionRect = new Rectangle(WINDOW_SPACING_LEFT, nextOffset, maxWidth, 0);
0N/A }
0N/A //Item rectangles
0N/A for (int i = 0; i < itemCnt; i++) {
0N/A XMenuItemPeer item = (XMenuItemPeer)itemVector[i];
0N/A XMenuItemPeer.TextMetrics metrics = itemMetrics[i];
0N/A Dimension dim = metrics.getTextDimension();
0N/A if (dim != null) {
0N/A int itemHeight = WINDOW_ITEM_MARGIN_TOP + dim.height + WINDOW_ITEM_MARGIN_BOTTOM;
0N/A Rectangle bounds = new Rectangle(WINDOW_SPACING_LEFT, nextOffset, itemWidth, itemHeight);
0N/A int y = (itemHeight + dim.height) / 2 - metrics.getTextBaseline();
0N/A Point textOrigin = new Point(WINDOW_SPACING_LEFT + WINDOW_ITEM_MARGIN_LEFT + maxLeftIndent, nextOffset + y);
0N/A nextOffset += itemHeight;
0N/A item.map(bounds, textOrigin);
0N/A } else {
2230N/A //Text metrics could not be determined because of errors
0N/A //Map item with empty rectangle
0N/A Rectangle bounds = new Rectangle(WINDOW_SPACING_LEFT, nextOffset, 0, 0);
0N/A Point textOrigin = new Point(WINDOW_SPACING_LEFT + WINDOW_ITEM_MARGIN_LEFT + maxLeftIndent, nextOffset);
0N/A item.map(bounds, textOrigin);
2230N/A }
2230N/A }
0N/A int height = nextOffset + WINDOW_SPACING_BOTTOM;
0N/A MappingData mappingData = new MappingData(itemVector, captionRect, new Dimension(width, height), maxLeftIndent, shortcutOrigin, rightMarkOrigin);
0N/A return mappingData;
2230N/A }
2230N/A
0N/A /**
2230N/A * @see XBaseMenuWindow.getSubmenuBounds()
2230N/A */
0N/A protected Rectangle getSubmenuBounds(Rectangle itemBounds, Dimension windowSize) {
0N/A Rectangle globalBounds = toGlobal(itemBounds);
2230N/A Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
0N/A Rectangle res;
0N/A res = fitWindowRight(globalBounds, windowSize, screenSize);
0N/A if (res != null) {
0N/A return res;
0N/A }
2230N/A res = fitWindowBelow(globalBounds, windowSize, screenSize);
2230N/A if (res != null) {
0N/A return res;
0N/A }
0N/A res = fitWindowAbove(globalBounds, windowSize, screenSize);
2230N/A if (res != null) {
0N/A return res;
0N/A }
0N/A res = fitWindowLeft(globalBounds, windowSize, screenSize);
2230N/A if (res != null) {
2230N/A return res;
0N/A }
0N/A return fitWindowToScreen(windowSize, screenSize);
0N/A }
2230N/A
0N/A /**
0N/A * It's likely that size of items was changed
0N/A * invoke resizing of window on eventHandlerThread
0N/A */
0N/A protected void updateSize() {
0N/A resetMapping();
2442N/A if (isShowing()) {
2230N/A XToolkit.executeOnEventHandlerThread(target, new Runnable() {
0N/A public void run() {
0N/A Dimension dim = getDesiredSize();
0N/A reshape(x, y, dim.width, dim.height);
0N/A }
0N/A });
0N/A }
0N/A }
0N/A
0N/A /************************************************
2230N/A *
2230N/A * Overridable caption-painting functions
0N/A * Necessary to fix 6267144: PIT: Popup menu label is not shown, XToolkit
0N/A *
0N/A ************************************************/
0N/A
2230N/A /**
2230N/A * Returns size of menu window's caption or null
2230N/A * if window has no caption.
2230N/A * Can be overriden for popup menus and tear-off menus
0N/A */
2230N/A protected Dimension getCaptionSize() {
0N/A return null;
2230N/A }
2230N/A
2230N/A /**
2230N/A * Paints menu window's caption.
2230N/A * Can be overriden for popup menus and tear-off menus.
2230N/A * Default implementation does nothing
2230N/A */
0N/A protected void paintCaption(Graphics g, Rectangle rect) {
2230N/A }
0N/A
0N/A /************************************************
0N/A *
0N/A * General-purpose utility functions
2230N/A *
0N/A ************************************************/
2230N/A
0N/A /**
0N/A * Returns corresponding menu peer
0N/A */
0N/A XMenuPeer getMenuPeer() {
2230N/A return menuPeer;
2230N/A }
2230N/A
0N/A /**
0N/A * Reads vector of items from target
0N/A * This function is overriden in XPopupMenuPeer
0N/A */
2230N/A Vector getMenuTargetItems() {
2230N/A return menuPeer.getTargetItems();
2442N/A }
2442N/A
2230N/A /**
2230N/A * Returns desired size calculated while mapping
2230N/A */
2230N/A Dimension getDesiredSize() {
2230N/A MappingData mappingData = (MappingData)getMappingData();
0N/A return mappingData.getDesiredSize();
0N/A }
0N/A
2230N/A /**
2230N/A * Checks if menu window is created
2230N/A */
2230N/A boolean isCreated() {
2230N/A return getWindow() != 0;
0N/A }
0N/A
0N/A /**
0N/A * Performs delayed creation of menu window if necessary
0N/A */
0N/A boolean ensureCreated() {
0N/A if (!isCreated()) {
0N/A XCreateWindowParams params = getDelayedParams();
0N/A params.remove(DELAYED);
0N/A params.add(OVERRIDE_REDIRECT, Boolean.TRUE);
0N/A params.add(XWindow.TARGET, target);
0N/A init(params);
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A /**
0N/A * Init window if it's not inited yet
0N/A * and show it at specified coordinates
0N/A * @param bounds bounding rectangle of window
0N/A * in global coordinates
0N/A */
0N/A void show(Rectangle bounds) {
0N/A if (!isCreated()) {
2230N/A return;
0N/A }
0N/A if (log.isLoggable(PlatformLogger.FINER)) {
0N/A log.finer("showing menu window + " + getWindow() + " at " + bounds);
0N/A }
2230N/A XToolkit.awtLock();
0N/A try {
0N/A reshape(bounds.x, bounds.y, bounds.width, bounds.height);
0N/A xSetVisible(true);
0N/A //Fixed 6267182: PIT: Menu is not visible after
0N/A //showing and disposing a file dialog, XToolkit
0N/A toFront();
0N/A selectItem(getFirstSelectableItem(), false);
0N/A } finally {
2230N/A XToolkit.awtUnlock();
2230N/A }
2230N/A }
2230N/A
2230N/A /**
2230N/A * Hides menu window
2230N/A */
2230N/A void hide() {
2442N/A selectItem(null, false);
2230N/A xSetVisible(false);
2230N/A }
2230N/A
2230N/A /************************************************
2230N/A *
2230N/A * Painting
2230N/A *
4030N/A ************************************************/
4030N/A
2230N/A /**
2230N/A * Paints menu window
4030N/A */
4030N/A public void paint(Graphics g) {
2230N/A resetColors();
2230N/A
2230N/A int width = getWidth();
0N/A int height = getHeight();
0N/A
0N/A flush();
2230N/A //Fill background of rectangle
4141N/A g.setColor(getBackgroundColor());
2442N/A g.fillRect(1, 1, width - 2, height - 2);
4022N/A draw3DRect(g, 0, 0, width, height, true);
2442N/A
2442N/A //Mapping data
2442N/A MappingData mappingData = (MappingData)getMappingData();
2442N/A
2442N/A //Paint caption
2442N/A paintCaption(g, mappingData.getCaptionRect());
2442N/A
2442N/A //Paint menus
2442N/A XMenuItemPeer[] itemVector = mappingData.getItems();
2442N/A Dimension windowSize = mappingData.getDesiredSize();
2442N/A XMenuItemPeer selectedItem = getSelectedItem();
2442N/A for (int i = 0; i < itemVector.length; i++) {
2442N/A XMenuItemPeer item = itemVector[i];
2442N/A XMenuItemPeer.TextMetrics metrics = item.getTextMetrics();
2442N/A Rectangle bounds = item.getBounds();
2442N/A if (item.isSeparator()) {
2442N/A draw3DRect(g, bounds.x, bounds.y + bounds.height / 2, bounds.width, 2, false);
2442N/A } else {
2442N/A //paint item
2442N/A g.setFont(item.getTargetFont());
2442N/A Point textOrigin = item.getTextOrigin();
2442N/A Dimension textDim = metrics.getTextDimension();
2442N/A if (item == selectedItem) {
2442N/A g.setColor(getSelectedColor());
2442N/A g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
2442N/A draw3DRect(g, bounds.x, bounds.y, bounds.width, bounds.height, false);
2442N/A }
2442N/A g.setColor(item.isTargetItemEnabled() ? getForegroundColor() : getDisabledColor());
2442N/A g.drawString(item.getTargetLabel(), textOrigin.x, textOrigin.y);
2442N/A String shortcutText = item.getShortcutText();
2442N/A if (shortcutText != null) {
2442N/A g.drawString(shortcutText, mappingData.getShortcutOrigin(), textOrigin.y);
2442N/A }
2442N/A if (item instanceof XMenuPeer) {
2442N/A //calculate arrow coordinates
2442N/A int markWidth = textDim.height * 4 / 5;
2442N/A int markHeight = textDim.height * 4 / 5;
2442N/A int markX = bounds.x + bounds.width - markWidth - WINDOW_SPACING_RIGHT - WINDOW_ITEM_MARGIN_RIGHT;
2442N/A int markY = bounds.y + (bounds.height - markHeight) / 2;
2442N/A //draw arrow
2442N/A g.setColor(item.isTargetItemEnabled() ? getDarkShadowColor() : getDisabledColor());
2442N/A g.drawLine(markX, markY + markHeight, markX + markWidth, markY + markHeight / 2);
2442N/A g.setColor(item.isTargetItemEnabled() ? getLightShadowColor() : getDisabledColor());
2442N/A g.drawLine(markX, markY, markX + markWidth, markY + markHeight / 2);
2442N/A g.drawLine(markX, markY, markX, markY + markHeight);
2442N/A } else if (item instanceof XCheckboxMenuItemPeer) {
2442N/A //calculate checkmark coordinates
2442N/A int markWidth = textDim.height * 4 / 5;
2442N/A int markHeight = textDim.height * 4 / 5;
2442N/A int markX = WINDOW_SPACING_LEFT + WINDOW_ITEM_MARGIN_LEFT;
2442N/A int markY = bounds.y + (bounds.height - markHeight) / 2;
2442N/A boolean checkState = ((XCheckboxMenuItemPeer)item).getTargetState();
2442N/A //draw checkmark
2442N/A if (checkState) {
2442N/A g.setColor(getSelectedColor());
2442N/A g.fillRect(markX, markY, markWidth, markHeight);
2442N/A draw3DRect(g, markX, markY, markWidth, markHeight, false);
2442N/A int[] px = new int[CHECKMARK_X.length];
2442N/A int[] py = new int[CHECKMARK_X.length];
2442N/A for (int j = 0; j < CHECKMARK_X.length; j++) {
2442N/A px[j] = markX + CHECKMARK_X[j] * markWidth / CHECKMARK_SIZE;
2442N/A py[j] = markY + CHECKMARK_Y[j] * markHeight / CHECKMARK_SIZE;
4022N/A }
4022N/A g.setColor(item.isTargetItemEnabled() ? getForegroundColor() : getDisabledColor());
2442N/A g.fillPolygon(px, py, CHECKMARK_X.length);
4022N/A } else {
4022N/A g.setColor(getBackgroundColor());
2442N/A g.fillRect(markX, markY, markWidth, markHeight);
2442N/A draw3DRect(g, markX, markY, markWidth, markHeight, true);
2442N/A }
2442N/A }
2442N/A }
2442N/A }
2442N/A flush();
2442N/A }
2442N/A
2442N/A}
2442N/A