foreach delegate in QML TreeView - qml

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.

Related

Should we use Interface Builder in need of dynamically created UI?

I'm currently thinking of project, which is basically interpreting data from many abstract data sources.
So the communication within application is like this
[UI] <-> [Controller / Delegate] <-> [Subclass of Abstract Data Source]
which is basically the MVC pattern. What is my problem, that each [Subclass of Abstract Data Source] can use only limited amount of [UI], so the flow is basically this:
Create instance of Data Source (DS)
Get list of possible UI's from DS
Create UI chooser and instantiate preset UI
Let DS modify UI
Fill UI from DS by predefined handler method
Example UI's are NSTableView, NSOutlineView, NSCollectionView, etc.
So I basically need to change column names, order, style of controls, ... without possibility of having unique NSWindow designed for each Data Source
Now the question:
If I need dynamic UI creation and custom data handling logic (no bindings to Core Data, or so), should I (and is it even possible to) use InterfaceBuilder or should I implement all view logic programatically?
Use whichever you favor. Any variations/dynamic areas can be represented/handled by the controllers. In a way, that means that I recommend moving the dynamic portions to code to controllers -- but you can still use XIBs for common high level design, if you choose.
Therefore, when a view is not suitable for a singular data representation and is used for multiple, the implementation/variations can be moved to the controller domain. When an implementation/definition applies to all, then you can define that in the XIB or in the program -- wherever you prefer to put it. In that case, you can use XIBs (or code) for invariant (skeletal) views.

Is there a standard pattern for managing object state in different Cocoa views and menus?

In a Cocoa application is there a standard pattern for keeping UI and other element states in sync? For example I have the main Menu managed by one class and a toolbar managed by another. Some of the menu items must reflect current selections in the toolbar and vice versa. I was going to handle this by having the selector triggered by the menu items and toolbar items fire off a Notification. The controlling classes would subscribe to these an update the UI to match the selection. Is this a good way to do this or am I missing some other natural way to do this in Cocoa?
For the specific case of whether an item should be enabled or disabled, that should be left to the target (or the implicit target if the target is the first responder). It should use User Interface Validation for that.
Bindings is another good technique. The state which governs the UI should either be in the model or the controller, and the UI should bind to it. (If the UI is to bind to the model, it should be through the controller.) That way, you only have to make sure the state is up-to-date and consistent and everything else happens automatically.
But then the technique you describe is a good third option. The model should provide notifications (through NSNotifications or a delegate) to the controller layer when it has changed. The controller layer watches those and has intimate knowledge about what effect state changes should have on the UI and explicitly configures the UI to conform.

Object Assignment vs Object Creation

I have always found it hard to decide when I should create a single object and pass it to every object that needs it, or create a new object for every object which needs that item.
Some cases are so obvious, like entity objects which are readonly after allocation and instantiation. You can pass the same object anywhere and not worry about another object modifying it, which ruins the other objects holding a reference to it.
My problem mainly lies with objects that represent themselves to the user. Objects like CCSprite in cocos2d, NSMenuItem in Cocoa (AppKit) and other objects with visual representation..
Examples:
In cocoa, i know that I have to create an NSMenu for each NSPopUpButton, so that the selection for a specific button does not affect the rest. But, what about the NSMenuItems contained within? Can I create a single set and pass them to all the menus? What are your grounds, or how did you come to such a conclusion?
Other example:
In cocos2d, and almost all GUI based applications, you can pass to a button two images/sprites/...etc. such that one is for the normal state, and the other is for the selected (highlighted, pressed, clicked) state. Can I pass the same image/sprite/...etc. to both, making them point to the same object?
I hope this is not an implementation related issue (that it ultimately depends on the implementation) , since I face it in a lot of my programming projects, in cocoa, cocos2d, Java ... etc.
PS: I need help with choosing the proper tags
I suggest creating new instances unless doing this causes a performance problem. Sharing an NSMenuItem instance among many NSMenu makes it more difficulty to maintain control over that instance, which increases the risk of errors.

Popup window similar to Xcode's code completion?

I would like to build something similar to the code-completion feature in Xcode 4. (The visual style and behavior, not the data structure type work required for code completion).
As the user is typing, a pop-up window presents other word choices that can be selected.
The Feature in action:
I'm not exactly sure where to start. I am mainly concerned with the visual appearance of the window and how I should populate the list with a given set of words. Later I will get into making the window follow the cursor around the screen and etc.
I am mainly looking for an overview of how to display such data in a "window", and how to cusomize the appearance of the thing so it looks like a nice little informational popup rather than a full-on OS X window.
Just add a subview to your current view that happens to be a tableview. Programmatically cause it to be visible on an event (such as mouseDown), and adjust it's position based on where you want it. You will need to instantiate the proper delegate/datasource methods, but it should be pretty straight forward. You will also need a source for the words you want to use in your autocomplete, and put them in an array or something for your tableview datasource to go through.
Like I said, it's not terribly hard, provided you are comfortable using tableviews and adding views to your existing view. If this doesn't explain enough, leave a comment and I can flesh this comment out more.
Add a (completions) subview to your view and set its visible property to NO. Create a separate AutoComplete object that includes the subview as a property and fills it with potential completions. Your controller can respond to key pressed (key typed) events and give the last word (substring the text from the end to the 1st preceding blank) to the AutoComplete on each event. The basic logic in AutoComplete could be something like:
Given an AutoComplete with a list of known words "dog, spaghetti, minute, horse, spare, speed"
When asked to complete a fragment "sp"
Then the following words should be offered as potential completions, "spaghetti, spare, speed"
Which would imply that you need to instantiate it with a list of words (this could be done in the init of your controller), and create a method "-(NSArray*) completeFragment:(NSString*)fragment;". You could drop this into an OCUnit test case and iterate over your implementation of autocomplete until you get it right. You would then write a method that takes the completions from AutoComplete and lists them in the subview. Even better you might create currentWord and potentialCompletions properties in AutoComplete that gets updated as you send it "newFragment:(NSString*)fragment;" messages. Throw that into OCUnit and work it out then use that potentialCompletions property to drive updated of a the subview (which is probably best modeled as a custom tableView).

Creating a window from a menu item

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.)