Mercurial > projects > dwt-win
annotate dwt/ole/win32/OleFrame.d @ 115:640928daee8c
Revert the reverting changes
Backed out changeset f353be82b6be
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 11 Feb 2008 04:05:55 +0100 |
parents | f353be82b6be |
children | 25f88bf5a6df |
rev | line source |
---|---|
98 | 1 /******************************************************************************* |
2 * Copyright (c) 2000, 2007 IBM Corporation and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module dwt.ole.win32.OleFrame; | |
14 | |
15 import dwt.DWT; | |
16 import dwt.DWTException; | |
17 import dwt.internal.ole.win32.COM; | |
18 import dwt.internal.ole.win32.OLEIDL; | |
19 import dwt.internal.ole.win32.extras; | |
20 import dwt.internal.win32.OS; | |
21 import dwt.widgets.Composite; | |
22 import dwt.widgets.Control; | |
23 import dwt.widgets.Display; | |
24 import dwt.widgets.Event; | |
25 import dwt.widgets.Listener; | |
26 import dwt.widgets.Menu; | |
27 import dwt.widgets.MenuItem; | |
28 import dwt.widgets.Shell; | |
29 import dwt.widgets.Widget; | |
30 | |
31 import dwt.ole.win32.OleClientSite; | |
32 import dwt.ole.win32.OLE; | |
33 | |
34 import dwt.dwthelper.utils; | |
35 import dwt.dwthelper.Runnable; | |
36 import tango.core.Array; | |
37 | |
38 /** | |
39 * | |
40 * OleFrame is an OLE Container's top level frame. | |
41 * | |
42 * <p>This object implements the OLE Interfaces IUnknown and IOleInPlaceFrame | |
43 * | |
44 * <p>OleFrame allows the container to do the following: <ul> | |
45 * <li>position and size the ActiveX Control or OLE Document within the application | |
46 * <li>insert menu items from the application into the OLE Document's menu | |
47 * <li>activate and deactivate the OLE Document's menus | |
48 * <li>position the OLE Document's menu in the application | |
49 * <li>translate accelerator keystrokes intended for the container's frame</ul> | |
50 * | |
51 * <dl> | |
52 * <dt><b>Styles</b> <dd>BORDER | |
53 * <dt><b>Events</b> <dd>Dispose, Move, Resize | |
54 * </dl> | |
55 * | |
56 */ | |
57 final public class OleFrame : Composite | |
58 { | |
59 // Interfaces for this Ole Client Container | |
60 //private COMObject iUnknown; | |
61 private _IOleInPlaceFrameImpl iOleInPlaceFrame; | |
62 | |
63 // Access to the embedded/linked Ole Object | |
64 private IOleInPlaceActiveObject objIOleInPlaceActiveObject; | |
65 | |
66 private OleClientSite currentdoc; | |
67 | |
68 private int refCount = 0; | |
69 | |
70 private MenuItem[] fileMenuItems; | |
71 private MenuItem[] containerMenuItems; | |
72 private MenuItem[] windowMenuItems; | |
73 | |
74 private Listener listener; | |
75 | |
76 private static char[] CHECK_FOCUS = "OLE_CHECK_FOCUS"; //$NON-NLS-1$ | |
77 private static char[] HHOOK = "OLE_HHOOK"; //$NON-NLS-1$ | |
78 private static char[] HHOOKMSG = "OLE_HHOOK_MSG"; //$NON-NLS-1$ | |
79 | |
80 private static bool ignoreNextKey; | |
81 private static const short [] ACCENTS = [ cast(short)'~', '`', '\'', '^', '"']; | |
82 | |
83 private static const char[] CONSUME_KEY = "org.eclipse.swt.OleFrame.ConsumeKey"; //$NON-NLS-1$ | |
84 | |
85 /** | |
86 * Create an OleFrame child widget using style bits | |
87 * to select a particular look or set of properties. | |
88 * | |
89 * @param parent a composite widget (cannot be null) | |
90 * @param style the bitwise OR'ing of widget styles | |
91 * | |
92 * @exception IllegalArgumentException <ul> | |
93 * <li>ERROR_NULL_ARGUMENT when the parent is null | |
94 * </ul> | |
95 * @exception DWTException <ul> | |
96 * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread | |
97 * </ul> | |
98 * | |
99 */ | |
100 public this(Composite parent, int style) { | |
101 super(parent, style); | |
102 | |
103 createCOMInterfaces(); | |
104 | |
105 // setup cleanup proc | |
106 listener = new class() Listener { | |
107 public void handleEvent(Event e) { | |
108 switch (e.type) { | |
109 case DWT.Activate : onActivate(e); break; | |
110 case DWT.Deactivate : onDeactivate(e); break; | |
111 case DWT.Dispose : onDispose(e); break; | |
112 case DWT.Resize : | |
113 case DWT.Move : onResize(e); break; | |
114 default : | |
115 OLE.error(DWT.ERROR_NOT_IMPLEMENTED); | |
116 } | |
117 } | |
118 }; | |
119 | |
120 | |
121 addListener(DWT.Activate, listener); | |
122 addListener(DWT.Deactivate, listener); | |
123 addListener(DWT.Dispose, listener); | |
124 | |
125 // inform inplaceactiveobject whenever frame resizes | |
126 addListener(DWT.Resize, listener); | |
127 | |
128 // inform inplaceactiveobject whenever frame moves | |
129 addListener(DWT.Move, listener); | |
130 | |
131 // Maintain a reference to yourself so that when | |
132 // ClientSites close, they don't take the frame away | |
133 // with them. | |
134 this.AddRef(); | |
135 | |
136 // Check for focus change | |
137 Display display = getDisplay(); | |
138 initCheckFocus(display); | |
139 initMsgHook(display); | |
140 } | |
141 private static void initCheckFocus (Display display_) { | |
142 if (display_.getData(CHECK_FOCUS) !is null) return; | |
143 display_.setData(CHECK_FOCUS, new ArrayWrapperString(CHECK_FOCUS)); | |
144 static const int time = 50; | |
145 auto timer = new class(display_) Runnable { | |
146 Display display; | |
147 Control[1] lastFocus; | |
148 this( Display display){ this.display = display; } | |
149 public void run() { | |
150 if (( null !is cast(OleClientSite)lastFocus[0] ) && !lastFocus[0].isDisposed()) { | |
151 // ignore popup menus and dialogs | |
152 auto hwnd = OS.GetFocus(); | |
153 while (hwnd !is null) { | |
154 auto ownerHwnd = OS.GetWindow(hwnd, OS.GW_OWNER); | |
155 if (ownerHwnd !is null) { | |
156 display.timerExec(time, this); | |
157 return; | |
158 } | |
159 hwnd = OS.GetParent(hwnd); | |
160 } | |
161 } | |
162 if (lastFocus[0] is null || lastFocus[0].isDisposed() || !lastFocus[0].isFocusControl()) { | |
163 Control currentFocus = display.getFocusControl(); | |
164 if ( auto frame = cast(OleFrame)currentFocus ) { | |
165 currentFocus = frame.getCurrentDocument(); | |
166 } | |
167 if (lastFocus[0] !is currentFocus) { | |
168 Event event = new Event(); | |
169 if (( null !is cast(OleClientSite)lastFocus[0] ) && !lastFocus[0].isDisposed()) { | |
170 lastFocus[0].notifyListeners (DWT.FocusOut, event); | |
171 } | |
172 if (( null !is cast(OleClientSite)currentFocus ) && !currentFocus.isDisposed()) { | |
173 currentFocus.notifyListeners(DWT.FocusIn, event); | |
174 } | |
175 } | |
176 lastFocus[0] = currentFocus; | |
177 } | |
178 display.timerExec(time, this); | |
179 } | |
180 }; | |
181 display_.timerExec(time, timer); | |
182 } | |
183 private static void initMsgHook(Display display) { | |
184 if (display.getData(HHOOK) !is null) return; | |
185 //final Callback callback = new Callback(OleFrame.class, "getMsgProc", 3); //$NON-NLS-1$ | |
186 //int address = callback.getAddress(); | |
187 //if (address is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS); | |
188 int threadId = OS.GetCurrentThreadId(); | |
189 auto hHook_ = OS.SetWindowsHookEx(OS.WH_GETMESSAGE, &getMsgProc, null, threadId); | |
190 if (hHook_ is null) { | |
191 //callback.dispose(); | |
192 return; | |
193 } | |
194 display.setData(HHOOK, new ValueWrapperT!(void*)(hHook_)); | |
195 display.setData(HHOOKMSG, new ValueWrapperT!(MSG*)(new MSG())); | |
196 display.disposeExec(new class(hHook_) Runnable { | |
197 void* hHook; | |
198 this( void* hHook ){ this.hHook = hHook; } | |
199 public void run() { | |
200 if (hHook !is null) OS.UnhookWindowsHookEx(hHook); | |
201 //if (callback !is null) callback.dispose(); | |
202 } | |
203 }); | |
204 } | |
205 static extern(Windows) int getMsgProc(int code, int wParam, int lParam) { | |
206 Display display = Display.getCurrent(); | |
207 if (display is null) return 0; | |
208 auto hHook = cast(ValueWrapperT!(void*))display.getData(HHOOK); | |
209 if (hHook is null) return 0; | |
210 if (code < 0) { | |
211 return OS.CallNextHookEx(hHook.value, code, wParam, lParam); | |
212 } | |
213 MSG* msg = cast(MSG*)(cast(ValueWrapperT!(MSG*))display.getData(HHOOKMSG)).value; | |
214 OS.MoveMemory(msg, lParam, MSG.sizeof); | |
215 int message = msg.message; | |
216 if (OS.WM_KEYFIRST <= message && message <= OS.WM_KEYLAST) { | |
217 if (display !is null) { | |
218 Widget widget = null; | |
219 auto hwnd = msg.hwnd; | |
220 while (hwnd !is null) { | |
221 widget = display.findWidget (hwnd); | |
222 if (widget !is null) break; | |
223 hwnd = OS.GetParent (hwnd); | |
224 } | |
225 if (widget !is null && (null !is cast(OleClientSite)widget )) { | |
226 OleClientSite site = cast(OleClientSite)widget; | |
227 if (site.handle is hwnd) { | |
228 bool consumed = false; | |
229 /* Allow activeX control to translate accelerators except when a menu is active. */ | |
230 int thread = OS.GetWindowThreadProcessId(msg.hwnd, null); | |
231 GUITHREADINFO* lpgui = new GUITHREADINFO(); | |
232 lpgui.cbSize = GUITHREADINFO.sizeof; | |
233 bool rc = cast(bool) OS.GetGUIThreadInfo(thread, lpgui); | |
234 int mask = OS.GUI_INMENUMODE | OS.GUI_INMOVESIZE | OS.GUI_POPUPMENUMODE | OS.GUI_SYSTEMMENUMODE; | |
235 if (!rc || (lpgui.flags & mask) is 0) { | |
236 OleFrame frame = site.frame; | |
237 frame.setData(CONSUME_KEY, null); | |
238 consumed = frame.translateOleAccelerator(msg); | |
239 if (frame.getData(CONSUME_KEY) !is null) consumed = false; | |
240 frame.setData(CONSUME_KEY, null); | |
241 } | |
242 bool accentKey = false; | |
243 switch (msg.message) { | |
244 case OS.WM_KEYDOWN: | |
245 case OS.WM_SYSKEYDOWN: { | |
115
640928daee8c
Revert the reverting changes
Frank Benoit <benoit@tionex.de>
parents:
113
diff
changeset
|
246 if (!OS.IsWinCE) { |
98 | 247 switch (msg.wParam) { |
248 case OS.VK_SHIFT: | |
249 case OS.VK_MENU: | |
250 case OS.VK_CONTROL: | |
251 case OS.VK_CAPITAL: | |
252 case OS.VK_NUMLOCK: | |
253 case OS.VK_SCROLL: | |
254 break; | |
255 default: { | |
256 /* | |
257 * Bug in Windows. The high bit in the result of MapVirtualKey() on | |
258 * Windows NT is bit 32 while the high bit on Windows 95 is bit 16. | |
259 * They should both be bit 32. The fix is to test the right bit. | |
260 */ | |
261 int mapKey = OS.MapVirtualKey (msg.wParam, 2); | |
262 if (mapKey !is 0) { | |
263 accentKey = (mapKey & (OS.IsWinNT ? 0x80000000 : 0x8000)) !is 0; | |
264 if (!accentKey) { | |
265 for (int i=0; i<ACCENTS.length; i++) { | |
266 int value = OS.VkKeyScan (ACCENTS [i]); | |
267 if (value !is -1 && (value & 0xFF) is msg.wParam) { | |
268 int state = value >> 8; | |
269 if ((OS.GetKeyState (OS.VK_SHIFT) < 0) is ((state & 0x1) !is 0) && | |
270 (OS.GetKeyState (OS.VK_CONTROL) < 0) is ((state & 0x2) !is 0) && | |
271 (OS.GetKeyState (OS.VK_MENU) < 0) is ((state & 0x4) !is 0)) { | |
272 if ((state & 0x7) !is 0) accentKey = true; | |
273 break; | |
274 } | |
275 } | |
276 } | |
277 } | |
278 } | |
279 break; | |
280 } | |
281 } | |
282 } | |
283 break; | |
284 } | |
285 } | |
286 /* Allow OleClientSite to process key events before activeX control */ | |
287 if (!consumed && !accentKey && !ignoreNextKey) { | |
288 auto hwndOld = msg.hwnd; | |
289 msg.hwnd = site.handle; | |
290 consumed = OS.DispatchMessage (msg) is 1; | |
291 msg.hwnd = hwndOld; | |
292 } | |
293 switch (msg.message) { | |
294 case OS.WM_KEYDOWN: | |
295 case OS.WM_SYSKEYDOWN: { | |
296 switch (msg.wParam) { | |
297 case OS.VK_SHIFT: | |
298 case OS.VK_MENU: | |
299 case OS.VK_CONTROL: | |
300 case OS.VK_CAPITAL: | |
301 case OS.VK_NUMLOCK: | |
302 case OS.VK_SCROLL: | |
303 break; | |
304 default: { | |
305 ignoreNextKey = accentKey; | |
306 break; | |
307 } | |
308 } | |
309 } | |
310 } | |
311 | |
312 if (consumed) { | |
313 // In order to prevent this message from also being processed | |
314 // by the application, zero out message, wParam and lParam | |
315 msg.message = OS.WM_NULL; | |
316 msg.wParam = msg.lParam = 0; | |
317 OS.MoveMemory(lParam, msg, MSG.sizeof); | |
318 return 0; | |
319 } | |
320 } | |
321 } | |
322 } | |
323 } | |
324 return OS.CallNextHookEx( hHook.value, code, wParam, lParam); | |
325 } | |
326 /** | |
327 * Increment the count of references to this instance | |
328 * | |
329 * @return the current reference count | |
330 */ | |
331 int AddRef() { | |
332 refCount++; | |
333 return refCount; | |
334 } | |
335 private int ContextSensitiveHelp(int fEnterMode) { | |
336 return COM.S_OK; | |
337 } | |
338 private void createCOMInterfaces() { | |
339 iOleInPlaceFrame = new _IOleInPlaceFrameImpl(this); | |
340 } | |
341 private void disposeCOMInterfaces () { | |
342 iOleInPlaceFrame = null; | |
343 } | |
344 private HRESULT GetBorder(LPRECT lprectBorder) { | |
345 /* | |
346 The IOleInPlaceUIWindow::GetBorder function, when called on a document or frame window | |
347 object, returns the outer rectangle (relative to the window) where the object can put | |
348 toolbars or similar controls. | |
349 */ | |
350 if (lprectBorder is null) return COM.E_INVALIDARG; | |
351 RECT* rectBorder = new RECT(); | |
352 // Coordinates must be relative to the window | |
353 OS.GetClientRect(handle, lprectBorder); | |
354 return COM.S_OK; | |
355 } | |
356 /** | |
357 * | |
358 * Returns the application menu items that will appear in the Container location when an OLE Document | |
359 * is in-place activated. | |
360 * | |
361 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application | |
362 * is given the opportunity to merge some of its menus into the menubar. The application | |
363 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window | |
364 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help | |
365 * menu locations. Note that an application can insert more than one menu into a single location. | |
366 * | |
367 * @return the application menu items that will appear in the Container location when an OLE Document | |
368 * is in-place activated. | |
369 * | |
370 */ | |
371 public MenuItem[] getContainerMenus(){ | |
372 return containerMenuItems; | |
373 } | |
374 /** | |
375 * | |
376 * Returns the application menu items that will appear in the File location when an OLE Document | |
377 * is in-place activated. | |
378 * | |
379 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application | |
380 * is given the opportunity to merge some of its menus into the menubar. The application | |
381 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window | |
382 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help | |
383 * menu locations. Note that an application can insert more than one menu into a single location. | |
384 * | |
385 * @return the application menu items that will appear in the File location when an OLE Document | |
386 * is in-place activated. | |
387 * | |
388 */ | |
389 public MenuItem[] getFileMenus(){ | |
390 return fileMenuItems; | |
391 } | |
392 IOleInPlaceFrame getIOleInPlaceFrame() { | |
393 return iOleInPlaceFrame; | |
394 } | |
395 private int getMenuItemID(HMENU hMenu, int index) { | |
396 int id = 0; | |
397 MENUITEMINFO lpmii; | |
398 lpmii.cbSize = MENUITEMINFO.sizeof; | |
399 lpmii.fMask = OS.MIIM_STATE | OS.MIIM_SUBMENU | OS.MIIM_ID; | |
400 OS.GetMenuItemInfo(hMenu, index, true, &lpmii); | |
401 if ((lpmii.fState & OS.MF_POPUP) is OS.MF_POPUP) { | |
402 id = cast(int)lpmii.hSubMenu; | |
403 } else { | |
404 id = lpmii.wID; | |
405 } | |
406 return id; | |
407 } | |
408 private int GetWindow(HWND* phwnd) { | |
409 if (phwnd !is null) { | |
410 *phwnd = handle; | |
411 } | |
412 return COM.S_OK; | |
413 } | |
414 /** | |
415 * | |
416 * Returns the application menu items that will appear in the Window location when an OLE Document | |
417 * is in-place activated. | |
418 * | |
419 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application | |
420 * is given the opportunity to merge some of its menus into the menubar. The application | |
421 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window | |
422 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help | |
423 * menu locations. Note that an application can insert more than one menu into a single location. | |
424 * | |
425 * @return the application menu items that will appear in the Window location when an OLE Document | |
426 * is in-place activated. | |
427 * | |
428 */ | |
429 public MenuItem[] getWindowMenus(){ | |
430 return windowMenuItems; | |
431 } | |
432 private HRESULT InsertMenus( HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths ) { | |
433 // locate menu bar | |
434 Menu menubar = getShell().getMenuBar(); | |
435 if (menubar is null || menubar.isDisposed()) { | |
436 int temp = 0; | |
437 COM.MoveMemory(lpMenuWidths, &temp, 4); | |
438 return COM.S_OK; | |
439 } | |
440 HMENU hMenu = menubar.handle; | |
441 | |
442 // Create a holder for menu information. This will be passed down to | |
443 // the OS and the OS will fill in the requested information for each menu. | |
444 MENUITEMINFO lpmii; | |
445 auto hHeap = OS.GetProcessHeap(); | |
446 int cch = 128; | |
447 int byteCount = cch * TCHAR.sizeof; | |
448 auto pszText = cast(TCHAR*) OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount); | |
449 lpmii.cbSize = MENUITEMINFO.sizeof; | |
450 lpmii.fMask = OS.MIIM_STATE | OS.MIIM_ID | OS.MIIM_TYPE | OS.MIIM_SUBMENU | OS.MIIM_DATA; | |
451 lpmii.dwTypeData = pszText; | |
452 lpmii.cch = cch; | |
453 | |
454 // Loop over all "File-like" menus in the menubar and get information about the | |
455 // item from the OS. | |
456 int fileMenuCount = 0; | |
457 int newindex = 0; | |
458 if (this.fileMenuItems !is null) { | |
459 for (int i = 0; i < this.fileMenuItems.length; i++) { | |
460 MenuItem item = this.fileMenuItems[i]; | |
461 if (item !is null) { | |
462 int index = item.getParent().indexOf(item); | |
463 lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the | |
464 // exact number of characters in name. Reset it to our max size | |
465 // before each call. | |
466 if (OS.GetMenuItemInfo(hMenu, index, true, &lpmii)) { | |
467 if (OS.InsertMenuItem(hmenuShared, newindex, true, &lpmii)) { | |
468 // keep track of the number of items | |
469 fileMenuCount++; | |
470 newindex++; | |
471 } | |
472 } | |
473 } | |
474 } | |
475 } | |
476 | |
477 // copy the menu item count information to the pointer | |
478 COM.MoveMemory(lpMenuWidths, &fileMenuCount, 4); | |
479 | |
480 // Loop over all "Container-like" menus in the menubar and get information about the | |
481 // item from the OS. | |
482 int containerMenuCount = 0; | |
483 if (this.containerMenuItems !is null) { | |
484 for (int i = 0; i < this.containerMenuItems.length; i++) { | |
485 MenuItem item = this.containerMenuItems[i]; | |
486 if (item !is null) { | |
487 int index = item.getParent().indexOf(item); | |
488 lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the | |
489 // exact number of characters in name. Reset it to a large number | |
490 // before each call. | |
491 if (OS.GetMenuItemInfo(hMenu, index, true, &lpmii)) { | |
492 if (OS.InsertMenuItem(hmenuShared, newindex, true, &lpmii)) { | |
493 // keep track of the number of items | |
494 containerMenuCount++; | |
495 newindex++; | |
496 } | |
497 } | |
498 } | |
499 } | |
500 } | |
501 | |
502 // copy the menu item count information to the pointer | |
503 COM.MoveMemory(lpMenuWidths + 8, &containerMenuCount, 4); | |
504 | |
505 // Loop over all "Window-like" menus in the menubar and get information about the | |
506 // item from the OS. | |
507 int windowMenuCount = 0; | |
508 if (this.windowMenuItems !is null) { | |
509 for (int i = 0; i < this.windowMenuItems.length; i++) { | |
510 MenuItem item = this.windowMenuItems[i]; | |
511 if (item !is null) { | |
512 int index = item.getParent().indexOf(item); | |
513 lpmii.cch = cch; // lpmii.cch gets updated by GetMenuItemInfo to indicate the | |
514 // exact number of characters in name. Reset it to a large number | |
515 // before each call. | |
516 if (OS.GetMenuItemInfo(hMenu, index, true, &lpmii)) { | |
517 if (OS.InsertMenuItem(hmenuShared, newindex, true, &lpmii)) { | |
518 // keep track of the number of items | |
519 windowMenuCount++; | |
520 newindex++; | |
521 } | |
522 } | |
523 } | |
524 } | |
525 } | |
526 | |
527 // copy the menu item count information to the pointer | |
528 COM.MoveMemory(lpMenuWidths + 16, &windowMenuCount, 4); | |
529 | |
530 // free resources used in querying the OS | |
531 if (pszText !is null) | |
532 OS.HeapFree(hHeap, 0, pszText); | |
533 return COM.S_OK; | |
534 } | |
535 void onActivate(Event e) { | |
536 if (objIOleInPlaceActiveObject !is null) { | |
537 objIOleInPlaceActiveObject.OnFrameWindowActivate(true); | |
538 } | |
539 if (objIOleInPlaceActiveObject !is null) { | |
540 objIOleInPlaceActiveObject.OnDocWindowActivate(true); | |
541 } | |
542 } | |
543 void onDeactivate(Event e) { | |
544 if (objIOleInPlaceActiveObject !is null) { | |
545 objIOleInPlaceActiveObject.OnFrameWindowActivate(false); | |
546 } | |
547 if (objIOleInPlaceActiveObject !is null) { | |
548 objIOleInPlaceActiveObject.OnDocWindowActivate(false); | |
549 } | |
550 } | |
551 private void onDispose(Event e) { | |
552 | |
553 releaseObjectInterfaces(); | |
554 currentdoc = null; | |
555 | |
556 this.Release(); | |
557 removeListener(DWT.Activate, listener); | |
558 removeListener(DWT.Deactivate, listener); | |
559 removeListener(DWT.Dispose, listener); | |
560 removeListener(DWT.Resize, listener); | |
561 removeListener(DWT.Move, listener); | |
562 } | |
563 private void onResize(Event e) { | |
564 if (objIOleInPlaceActiveObject !is null) { | |
565 RECT lpRect; | |
566 OS.GetClientRect(handle, &lpRect); | |
567 objIOleInPlaceActiveObject.ResizeBorder(&lpRect, iOleInPlaceFrame, true); | |
568 } | |
569 } | |
570 private HRESULT QueryInterface(REFIID riid, void** ppvObject) { | |
571 // implements IUnknown, IOleInPlaceFrame, IOleContainer, IOleInPlaceUIWindow | |
572 if (riid is null || ppvObject is null) | |
573 return COM.E_INVALIDARG; | |
574 | |
575 if (COM.IsEqualGUID(riid, &COM.IIDIUnknown) || COM.IsEqualGUID(riid, &COM.IIDIOleInPlaceFrame) ) { | |
576 *ppvObject = cast(void*)iOleInPlaceFrame; | |
577 AddRef(); | |
578 return COM.S_OK; | |
579 } | |
580 | |
581 *ppvObject = null; | |
582 return COM.E_NOINTERFACE; | |
583 } | |
584 /** | |
585 * Decrement the count of references to this instance | |
586 * | |
587 * @return the current reference count | |
588 */ | |
589 int Release() { | |
590 refCount--; | |
591 if (refCount is 0){ | |
592 disposeCOMInterfaces(); | |
593 COM.CoFreeUnusedLibraries(); | |
594 } | |
595 return refCount; | |
596 } | |
597 private void releaseObjectInterfaces() { | |
598 if (objIOleInPlaceActiveObject !is null) { | |
599 objIOleInPlaceActiveObject.Release(); | |
600 } | |
601 objIOleInPlaceActiveObject = null; | |
602 } | |
603 private int RemoveMenus(HMENU hmenuShared) { | |
604 | |
605 Menu menubar = getShell().getMenuBar(); | |
606 if (menubar is null || menubar.isDisposed()) return COM.S_FALSE; | |
607 | |
608 auto hMenu = menubar.handle; | |
609 | |
610 int[] ids; | |
611 if (this.fileMenuItems !is null) { | |
612 for (int i = 0; i < this.fileMenuItems.length; i++) { | |
613 MenuItem item = this.fileMenuItems[i]; | |
614 if (item !is null && !item.isDisposed()) { | |
615 int index = item.getParent().indexOf(item); | |
616 // get Id from original menubar | |
617 int id = getMenuItemID(hMenu, index); | |
618 ids ~= id; | |
619 } | |
620 } | |
621 } | |
622 if (this.containerMenuItems !is null) { | |
623 for (int i = 0; i < this.containerMenuItems.length; i++) { | |
624 MenuItem item = this.containerMenuItems[i]; | |
625 if (item !is null && !item.isDisposed()) { | |
626 int index = item.getParent().indexOf(item); | |
627 int id = getMenuItemID(hMenu, index); | |
628 ids ~= id; | |
629 } | |
630 } | |
631 } | |
632 if (this.windowMenuItems !is null) { | |
633 for (int i = 0; i < this.windowMenuItems.length; i++) { | |
634 MenuItem item = this.windowMenuItems[i]; | |
635 if (item !is null && !item.isDisposed()) { | |
636 int index = item.getParent().indexOf(item); | |
637 int id = getMenuItemID(hMenu, index); | |
638 ids ~= id; | |
639 } | |
640 } | |
641 } | |
642 int index = OS.GetMenuItemCount(hmenuShared) - 1; | |
643 for (int i = index; i >= 0; i--) { | |
644 int id = getMenuItemID(hmenuShared, i); | |
645 if ( ids.contains(id)){ | |
646 OS.RemoveMenu(hmenuShared, i, OS.MF_BYPOSITION); | |
647 } | |
648 } | |
649 return COM.S_OK; | |
650 } | |
651 private int RequestBorderSpace(LPCBORDERWIDTHS pborderwidths) { | |
652 return COM.S_OK; | |
653 } | |
654 HRESULT SetActiveObject( LPOLEINPLACEACTIVEOBJECT pActiveObject, LPCOLESTR pszObjName ) { | |
655 if (objIOleInPlaceActiveObject !is null) { | |
656 objIOleInPlaceActiveObject.Release(); | |
657 objIOleInPlaceActiveObject = null; | |
658 } | |
659 if (pActiveObject !is null) { | |
660 objIOleInPlaceActiveObject = pActiveObject; | |
661 objIOleInPlaceActiveObject.AddRef(); | |
662 } | |
663 | |
664 return COM.S_OK; | |
665 } | |
666 | |
667 private HRESULT SetBorderSpace( LPCBORDERWIDTHS pborderwidths ) { | |
668 // A Control/Document can : | |
669 // Use its own toolbars, requesting border space of a specific size, or, | |
670 // Use no toolbars, but force the container to remove its toolbars by passing a | |
671 // valid BORDERWIDTHS structure containing nothing but zeros in the pborderwidths parameter, or, | |
672 // Use no toolbars but allow the in-place container to leave its toolbars up by | |
673 // passing NULL as the pborderwidths parameter. | |
674 if (objIOleInPlaceActiveObject is null) return COM.S_OK; | |
675 RECT* borderwidth = new RECT(); | |
676 if (pborderwidths is null || currentdoc is null ) return COM.S_OK; | |
677 | |
678 COM.MoveMemory(borderwidth, pborderwidths, RECT.sizeof); | |
679 currentdoc.setBorderSpace(borderwidth); | |
680 | |
681 return COM.S_OK; | |
682 } | |
683 /** | |
684 * | |
685 * Specify the menu items that should appear in the Container location when an OLE Document | |
686 * is in-place activated. | |
687 * | |
688 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application | |
689 * is given the opportunity to merge some of its menus into the menubar. The application | |
690 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window | |
691 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help | |
692 * menu locations. Note that an application can insert more than one menu into a single location. | |
693 * | |
694 * <p>This method must be called before in place activation of the OLE Document. After the Document | |
695 * is activated, the menu bar will not be modified until a subsequent activation. | |
696 * | |
697 * @param containerMenus an array of top level MenuItems to be inserted into the Container location of | |
698 * the menubar | |
699 */ | |
700 public void setContainerMenus(MenuItem[] containerMenus){ | |
701 containerMenuItems = containerMenus; | |
702 } | |
703 OleClientSite getCurrentDocument() { | |
704 return currentdoc; | |
705 } | |
706 void setCurrentDocument(OleClientSite doc) { | |
707 currentdoc = doc; | |
708 | |
709 if (currentdoc !is null && objIOleInPlaceActiveObject !is null) { | |
710 RECT lpRect; | |
711 OS.GetClientRect(handle, &lpRect); | |
712 objIOleInPlaceActiveObject.ResizeBorder(&lpRect, iOleInPlaceFrame, true); | |
713 } | |
714 } | |
715 /** | |
716 * | |
717 * Specify the menu items that should appear in the File location when an OLE Document | |
718 * is in-place activated. | |
719 * | |
720 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application | |
721 * is given the opportunity to merge some of its menus into the menubar. The application | |
722 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window | |
723 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help | |
724 * menu locations. Note that an application can insert more than one menu into a single location. | |
725 * | |
726 * <p>This method must be called before in place activation of the OLE Document. After the Document | |
727 * is activated, the menu bar will not be modified until a subsequent activation. | |
728 * | |
729 * @param fileMenus an array of top level MenuItems to be inserted into the File location of | |
730 * the menubar | |
731 */ | |
732 public void setFileMenus(MenuItem[] fileMenus){ | |
733 fileMenuItems = fileMenus; | |
734 } | |
735 HRESULT SetMenu( HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject ) { | |
736 IOleInPlaceActiveObject inPlaceActiveObject; | |
737 if (objIOleInPlaceActiveObject !is null) | |
738 inPlaceActiveObject = objIOleInPlaceActiveObject; | |
739 | |
740 Menu menubar = getShell().getMenuBar(); | |
741 if (menubar is null || menubar.isDisposed()){ | |
742 return COM.OleSetMenuDescriptor(null, getShell().handle, hwndActiveObject, iOleInPlaceFrame, inPlaceActiveObject); | |
743 } | |
744 | |
745 HWND handle = menubar.getShell().handle; | |
746 | |
747 if (hmenuShared is null && holemenu is null) { | |
748 // re-instate the original menu - this occurs on deactivation | |
749 hmenuShared = menubar.handle; | |
750 } | |
751 if (hmenuShared is null) return COM.E_FAIL; | |
752 | |
753 OS.SetMenu(handle, hmenuShared); | |
754 OS.DrawMenuBar(handle); | |
755 | |
756 return COM.OleSetMenuDescriptor(holemenu, handle, hwndActiveObject, iOleInPlaceFrame, inPlaceActiveObject); | |
757 } | |
758 | |
759 /** | |
760 * | |
761 * Set the menu items that should appear in the Window location when an OLE Document | |
762 * is in-place activated. | |
763 * | |
764 * <p>When an OLE Document is in-place active, the Document provides its own menus but the application | |
765 * is given the opportunity to merge some of its menus into the menubar. The application | |
766 * is allowed to insert its menus in three locations: File (far left), Container(middle) and Window | |
767 * (far right just before Help). The OLE Document retains control of the Edit, Object and Help | |
768 * menu locations. Note that an application can insert more than one menu into a single location. | |
769 * | |
770 * <p>This method must be called before in place activation of the OLE Document. After the Document | |
771 * is activated, the menu bar will not be modified until a subsequent activation. | |
772 * | |
773 * @param windowMenus an array of top level MenuItems to be inserted into the Window location of | |
774 * the menubar | |
775 */ | |
776 public void setWindowMenus(MenuItem[] windowMenus){ | |
777 windowMenuItems = windowMenus; | |
778 } | |
779 private bool translateOleAccelerator(MSG* msg) { | |
780 if (objIOleInPlaceActiveObject is null) return false; | |
781 int result = objIOleInPlaceActiveObject.TranslateAccelerator(msg); | |
782 return (result != COM.S_FALSE && result != COM.E_NOTIMPL); | |
783 } | |
784 | |
785 HRESULT TranslateAccelerator( LPMSG lpmsg, WORD wID ){ | |
786 Menu menubar = getShell().getMenuBar(); | |
787 if (menubar is null || menubar.isDisposed() || !menubar.isEnabled()) return COM.S_FALSE; | |
788 if (wID < 0) return COM.S_FALSE; | |
789 | |
790 Shell shell = menubar.getShell(); | |
791 HWND hwnd = shell.handle; | |
792 HACCEL hAccel = cast(HACCEL)OS.SendMessage(hwnd, OS.WM_APP+1, 0, 0); | |
793 if (hAccel is null) return COM.S_FALSE; | |
794 | |
795 MSG msg = *lpmsg; | |
796 int result = OS.TranslateAccelerator(hwnd, hAccel, &msg); | |
797 return result == 0 ? COM.S_FALSE : COM.S_OK; | |
798 } | |
799 } | |
800 | |
801 // implements IOleInPlaceFrame, IOleInPlaceUIWindow, IOleWindow, IUnknown | |
802 class _IOleInPlaceFrameImpl : IOleInPlaceFrame { | |
803 | |
804 OleFrame parent; | |
805 this(OleFrame p) { parent = p; } | |
806 extern (Windows) : | |
807 // interface of IUnknown | |
808 HRESULT QueryInterface(REFIID riid, void ** ppvObject) { return parent.QueryInterface(riid, ppvObject); } | |
809 ULONG AddRef() { return parent.AddRef(); } | |
810 ULONG Release() { return parent.Release(); } | |
811 | |
812 // interface IOleWindow | |
813 HRESULT GetWindow( HWND * phwnd ) { return parent.GetWindow(phwnd); } | |
814 HRESULT ContextSensitiveHelp( BOOL fEnterMode ){ return COM.S_OK; } | |
815 | |
816 //interface IOleInPlaceUIWindow | |
817 HRESULT GetBorder( LPRECT lprectBorder ) { return parent.GetBorder(lprectBorder); } | |
818 HRESULT RequestBorderSpace( LPCBORDERWIDTHS pborderwidths ){ return COM.S_OK; } | |
819 HRESULT SetBorderSpace( LPCBORDERWIDTHS pborderwidths ) { return parent.SetBorderSpace(pborderwidths); } | |
820 HRESULT SetActiveObject( LPOLEINPLACEACTIVEOBJECT pActiveObject, LPCOLESTR pszObjName ) { | |
821 return parent.SetActiveObject(pActiveObject, pszObjName); | |
822 } | |
823 | |
824 // interface IOleInPlaceFrame : IOleInPlaceUIWindow | |
825 HRESULT InsertMenus( HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths ){ | |
826 return parent.InsertMenus(hmenuShared, lpMenuWidths); | |
827 } | |
828 HRESULT SetMenu( HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject ){ | |
829 return parent.SetMenu(hmenuShared, holemenu, hwndActiveObject); | |
830 } | |
831 HRESULT RemoveMenus( HMENU hmenuShared ) { | |
832 return parent.RemoveMenus(hmenuShared); | |
833 } | |
834 HRESULT SetStatusText( LPCOLESTR pszStatusText ) { return COM.E_NOTIMPL; } | |
835 HRESULT EnableModeless( BOOL fEnable ) { return COM.E_NOTIMPL; } | |
836 HRESULT TranslateAccelerator( LPMSG lpmsg, WORD wID ) { | |
837 return parent.TranslateAccelerator(lpmsg, wID); | |
838 } | |
839 | |
840 } | |
841 |