Applescript and Microsoft Word - macos

I'm working on a applescript to update the content of a document in Microsoft Word. The updating process is quite long (might take more than 5s). So I want to prevent users to change anything during the updating. Do you know whether Microsoft or Applescript a function like that?
In Windows, I can just display a User Form (which is a dialog telling that "we are updating... ") and close that form when it's done. However, I don't know whether I can do the same in Mac (with Applescript alone).

When you say "applescript", I don't know if you mean "plain" applescript or the AppleScriptObjC version. If you mean the latter, then I know ways to do it.
One way I've used during slow processes is to put an overlay view over the whole content view of the window. I make it translucent white to partially obscure the window, and put some kind of message (and maybe a progress indicator) on it. You can just use an NSBox (of the custom type) in IB to make this, and then make a subclass of NSBox to color the view and override mouseDown:. MouseDown:, doesn't need to have any code in it, just by overriding it, you capture any key and mouse events so they don't accumulate on the event queue, and get used by the view below after your overlay goes away. Here's code I've used:
script Overlay
property parent : class "NSBox"
on awakeFromNib()
set overlayColor to current application's NSColor's colorWithCalibratedWhite_alpha_(1,.8)
setFillColor_(overlayColor)
end
on mouseDown_(theEvent)
--log "mouseDown"
end
end script
I have this view as the top most view in the view hierarchy, and set its hidden property to true until I want to show it.

Related

NSDocument with multiple windows -- Appkit dialog sheets jump to the wrong window

It is rarely used, but Apple's NSDocument documentation describes how to set up an NSDocument with multiple windows for a single document. I'm working on a database application that does this. Here is an example of a checkbook database document with two windows open. Each window shows a different view of the document, in this case a spreadsheet like view in the back, and a chart summarizing this data set in the front window. This example shows two windows for one document, but the user can create as many windows per document as they want, each displaying the same underlying document in a different way.
Everything works fine, except that if a system dialog sheet is opened (Save As, Print, Page Setup), most of the time (but not every time) the dialog sheet jumps to another window and attaches to that window instead of the current window, as shown in this movie.
Notice that although the dialog sheet attaches to the window containing the chart, it is correctly printing the content in the spreadsheet window. If I press Print, the correct content will be printed.
For printing, all our code does is call the NSDocument printDocument: method.
[NSApplication sendActionToFirstResponder:#selector(printDocument:)];
Page Setup code is also just calling NSDocument.
[NSApplication sendActionToFirstResponder:#selector(runPageLayout:)];
Our code is not customizing any of these dialog sheets, they are completely stock.
For the Save As command there is no code in our application at all, this appears automatically in the menu when the option key is pressed.
This problem appears in all versions of macOS supported by our application, from 10.9 thru 10.13. Perhaps this is an AppKit bug that is rarely seen because multiple windows with a single document is so rarely used?
This problem doesn't cause a crash, or prevent a user from doing what they want, but it is very visibly incorrect and reduces user confidence in the quality of the program.
For my reference this is #221 in the Panorama X issue tracker.
Implement/override NSDocument property windowForSheet.
The value of this property may be nil, in which case the sender should present an app-modal panel. The NSDocument implementation of this property sets the value to the window of the first window controller, or [NSApp mainWindow] if there are no window controllers or if the first window controller has no window.

How to add a NSColorPicker to the application's main window?

I'm building an application to generate an array of colors based on a color chosen by the user.
The default on Mac OS X for color selection is to open a NSColorPanel containing multiple NSColorPickers. But, as the color selection process is the main interaction the user will have with the app, it'd be better to avoid the extra clicks and panel-popping in favor of a more straightforward way.
So, is there any way to add a NSColorPicker object to a window?
I know this is an older question, but check out NSColorWell. From the docs:
NSColorWell is an NSControl for selecting and displaying a single color value.
Interresting Question.
I strongly doubt it (but would love to be proven wrong). NSColorPickers are not NSControls (nor NSCells) so there's no clean wrapper to insert into a window.
Even if you were to instanciate an NSColorPanel and get a reference to its contentView and copy it (with all that defines the color picking controls) to your own window... there's no obvious way of obtaining the color value. NSColorPickers are plug-ins so you can't forsee the controls of a colorPicker.
The only other way I can see (and that's a stretch) would be to manually load the NSColorPickers plug-ins directly. I don't know how successfull this would be.
File a bug report and request the feature?

How do I not show the paste bar / Clear the clipboard?

I'm writing a Silverlight+XNA game and when the user has something in their clipboard they can see less of the screen. I'd really like to be able to not show this clipbaord but I can't see any way (though it does seem to go away after some amount of time)
I've tried an empty string and Clipboard.SetText(null) but that throws an exception.
Unfortunately, there is no way to either clear the clipboard from code or influence the display of the SIP beyond setting an InputScope.
The best you can do for now is to update your design to allow for the amount of space which the SIP may use. :(
While more complicated, you could create your own text input keys as buttons, and instead of using a textbox, use buttons templated to look like textblocks, with background as you show above, and all... When the user taps the "button" that is a "textblock", you set a flag that says which textblock the keypad buttons send their numbers to.
Or, if the only spot you are sending inputs to (as it appears now that I look at your UI again), there is no need for the button template as the input space, or the flag. Just create buttons for user to tap for input, and send that input to the textblock that appears to be where your answer is. You could make the buttons whatever size you want, that way, as well, so you control how much of the screen is visible. Another thing you could do is make the buttons semi-transparent, so you could have even more background image showing.
Another thought - send the buttons all to the same event handler (except the backspace button), and have the code for that event handler look like this:
{
Button btn = sender as Button;
textblock.Text += btn.Content;
}

Get Context Menu text of specific TaskBar button

I've got some code that grabs the TaskBar buttons and their text from the windows TaskBar using User32.SendMessage with the TB_GETBUTTON message to retrieve a TBBUTTON structure (Win32 API via C# P/Invokes). But I'm trying to figure out how to then, once I have the handle to the button, grab the associated context menu text. There is some status information on there for a specific application that I would like to retrieve. The button text gets me some of it, but I need to the context menu text to complete it.
Any ideas?
This is not completely clear... Context menus don't have text, as such - they have menu items, each one of which will have text. By "context menu text", do you mean the text of the menu items in the taskbar button's popup/context menu? For example, "Restore", "Minimize" etc in the screenshot below?
If so, I suspect you're going about this the wrong way:
This menu doesn't belong to the button, but is the system menu of the window represented by the taskbar button. If the button has a context menu, this is probably for a grouped collection of windows, not one specific window (or even windows for one process.)
Making judgements based on the context menu of a window sounds like a dodgy approach to me, especially based on text since that will change depending on where in the world your user is located. Applications can also change the contents of this menu so there's no guarantee it will contain something you expect to be there. It would be better to check the window style, if it's minimized, etc, to find out the information that also affects the contents of the menu.
I'm going to answer this based on what your needs seem to be from the question, not what you've directly asked, since (a) it's not possible as asked and (b) I think you're trying to do something else. (As a general guideline, in a question it's good to state why you're trying to do something - and even maybe ask about that, ie 'how do I achieve X' - in case there's a better method than the one you're using. Here, X is probably 'find out information about this window' not 'get the text of the context menu', because that's probably only one possible method to get to X.) Also I think extracting data from the internals of a third-party application like Explorer (the taskbar is an Explorer window) is fragile and prone to break in future versions of Windows.
The system menu or window information (whichever one) belongs to application windows. Unless taskbar buttons are grouped (and then it's the subitems) one taskbar button corresponds to one specific window in the system. So what you want to do is find these windows. You do this by:
Using the EnumWindows function
Then for each window that is passed to the callback, checking the extended window style using GetWindowLong with GWL_EXSTYLE to see if the WS_EX_APPWINDOW bit is set
In addition, sometimes other windows are shown: these heuristics should help.
Each one of these windows is a window that should appear on the taskbar, Alt-Tab dialog, etc.
You say you're getting the text of the taskbar button - this is probably the window caption of the window, and GetWindowText is the canonical (read: probably a lot more reliable) way to get the caption of a window belonging to another process.
If you really want the popup menu, then:
Use GetSystemMenu to retrieve the handle for the system menu for the window. Applications can customise this, so if your app is doing this (and that's why you want the popup menu) ensure you pass false to the bRevert parameter
You can then get the number of menu items using GetMenuItemCount and for each one call GetMenuItemInfo to get info about each menu item. Pass true to the fByPosition parameter to indicate you're accessing the menus by position (since you know the count, you're getting item 0, 1, 2... count-1).
This fills a MENUITEMINFO structure, which (I think, I haven't ever had to code this so I haven't tested) will tell you the text associated with an item via the dwTypeData field "if the MIIM_STRING flag is set in the fMask member".
If you really want information about the window status, you can get this information using methods like IsIconic to see if it's minimized, GetWindowLong again to get other information, etc. I'd suggest you ask another SO question about how to get whatever specific information about a window for details.
Hope that helps!

What's a good way to bind from a shared utility window and the frontmost document window?

I have an application which allows for multiple NSDocuments to be open. In this application is a single utility window that contains some functionality that I want to apply to the frontmost document.
I am trying to use bindings here, so the trick is how to cleanly bind the user interface of the utility window to the frontmost document. The goal is that then switching the frontmost document window will update the view in the utility window; controls that are bound to properties of the frontmost document's model would be updated appropriately when state changes in the document's model, etc.
For sending actions from such a window, it's easy to just use first responder; the document object can intercept actions via the responder chain. But I want more than this, and of course you can't bind to the first responder.
A few ideas that I have:
put an object controller in my nib for the shared window. When a document window changes frontmost status, change the content of that binding. A disadvantage of this is that if I were to have another kind of utility window, I'd have to remember to hook up the bindings from the document window to that utility window too!
Make an accessor in the application delegate that gets the frontmost document window by traversing the window list. My utility window would just bind through the application delegate's method. A disadvantage here is that it's not KVO compliant
Have a getter and setter in the application delegate to determine (and perhaps set to be KVO-compliant? would that make sense?) the frontmost document. Perhaps use window notifications set an ivar to the appropriate value when a window loses main status. Update: I'm using this for now, and it actually seems pretty clean. I set the value from the windowDidBecomeMain notification of my doc window and clear it (if it's the current value) in windowWillClose. Unless there is any major objection, this is probably the approach I'll use.
One idea was to bind to mainWindow.windowController.document ... this comes close, except that when my shared window becomes main, then this binding goes away. So really I need to find the frontmost document window's controller (and of the right class).
None of these seem quite right. Is there a better way to do this that I'm missing?
I’ve always bound through Shared Application, mainWindow.document, which works fine. if you have windows w/o documents, you may want to add a mainYourKindOfWindow key that is implemented by watching mainWindow and updating the value based on some filter criteria.
Leopard's TextEdit does this for its inspector. Check it out in file:///Developer/Examples/AppKit/TextEdit.
put an object controller in my nib for the shared window. When a document window changes frontmost status, change the content of that binding.
That makes the most sense to me. You'd change the content to the document instance ([NSDocumentController currentDocument]).
A disadvantage of this is that if I were to have another kind of utility window, I'd have to remember to hook up the bindings from the document window to that utility window too!
Huh? I don't understand this.
Leopard's TextEdit does this for its inspector. Check it out in >file:///Developer/Examples/AppKit/TextEdit.
In TextEdit, inspector values are bound via an intermediate object controller. The controller content object is bound to the shared application mainWindow.
You may bind the content to mainWindow.firstResponder and uncheck "Raises for not applicable keys".
Use the key window, not the main window. KVO might not be supported for NSApplication's keyWindow property, but you can still use NSNotifications if it doesn't work. The reason for this is that NSDocumentController's currentDocument uses the keyWindow, so it better represents the built in functionality. Also, panels can be set to avoid becoming key window.

Resources