Mouse Event in Outline View - cocoa

I have a window which contains a split view. One of the "splits" contains an outline view. I have a window controller (which is the file owner for the window's XIB). The window controller is the delegate and data source of the outline view.
When I call the -(void)mouseDown:(NSEvent *)e method in the window controller only the toolbar responds to the method - the outline view does not.
How do I get the mouse events, e.g. the mouseDown, of the outline view?

To get the mouse event of the outline view:
Subclass the outline view.
In Interface Builder (IB) > Library panel > Classes tab select NSOutlineView
Right-click NSOutlineView and select "New Subclass..."
Complete the following pop-up windows selecting "Generate Source Files" and add the fils to your project
Select the NSOutlineView
In Inspector Panel > Identity tab > Class Identity > Class select your new class
Implement your mouse event method
In Xcode > your new subclass of your outline view > the implementation (.m) file type your method e.g.
(void)mouseDown:(NSEvent *)theEvent {
/* CODE YOU WANT EXECUTED WHEN MOUSE IS CLICKED */
NSLog(#"Mouse down occurred");
// call this to get the usual behaviour of your outline
// view in addition to your custom code
[super mouseDown:theEvent];
}
It may be useful to know that one can get mouse events by using [NSEvent modifierFlags]. This is will work not just for the outline view but for views throughout the app. For example, in the window controller (referred to in the question) I could include code like:
if ([NSEvent modifierFlags] == NSAlternateKeyMask) { // if the option key is being pressed
/*SOME CODE*/
}

Related

Changing the selection behaviour of NSCollectionView

In my Mac app I have a NSCollectionView with multi select enabled. In my app being able to select more than one item is the norm, and having to press cmd while clicking to select multiple items is frustrating some users and most don't realise they can do it (I get a lot of feature requests asking for multi select).
So, I want to change the behaviour so that:
when a user clicks a second item, the first item remains selected (without the need for holding cmd)
When a user clicks a selected item, the item is deselected
I've tried overriding setSelected on my own subclass of NSCollectionViewItem like so:
-(void)setSelected:(BOOL)flag
{
[super setSelected:flag];
[(MyView*)[self view] setSelected: flag];
[(MyView*)[self view] setNeedsDisplay:YES];
}
Calling super setSelected is required to make sure the collection view functions correctly, but it also seems to be what is responsible for the default behaviour.
What should I do instead?
You could try intercepting all left-mouse-down events using a local events monitor. Within this block you'd then work out if the click happened on your collection view. If it did, create a new event which mimics the event you intercepted but add in the command key mask if it isn't already present. Then, at the end of the block return your event rather than the one you intercepted. Your collection view will behave as if the user had pressed the command key, even though they haven't!
I had a quick go with this in a very simple demo app and it looks like a promising approach - though I expect you'll have to negotiate a few gotchas along the way.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskFromType(NSLeftMouseDown)
handler:^NSEvent *(NSEvent *originalEvent) {
// Did this left down event occur on your collection view?
// If it did add in the command key
NSEvent *newEvent =
[NSEvent
mouseEventWithType: NSLeftMouseDown
location: originalEvent.locationInWindow
modifierFlags: NSCommandKeyMask // I'm assuming it's not already present
timestamp: originalEvent.timestamp
windowNumber: originalEvent.windowNumber
context: originalEvent.context
eventNumber: originalEvent.eventNumber
clickCount: originalEvent.clickCount
pressure:0];
return newEvent; // or originalEvent if it's nothing to do with your collection view
}];
}
Edit (by question author):
This solution is so heavily based on the original answer that this answer deserves credit (feel free to edit)
You can also intercept the mouse event by subclassing the NSCollectionView class and overriding mousedown like this:
#implementation MyCollectionView
-(void) mouseDown:(NSEvent *)originalEvent {
NSEvent *mouseEventWithCmd =
[NSEvent
mouseEventWithType: originalEvent.type
location: originalEvent.locationInWindow
modifierFlags: NSCommandKeyMask
timestamp: originalEvent.timestamp
windowNumber: originalEvent.windowNumber
context: originalEvent.context
eventNumber: originalEvent.eventNumber
clickCount: originalEvent.clickCount
pressure: originalEvent.pressure];
[super mouseDown: mouseEventWithCmd];
}
#end

What is the statement to go from one ViewController to another ViewController AFTER I have selected an item from my UIPickerView?

I have an initial view controller. It goes to the next view controller which has the “picker wheel” in it. From that screen, if the user selects one of the 4 items in the picker wheel and stops on it. Then press ONE action button to initiate several C code statements.
I need specific help with coding the statement (s) that cause the transition from one view controller to another view controller.
I’m thinking out loud, it should look something like this (but I really don’t know):
‘If row = 0 then go to View controller B.’
‘If row = 1 then go to View controller C’
etc.
Or use some other ‘VERY SIMPLE’ method for transitioning from a ‘selection from a picker wheel to another view controller’.
Basic documentation.
I have 4 viewcontrollers :
First view controller is named - VCa
Second view controller is named - VC1
Third View controller is named - VCb
Forth view controller is named - Vcc
There is nothing but the default 'Storyboard" coding in this VCa (view controller).
The first view controller only has a label named VCa , so we can see which VC this is.
And it has a button named Button A, so I can do a modal segue to the next view controller named VC1.
The second view controller (VC1) only has some basic things.
The picker wheel named pickerView1. The array named Companies with data.
A button to go back to the first view controller VCa.
The button is named B1Back.
A button to go forward to the next view controller named VCb.
The pupose for this button is only for demo. purposes to transition to VCb.
It has nothing to do with coding a solution to allow the picker wheel selection to . transition somehow to the next view controller.
The button is named B1forwardtob.
The same is true for the 3rd button. It just allows this VC (VCa) to transition to . . another view controller named VCc. The button is named B1forwardtoc.
An ACTION button that does nothing, yet. I’m hoping the transition from view controller to view controller code goes here (after the action button). But again I don’t know what I don’t know.
There is nothing but the default 'Storyboard" coding in this VCb (view controller).
The third viewcontroller (VCb) is very simple too. It is there just to go to and then go back to VC1.
There is nothing but the default 'Storyboard" coding in this VCc (view controller).
Same for the forth viewcontroller (VCc). It is there just to go to and then go backto VC1.
It's sort of hard to tell what you're asking, but are you looking for something like this?
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row
inComponent:(NSInteger)component
{
UIViewController *viewControllerToDisplay;
if (row == 0) {
viewControllerToDisplay = [[ViewControllerB alloc] init];
} else if (row == 1) {
viewControllerToDisplay = [[ViewControllerC alloc] init];
}
if (viewControllerToDisplay) {
[self presentViewController:viewControllerToDisplay animated:YES completion:nil];
}
}

Done Bar Button isn't dismissing view controller

Can anybody please tell me why my 'Done' bar button isn't dimissing my view i'm trying to edit the data from the table view?Here is the link of my code:
https://www.dropbox.com/s/gylo67z2n00yc9i/TableView.zip?dl=0
I want to know the reason.I can't figure out what i have missed out.
1.add following method in checkListViewController.
-(IBAction)unwindTocheckListViewController:(UIStoryboardSegue *)segue {
}
select Storyboard and select Add Item View Controller Scene.
Press ctrl on your Mac, select Done button and drag(pressing ctrl) to Exit.
A pop up opens up with above method name. Select it.
Repeat same for Cancel button.
You done!!!
Read upon UnwindToSegue. where your codes goes etc.
Hope this helps.
-(IBAction)unwindTocheckListViewController:(UIStoryboardSegue *)segue
{
SourceViewController *source = [segue sourceViewController];
/*
values of properties declared in .h file of your source ViewController
(called rightly SourceViewController) can be passed to
viewController you coming back to(Unwinding to).
*/
}
here source is your View controller where Done button is, this helps to bring your input from source to destination view controller.

NSTableHeaderView prevents auto layout from resizing scroll view in a split view

The question: Why having a header view prevents scroll view from being resized by auto layout?
I'm trying to embed my custom view in a scroll view, which in turn is enclosed in a split view. I've created the following view hierarchy using Interface Builder in Xcode 4.5 DP 4, but the same problem seems to happen also in Xcode 4.4.
NSWindow
NSView (content view of the window)
NSSplitView
NSView (split view panel)
NSView (split view panel)
NSScrollView
TestView (my custom view)
Now, if TestView provides a NSTableHeaderView (via -headerView) property the split view divider cannot be dragged all the way to bottom (or right) to hide the TestView but stops to the boundary of the initial width or height of the TestView. If the -headerView property returns nil, the divider can be dragged freely.
This can be reproduced every time, just by creating a fresh Cocoa application project, adding the views and running the project. The steps:
Create a new Cocoa Application project
Create TestView class with headerView property which returns a NSTableHeaderView instance.
Edit MainMenu.xib and add a split view
Add custom view and make it TestView
Choose Editor -> Embed in -> Scroll view
Run the project
(No constraints or other Interface Builder menus touched)
TestView.m:
#implementation TestView {
NSTableHeaderView *_header;
}
- (NSTableHeaderView *)headerView
{
if (!_header) {
_header = [[NSTableHeaderView alloc]
initWithFrame:NSMakeRect(0.0, 0.0, 100.0, 17.0)];
}
return _header;
}
#end
Any pointers, what should I do to get the split view divider moving again?
Implement this NSSplitViewProtocol method in a convenient class:
- (BOOL)splitView:(NSSplitView *)splitView shouldAdjustSizeOfSubview:(NSView *)subview {return TRUE;}
Make sure to connect the split view's delegate output the class object.
The split view can now be adjusted to any size.
My solution was to manually remove the autoresizing constraints of the table header:
NSTableHeaderView *headerView = outlineView.headerView;
NSView *headerViewSuperview = headerView.superview;
[headerViewSuperview removeFromSuperview];
headerView.superview.translatesAutoresizingMaskIntoConstraints = NO;
[scrollView addSubview:headerViewSuperview];

NSView custom context menu and keys

i have an NSCollectionView in my application's main window that manages a collection of custom NSView items. Each custom view has a context menu assigned to it. I want to add shortcut keys to some of the items, for example to associate a "delete" key with "remove item from collection" action. I've added key equivalents to context menu items through IB but the question is how do i make the collection items respond to the pressed keys?
I know that i can achieve this by adding this menu to the NSApp's main menu and keep track of the selected item. Is there any other way besides that?
You could add something like this to your NSCollectionView subclass:
- (BOOL)performKeyEquivalent:(NSEvent *)theEvent
{
BOOL rv = NO;
id firstResponder = self.window.firstResponder;
if ([firstResponder isKindOfClass:[NSView class]] && [firstResponder isDescendantOf:self]) {
// Note: performKeyEquivalent: messages come DOWN the view hierarchy, not UP the responder chain.
// Perform the key equivalent
}
if (!rv) {
rv = [super performKeyEquivalent:theEvent];
}
return rv;
}

Resources