Enabling open file menu item in a non-document-based application - objective-c

I would like to enable the grayed out open file menu item within a non-document-based application. Document-based applications automatically give you a nice open file dialog with file extension filters based on plist entries etc... Surely, a simple elegant method exist to re-enable this functionality.
I have...
Added document types to the project properties window
Assigned my controller class as the application delegate
Added the delegate application:openFile: to my controller class

First, make sure your File->Open menu item's selector is connected to the openDocument: action of the First Responder.
Second, make sure you are responding to the action. Take a look at the Responder chain of a non-document application with an NSWindowController object. Any object within your responder chain can respond to the message, but it is best to pick the object which is the most capable and appropriate. Once you have decided which class in your responder chain is the most appropriate to handle the message, add the openDocument: action to it's implementation and write your code to respond to it accordingly.

The key is that something along the menu item's responder chain has to respond to the -openDocument: action. Normally it's the NSDocumentController. I'd take a look at how an empty document-based application sets up that menu item.

Related

Mac application About menu customisation

I am doing my first mac application. I have added my menus and customized. What is my problem is that I need some customizations in the about view. While the about menu clicked, automatically a view will pops up with details Name, Icon, copyright string, version etc. fetched from application plist. About menu in XCode application, which has buttons for Acknowledgment and Licensee Agreement. In chrome About Chrome will create a new tab in the webpage and details are shown. How this possible? Any help is appreciated.
It seems that you can do it in your MainMenu.xib, change to the target-action of the menu item About myApp to your custom action.
See the doc:
Connecting Menu Items Across Nib Files
The items in an OS X application’s menu bar often need to interact
with many different objects, including your application’s documents
and windows. The problem is that many of these objects cannot (or
should not) be accessed directly from the main nib file. The File’s
Owner of the main nib file is always set to an instance of the
NSApplication class. And although you might be able to instantiate a
number of custom objects in your main nib file, doing so is hardly
practical or necessary. In the case of document objects, connecting
directly to a specific document object is not even possible because
the number of document objects can change dynamically and can even be
zero.
Most menu items send action messages to one of the following:
A fixed object that always handles the command
A dynamic object, such as a document or window
Messaging fixed objects is a relatively straightforward process that
is usually best handled through the application delegate. The
application delegate object assists the NSApplication object in
running the application and is one of the few objects that rightfully
belongs in the main nib file. If the menu item refers to an
application-level command, you can implement that command directly in
the application delegate or just have the delegate forward the message
to the appropriate object elsewhere in your application.
If you have a menu item that acts on the contents of the frontmost
window, you need to link the menu item to the First Responder
placeholder object. If the action method associated with the menu item
is specific to one of your objects (and not defined by Cocoa), you
must add that action to the First Responder before creating the
connection.
After creating the connection, you need to implement the action method
in your custom class. That object should also implement the
validateMenuItem: method to enable the menu item at appropriate times.
For more information about how the responder chain handles commands,
see Cocoa Event Handling Guide.

How to make mainMenu send all action to specific NSWindowController?

Short answer is inside the title :)
Explaining: in my MainMenu.xib I have only the Main Menu of the application, that must be same for all NSWindows I open. There is one particular NSWindowController that has, let me say, all answers about when menu item must be enabled (via cases on selector in validateUserInterfaceItem) and what to do with all actions. When NSWindow associated with that NSWindowController is currently focused, there is no problem, but as I focus on another NSWindow all menus are grayed.
I have this flow now: MainMenu is created by reference to it as Main nib into info.plist, then AppDelegate do some init stuff and create MainWinController with MainWindow, at some point MainWinController creates 1+ DetailsWinController with DetailsWindow. AppDelegate manage my custom menu by calling each time functions from MainWinController.
So, how can I force the responder chain to query always that particular NSWindowController (MainWinController)?
You don't give many details to go on, and it isn't clear what you are trying to achieve.
My first reaction is that if you want share Menu items why are you creating multiple windows rather than Views within your MainWindow?
Assuming both your MainWindow and DetailsWindow implement the same selectors you could direct Menu Actions to the First Responder
To add the DetailsWinController in the InterfaceBuilder drag an NSObject from the Object Library, then in Identity Inspector change its class to your DetailsWinController class.
If your Main Menu has different items for the DetailsWindow just connect these to the actions in that instance.
NOTE if you so this you should NOT create the DetailsWinController in code.
If you really want to do this in code you will need to add actions and targets to your menu in code.

Main Menu in different nibs

I have a Cocoa app with a ManMenu.xib, in which the main menu is stored and different other subviews in several xibs handling different tasks of my app. So how do I make my sub-xibs or rather their NSViewControllerController receive actions from the menu?
i have an idea but I don't know if it's the right way: I subclass NSViewController and add some actions like - (IBAction)undo or - (IBAction)redo use instances of it as the files owner. Further I add a pointer to my app delegate pointing at the actual view or rather its controller and the menu sends the action to that pointer.
Wise solution?
You should hook up your menu items to the First Responder. Their action messages will then travel along the responder chain until they reach something that responds to them.
You'll need to make sure your view controller is in the responder chain by setting it as the next responder of something else in the responder chain. I would suggest the window controller.
Speaking of the window controller, you probably should be handling undo there rather than in a view controller—it would be confusing for different views in the same window to have different undo lists. The only exception I can think of would be if the controlled views correspond to document tabs, like in Photoshop or Xcode.

Objective-C NSWindow remove window from key

Hi need a little help, i have a window which is set to always show in the top right corner but it is not set to always key. The window has a few buttons on it and when a button is clicked the window becomes key, but what i want it to do is when a button is clicked i want the window to remove itself from being key.
So ideally the window becomes key when a button is clicked and in the method which the button calls i want to write a statement which will then perform the action of the button and remove the window from key.
However the window is declared under the app delegate and the method linked to the button is declared in a separate header file.
Anyone have any ideas how i can do this, any help would be much appreciated.
Thanks in advance, Sami.
There are a few solutions depending on the architecture of your application.
Send [[NSApp mainWindow] makeKeyWindow], which will make the main window become key.
Your application delegate could have a reference to the main window. In the action method that handles the button click, you could ask the application delegate to make the main window become key. The application delegate would send [mainWindow makeKeyWindow].
Your application delegate could have a reference to the window controller that manages the main window. In the action method that handles the button click, you could ask the application delegate to make the main window become key. The application delegate would ask the main window controller to do that, and the main window controller would send [[self window] makeKeyWindow].
Your application delegate could listen to the NSWindowDidResignKeyNotification notification and keep a reference to the last window that resigned being key. In the action method that handles the button click, you could ask the application delegate to return key status to that previous window. The application delegate would need to ignore NSWindowDidResignKeyNotification notifications when the window is your auxiliary window. This solution is better when there’s no single main window.
If the first solution is not applicable, a) your application delegate could conform to a protocol that declares a method responsible for restoring key status to the proper window, or b) your action method could post a notification informing the application that your action method has completed, and have the application delegate listen to that notification and restore key status to the proper window.
Note that even though I’ve suggested that the application delegate would implement the behaviour of restoring key status, other objects could be responsible for that. This is particularly easier when notifications are used since there’s no need to grab a reference to the object that will restore key status due to the inherent loose coupling provided by notifications.

linking file menu items to buttons

I'm in need of linking some buttons in a 'document based' application to the file menu (bold text, italic text, make text bigger etc.). The issue is that since its a document based application, the MainMenu.xib is a completely different XIB file than the MyDocument.xib, so I can't drag the connections in Interface Builder like I usually would. Does anyone have a workaround? Is there a way to link button actions to a separate XIB files' built in menu functions?
Zach
Generally, you use the First Responder place-holder object.
About the First Responder
"In Interface Builder, the First Responder is a proxy object that represents the first object in your application’s dynamically determined responder chain. Because the responder chain of an application cannot be determined at design time, the First Responder proxy acts as a stand-in target for any action messages that need to be directed at the application’s responder chain. Menu items commonly target the First Responder proxy. For example, the Minimize menu item in the Window menu hides the frontmost window in an application, not just a specific window, and the Copy menu item should copy the current selection, not just the selection of a single control or view. Other objects in your application can target the First Responder as well."
Also see:
Connecting Menu Items Across Nib Files
Also, if you want to create buttons whose actions are basically the same as the Format > Bold, etc. commands, see: Connecting the Font Menu in Interface Builder 3