/******************************************************************************* * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.ole.win32; import java.util.*; import java.util.List; import org.eclipse.swt.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.ole.win32.*; import org.eclipse.swt.internal.win32.*; import org.eclipse.swt.widgets.*; /** * * OleFrame is an OLE Container's top level frame. * *
This object implements the OLE Interfaces IUnknown and IOleInPlaceFrame * *
OleFrame allows the container to do the following:
When an OLE Document is in-place active, the Document provides its own menus but the application * is given the opportunity to merge some of its menus into the menubar. The application * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window * (far right just before Help). The OLE Document retains control of the Edit, Object and Help * menu locations. Note that an application can insert more than one menu into a single location. * * @return the application menu items that will appear in the Container location when an OLE Document * is in-place activated. * */ public MenuItem[] getContainerMenus(){ return containerMenuItems; } /** * * Returns the application menu items that will appear in the File location when an OLE Document * is in-place activated. * *
When an OLE Document is in-place active, the Document provides its own menus but the application * is given the opportunity to merge some of its menus into the menubar. The application * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window * (far right just before Help). The OLE Document retains control of the Edit, Object and Help * menu locations. Note that an application can insert more than one menu into a single location. * * @return the application menu items that will appear in the File location when an OLE Document * is in-place activated. * */ public MenuItem[] getFileMenus(){ return fileMenuItems; } long getIOleInPlaceFrame() { return iOleInPlaceFrame.getAddress(); } private long getMenuItemID(long hMenu, int index) { long id = 0; MENUITEMINFO lpmii = new MENUITEMINFO(); lpmii.cbSize = MENUITEMINFO.sizeof; lpmii.fMask = OS.MIIM_STATE | OS.MIIM_SUBMENU | OS.MIIM_ID; OS.GetMenuItemInfo(hMenu, index, true, lpmii); if ((lpmii.fState & OS.MF_POPUP) == OS.MF_POPUP) { id = lpmii.hSubMenu; } else { id = lpmii.wID; } return id; } private int GetWindow(long phwnd) { if (phwnd != 0) { OS.MoveMemory(phwnd, new long[] {handle}, C.PTR_SIZEOF); } return COM.S_OK; } /** * * Returns the application menu items that will appear in the Window location when an OLE Document * is in-place activated. * *
When an OLE Document is in-place active, the Document provides its own menus but the application
* is given the opportunity to merge some of its menus into the menubar. The application
* is allowed to insert its menus in three locations: File (far left), Container(middle) and Window
* (far right just before Help). The OLE Document retains control of the Edit, Object and Help
* menu locations. Note that an application can insert more than one menu into a single location.
*
* @return the application menu items that will appear in the Window location when an OLE Document
* is in-place activated.
*
*/
public MenuItem[] getWindowMenus(){
return windowMenuItems;
}
private int InsertMenus(long hmenuShared, long lpMenuWidths) {
// locate menu bar
Menu menubar = getShell().getMenuBar();
if (menubar == null || menubar.isDisposed()) {
OS.MoveMemory(lpMenuWidths, new int[] {0}, 4);
return COM.S_OK;
}
long hMenu = menubar.handle;
// Create a holder for menu information. This will be passed down to
// the OS and the OS will fill in the requested information for each menu.
MENUITEMINFO lpmii = new MENUITEMINFO();
long hHeap = OS.GetProcessHeap();
int cch = 128;
int byteCount = cch * TCHAR.sizeof;
long pszText = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
lpmii.cbSize = MENUITEMINFO.sizeof;
lpmii.fMask = OS.MIIM_STATE | OS.MIIM_ID | OS.MIIM_TYPE | OS.MIIM_SUBMENU | OS.MIIM_DATA;
lpmii.dwTypeData = pszText;
lpmii.cch = cch;
// Loop over all "File-like" menus in the menubar and get information about the
// item from the OS.
int fileMenuCount = 0;
int newindex = 0;
if (this.fileMenuItems != null) {
for (int i = 0; i < this.fileMenuItems.length; i++) {
MenuItem item = this.fileMenuItems[i];
if (item != null) {
int index = item.getParent().indexOf(item);
lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the
// exact number of characters in name. Reset it to our max size
// before each call.
if (OS.GetMenuItemInfo(hMenu, index, true, lpmii)) {
if (OS.InsertMenuItem(hmenuShared, newindex, true, lpmii)) {
// keep track of the number of items
fileMenuCount++;
newindex++;
}
}
}
}
}
// copy the menu item count information to the pointer
OS.MoveMemory(lpMenuWidths, new int[] {fileMenuCount}, 4);
// Loop over all "Container-like" menus in the menubar and get information about the
// item from the OS.
int containerMenuCount = 0;
if (this.containerMenuItems != null) {
for (int i = 0; i < this.containerMenuItems.length; i++) {
MenuItem item = this.containerMenuItems[i];
if (item != null) {
int index = item.getParent().indexOf(item);
lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the
// exact number of characters in name. Reset it to a large number
// before each call.
if (OS.GetMenuItemInfo(hMenu, index, true, lpmii)) {
if (OS.InsertMenuItem(hmenuShared, newindex, true, lpmii)) {
// keep track of the number of items
containerMenuCount++;
newindex++;
}
}
}
}
}
// copy the menu item count information to the pointer
OS.MoveMemory(lpMenuWidths + 8, new int[] {containerMenuCount}, 4);
// Loop over all "Window-like" menus in the menubar and get information about the
// item from the OS.
int windowMenuCount = 0;
if (this.windowMenuItems != null) {
for (int i = 0; i < this.windowMenuItems.length; i++) {
MenuItem item = this.windowMenuItems[i];
if (item != null) {
int index = item.getParent().indexOf(item);
lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the
// exact number of characters in name. Reset it to a large number
// before each call.
if (OS.GetMenuItemInfo(hMenu, index, true, lpmii)) {
if (OS.InsertMenuItem(hmenuShared, newindex, true, lpmii)) {
// keep track of the number of items
windowMenuCount++;
newindex++;
}
}
}
}
}
// copy the menu item count information to the pointer
OS.MoveMemory(lpMenuWidths + 16, new int[] {windowMenuCount}, 4);
// free resources used in querying the OS
if (pszText != 0)
OS.HeapFree(hHeap, 0, pszText);
return COM.S_OK;
}
void onActivate(Event e) {
if (objIOleInPlaceActiveObject != null) {
objIOleInPlaceActiveObject.OnFrameWindowActivate(true);
}
}
void onDeactivate(Event e) {
if (objIOleInPlaceActiveObject != null) {
objIOleInPlaceActiveObject.OnFrameWindowActivate(false);
}
}
private void onDispose(Event e) {
releaseObjectInterfaces();
currentdoc = null;
this.Release();
removeListener(SWT.Activate, listener);
removeListener(SWT.Deactivate, listener);
removeListener(SWT.Dispose, listener);
removeListener(SWT.Resize, listener);
removeListener(SWT.Move, listener);
}
void onFocusIn(Event e) {
if (lastActivatedMenuHandle != newMenuHandle)
currentdoc.doVerb(OLE.OLEIVERB_SHOW);
if (OS.GetMenu(shellHandle) != newMenuHandle)
OS.SetMenu(shellHandle, newMenuHandle);
}
void onFocusOut(Event e) {
Control control = getDisplay().getFocusControl();
if (OS.GetMenu(shellHandle) != oldMenuHandle && control != null && control.handle != shellHandle)
OS.SetMenu(shellHandle, oldMenuHandle);
}
private void onResize(Event e) {
if (objIOleInPlaceActiveObject != null) {
RECT lpRect = new RECT();
OS.GetClientRect(handle, lpRect);
objIOleInPlaceActiveObject.ResizeBorder(lpRect, iOleInPlaceFrame.getAddress(), true);
}
}
private int QueryInterface(long riid, long ppvObject) {
// implements IUnknown, IOleInPlaceFrame, IOleContainer, IOleInPlaceUIWindow
if (riid == 0 || ppvObject == 0)
return COM.E_INVALIDARG;
GUID guid = new GUID();
COM.MoveMemory(guid, riid, GUID.sizeof);
if (COM.IsEqualGUID(guid, COM.IIDIUnknown) || COM.IsEqualGUID(guid, COM.IIDIOleInPlaceFrame) ) {
OS.MoveMemory(ppvObject, new long [] {iOleInPlaceFrame.getAddress()}, C.PTR_SIZEOF);
AddRef();
return COM.S_OK;
}
OS.MoveMemory(ppvObject, new long [] {0}, C.PTR_SIZEOF);
return COM.E_NOINTERFACE;
}
/**
* Decrement the count of references to this instance
*
* @return the current reference count
*/
int Release() {
refCount--;
if (refCount == 0){
disposeCOMInterfaces();
if (COM.FreeUnusedLibraries) {
COM.CoFreeUnusedLibraries();
}
}
return refCount;
}
private void releaseObjectInterfaces() {
if (objIOleInPlaceActiveObject != null) {
objIOleInPlaceActiveObject.Release();
}
objIOleInPlaceActiveObject = null;
}
private int RemoveMenus(long hmenuShared) {
Menu menubar = getShell().getMenuBar();
if (menubar == null || menubar.isDisposed()) return COM.S_FALSE;
long hMenu = menubar.handle;
List When an OLE Document is in-place active, the Document provides its own menus but the application
* is given the opportunity to merge some of its menus into the menubar. The application
* is allowed to insert its menus in three locations: File (far left), Container(middle) and Window
* (far right just before Help). The OLE Document retains control of the Edit, Object and Help
* menu locations. Note that an application can insert more than one menu into a single location.
*
* This method must be called before in place activation of the OLE Document. After the Document
* is activated, the menu bar will not be modified until a subsequent activation.
*
* @param containerMenus an array of top level MenuItems to be inserted into the Container location of
* the menubar
*/
public void setContainerMenus(MenuItem[] containerMenus){
containerMenuItems = containerMenus;
}
OleClientSite getCurrentDocument() {
return currentdoc;
}
void setCurrentDocument(OleClientSite doc) {
currentdoc = doc;
if (currentdoc != null && objIOleInPlaceActiveObject != null) {
RECT lpRect = new RECT();
OS.GetClientRect(handle, lpRect);
objIOleInPlaceActiveObject.ResizeBorder(lpRect, iOleInPlaceFrame.getAddress(), true);
}
}
/**
*
* Specify the menu items that should appear in the File location when an OLE Document
* is in-place activated.
*
* When an OLE Document is in-place active, the Document provides its own menus but the application
* is given the opportunity to merge some of its menus into the menubar. The application
* is allowed to insert its menus in three locations: File (far left), Container(middle) and Window
* (far right just before Help). The OLE Document retains control of the Edit, Object and Help
* menu locations. Note that an application can insert more than one menu into a single location.
*
* This method must be called before in place activation of the OLE Document. After the Document
* is activated, the menu bar will not be modified until a subsequent activation.
*
* @param fileMenus an array of top level MenuItems to be inserted into the File location of
* the menubar
*/
public void setFileMenus(MenuItem[] fileMenus){
fileMenuItems = fileMenus;
}
private int SetMenu(long hmenuShared, long holemenu, long hwndActiveObject) {
long inPlaceActiveObject = 0;
if (objIOleInPlaceActiveObject != null)
inPlaceActiveObject = objIOleInPlaceActiveObject.getAddress();
Menu menubar = getShell().getMenuBar();
if (menubar == null || menubar.isDisposed()){
return COM.OleSetMenuDescriptor(0, getShell().handle, hwndActiveObject, iOleInPlaceFrame.getAddress(), inPlaceActiveObject);
}
long handle = menubar.getShell().handle;
if (hmenuShared == 0 && holemenu == 0) {
// re-instate the original menu - this occurs on deactivation
hmenuShared = menubar.handle;
}
if (hmenuShared == 0) return COM.E_FAIL;
shellHandle = handle;
oldMenuHandle = menubar.handle;
newMenuHandle = hmenuShared;
lastActivatedMenuHandle = newMenuHandle;
return COM.OleSetMenuDescriptor(holemenu, handle, hwndActiveObject, iOleInPlaceFrame.getAddress(), inPlaceActiveObject);
}
/**
*
* Set the menu items that should appear in the Window location when an OLE Document
* is in-place activated.
*
* When an OLE Document is in-place active, the Document provides its own menus but the application
* is given the opportunity to merge some of its menus into the menubar. The application
* is allowed to insert its menus in three locations: File (far left), Container(middle) and Window
* (far right just before Help). The OLE Document retains control of the Edit, Object and Help
* menu locations. Note that an application can insert more than one menu into a single location.
*
* This method must be called before in place activation of the OLE Document. After the Document
* is activated, the menu bar will not be modified until a subsequent activation.
*
* @param windowMenus an array of top level MenuItems to be inserted into the Window location of
* the menubar
*/
public void setWindowMenus(MenuItem[] windowMenus){
windowMenuItems = windowMenus;
}
private boolean translateOleAccelerator(MSG msg) {
if (objIOleInPlaceActiveObject == null) return false;
int result = objIOleInPlaceActiveObject.TranslateAccelerator(msg);
return (result != COM.S_FALSE && result != COM.E_NOTIMPL);
}
private int TranslateAccelerator(long lpmsg, int wID){
Menu menubar = getShell().getMenuBar();
if (menubar == null || menubar.isDisposed() || !menubar.isEnabled()) return COM.S_FALSE;
if (wID < 0) return COM.S_FALSE;
Shell shell = menubar.getShell();
long hwnd = shell.handle;
long hAccel = OS.SendMessage(hwnd, OS.WM_APP+1, 0, 0);
if (hAccel == 0) return COM.S_FALSE;
MSG msg = new MSG();
OS.MoveMemory(msg, lpmsg, MSG.sizeof);
int result = OS.TranslateAccelerator(hwnd, hAccel, msg);
return result == 0 ? COM.S_FALSE : COM.S_OK;
}
}