Creating a window from a menu item - objective-c

I would like three menu items on the menubar with the keyboard shortcuts cmd-1, cmd-2, cmd-3. This I know how to do.
Each menu item would open up a different window (win1, win2, win3).
I want it so that only one instance of each window is permitted to be open at any one time (i.e. only one win1, one win2, etc).
How is this best approached?

If the windows in question are in the MainMenu.nib it's simple; attach the action to -makeKeyAndOrderFront: on each window.
If, on the other hand, they are not in MainMenu.nib, as is more likely the case if your application is structured in a sane fashion; things get a little more complicated. Long story short; you need to attach the menu item actions to appropriate methods on some manner of controller object (most likely your application delegate, although any controller that "sees" all the required nibs will do); and then have the controller in question send a similar message to its window.
This is generally a sensible approach, as you can have smaller controller objects attached to your windows that also act, if appropriate, as data sources for the various views in the windows in question.
It also allows for lazy loading of the windows, which is, at last count, a Good Thing™.
If this is some manner of document-oriented (not necessarily document-based) application, and the windows display some attribute of the currently selected "document" or piece of data; subclassing NSWindowController and loading the window controllers in your MainMenu.nib is probably a good place to start.
Note: If the objects responsible for controlling the windows live in the responder chain, they don't even need to be referenced in MainMenu.nib; you can just attach the appropriately-named IBActions (e.g. openDetailsWindow: or the like) used to open the windows to the virtual FirstResponder object. (Simply add the selectors to its list of known methods, and you're golden.)
Reedit: To make the window not appear in the windows menu, you can call [window setExcludedFromWindowsMenu:YES].
To check/uncheck the menu item is a bit tricker, as it requires your window controller actually knowing about the menu item; but as long as this is the case, it's quite simple, again; call -setState:, with the relevant state names (NSOffState, NSOnState), for example from the delegate methods called when the window is shown/closed. (This could, again, be encapsulated "inside" the application delegate; if you for whatever reason don't want your MainMenu.nib to contain the window controllers.)

Related

foreach delegate in QML TreeView

Similar to Foreach delegate in QML view I'm having trouble finding a list of current delegates in a QML TreeView.
However, the actual problem I'm trying to solve is this: I have a C++ class that inherits from QAbstractItemModel that provides several different roles. One of them is Qt::CheckStateRole which functions as an indicator for whether a particular item in the TreeView is selected for display elsewhere in the GUI.
Using Edit QStandardItemModel via TableView with Custom Delegate as a general guide (but adapted to TreeView, hint: use mapToItem() instead of mapFromGlobal()) I'm able to service user clicks to the checkbox that appears in that particular column (role). However, I need to programmatically alter the state of other checkboxes as well (different than the one that got clicked).
Strangely, dataChanged() signals (got them working for all of the other roles) do not affect the state of the checkbox (this is Qt 5.12.2, Ubuntu 20.04). I know what state I want to impose on the checkbox, and of course I should only need to do that for the currently existing delegates. However, it seems like it ought to be extremely convoluted -- the way there's a separate delegate for each role -- on top of the hierarchal nature of the data.
So, is there a way to access the set of currently existing delegates for a particular role that is operative in a QML TreeView?
Instead of trying to iterate over delegates I found that instead I could just create a Connections component within the delegate that connects a global youNeedToUpdateYourValue() signal to the delegate, which reassesses the current state of the checkbox. As the connection will disappear when the delegate is pruned, this seems to be a very elegant way to impose an action upon all existing delegates.

Global Access to Class instance - Optimal design approach?

OK, here is my situation and I'm really not sure on which design approach to use. So, I'd be glad to read some input on my particular case...
The scenario :
I've got a tab-based application
Initially we create an instance of NSWindowController (e.g. MyDocumentManager) which takes care of the tab creation/manipulation
Each tab contains (= is attached to) an instance of MyDocument
Now, I'm about to implement the menu actions.
For each menu there is a separate Menu Controller (actually a subclass of NSObject grouping all relevant functions), e.g. MyFileMenuController
File Menu's actions are linked to actions in a MyFileMenuController object, via Interface Builder
The question :
How is it possible that MyFileMenuController "knows" about MyDocumentManager (created in my AppDelegate.m), so that we can access current document details and perform all relevant actions? Any ideas? Which approach is preferable?
My ideas :
Passing object from class to class (not sounding that great)
Singletons (although I've honestly never used them, and do not know whether/how it could be my particular case)
Notifications & Notification Listeners
(Looking at it from the opposite side, though not sure) Delegate methods
OK (not sure if that's the best way to do it), but this is what I decided to do :
[[[NSApplication sharedApplication] delegate] MyDocumentManager]
So, as long as an object is part of my AppDelegate, this way I can access it from anywhere.
I would make an initial UIViewController linked to appDelegate.rootViewController.
In this new view controller (just call it "mainViewController") I would put my tabBar and the menuController.
I understand your interface is similar to facebook with a leftBarbutton which makes horizontal scroll and discover the menu. So in the selector for this leftBarButton I would call a method like:
- (void)discoverMenuForDocument:(MyDocument*)document {
// Set menu configuration for specific document
// Make animation to discover menu
}
Where document could be something like:
self.selectedViewController (<-- You cand make this in several ways depending on your code...)
Realize that (MyDocument*) is not an object but just a reference, so in my opinion there isn't any problem doing this.
Good luck!

Xcode: How should I organize my multi-window user-interface project?

Note: Using Objective-C, Cocoa, and Xcode.
At first, I did all my programming in the AppDelegate and had all user-interface elements such as windows in the same '.xib' (nib file). This worked great at first, but then as my application became more advanced with more "features", everything became extremely cluttered and the file too long for my liking.
I'm now trying to progress. I'm wondering how I should (properly and efficiently) go about having a multi-window project? My plan was to have a .xib file for every window, and put only necessary things in the AppDelegate. I would then have a core file for all necessary calculations and such to be used in my application and a Main Controller file to control outlets and actions from all windows in my app. However, I'm quite new to Objective-C and have been running into SO many issues and problems trying to set up Window Controllers and stuff.
Am I even on the right path? Am I doing it wrong? How should I manage a multi-window user-interface application in Xcode?
Thanks in advance.
For multiple windows, I think it's best to use an NSWindowController for each, with it's associated xib file for the window. I'm not sure what you mean by "a Main Controller file to control outlets and actions from all windows" -- each window controller will have outlets to its own window. You can't connect outlets across multiple xib files. You can have one window in the MainMenu.xib file that you get by default when you create a project, and use that to launch other windows perhaps, but it's hard to offer any more specific advice without knowing how all your windows relate to each other.
After Edit:
If you want to open another window, have a menu item's action method be something like this:
self.controller = [[WindowController alloc] initWithWindowNibName:#"WindowController"];
[self.controller showWindow:nil];
Here, I have a property called controller to keep a strong reference to the new window controller. If you don't do that, the controller will be deallocated, so if you have multiple windows, that you want to show at the same time, you'll need properties to hold on to them.

When should I extend NSDocument and when should I extend NSWindowController?

I've an application that holds a main window with a list of items, and from that window an undetermined number of windows can be opened. Each of those windows can hold several instances of a model object, with those instances listed in a drawer.
I started my project by making the (main window) list of items extend NSDocument and each other window extend NSWindowController. But functionally the main window is used once every blue moon, despite being the window that should pop-up when the users start the application, and the windows that extend NSWindowController are the ones used extensively by the user and also the ones that end up holding my "document".
Because of that I'm now having problems implementing methods such as New, Open and Save - I find myself writing a lot of code the manuals say should be implemented by the super class.
Because I'm at a cross-roads I wonder how I should implement my application. Should I re-factor my main window into a class that extends NSWindowController and launch it from the xib that holds main menu, or should I keep things the way they are and just override newDocument, openDocument, etc in order to get the desired functionality?
Just to help with the mental image, my application works like MSN - I've a main list with several items on it (the contact list on MSN), when I double click on an item I open a window (you open a chat to a user). My app goes one step further by keeping several instances of a model object for each "chat" window and each instance will be accessible by a table in a drawer.
You would subclass NSDocument in order to handle a type of document. It may be a general type, such as any image, or a specific type, such as PDF, but you need to create an NSDocument subclass to handle the type, since NSDocument itself doesn't know how.
I'm not sure why people subclass NSWindowController. It seems to work well enough as it is.
I've an application that holds a main window with a list of items, and from that window an undetermined number of windows can be opened. Each of those windows can hold several instances of a model object, with those instances listed in a drawer.
I started my project by making the (main window) list of items extend NSDocument and each other window extend NSWindowController.
That's wrong. If anything, your secondary windows are document windows. The primary window is not.
Make a new controller for the primary window. When the user opens an item in that window, tell the document controller to open the relevant file. You probably don't need to subclass NSWindowController for this.
If the items don't correspond to files, then your application is not document-based, and you should not pretend it is: Don't use NSDocument or NSDocumentController at all in this case.

How to retain an window without holding a pointer to it in garbage collected Obj-C?

I am currently working through the famous "Cocoa Programming for OSX" by Aaron Hillegaas.
In Chapter 12 he wants me to create an about window using
[BOOL] successful = [NSBundle loadNibNamed:#"About" owner:self];
which, by itself, works perfectly well. However, I am using the garbage collector and since I do not retain a pointer to that about window, it is garbage collected and thus disappears after a second or two. It works perfectly well if garbage collection is disabled.
Is there a way to create a window without holding a pointer to it and without having it eaten by the garbage collector?
You can retain the window with CFRetain, or use NSGarbageCollector's disableCollectorForPointer:. However, you can easily introduce a memory leak. Make sure whichever action you use to close the window also releases the window.
If the sender passed to the close action inherits from NSView, it will have a window property that you can use to get a pointer to the window.
However, this is not how Cocoa is designed to work. In Chapter 12 of Hillegaas' book, he has this to say:
When sent showWindow: for the first time, the NSWindowController automatically loads the nib file and moves the window on screen and to the front. The nib file is loaded only once. When the user closes the [window], it is moved off screen but is not deallocated. The next time the user asks for the [window], it is simply moved on screen.
If you deallocate the About window, your app will either crash or appear not to respond the second time someone opens it.
Edit: An alternative (but one that doesn't give you practice in loading nibs) is to add the About window an an NSWindowController to the main nib (make sure you uncheck the About window's "Visible At Launch" attribute). This makes a mess of Main.nib, but can be done entirely in Interface Builder. Connect:
the About controller's window outlet to the About window
the About controller's showWindow: action to the About menu item
if you've your own close button in the About window, connect it to the window's performClose: action.
As for how advisable this course is, Apple has this to say:
A very simple application might be able to store all of its user interface components in a single nib file, but for most applications, it is better to distribute components across multiple nib files. Creating smaller nib files lets you load only those portions of your interface that you need immediately. Smaller nib files results in better performance for your application. They also make it easier to debug any problems you might encounter, since there are fewer places to look for problems.