Which one of the two NSTextViews has been edited? doCommandBySelector is always returns the first one - objective-c

I'm desperate to find the answer, so I opened TextLayoutDemo sample project from Apple. The point is that: I have two NSTextViews for column view. Everything works fine, text I enter is successfully laying out in those two text views via single layout manager:
NSLayoutManager *twoColumnLayoutManager = [[NSLayoutManager alloc] init];
NSTextContainer *firstColumnTextContainer = [[NSTextContainer alloc] init];
NSTextContainer *secondColumnTextContainer = [[NSTextContainer alloc] init];
NSTextView *firstColumnTextView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, 240, 360) textContainer:firstColumnTextContainer];
firstColumnTextView.delegate = self;
NSTextView *secondColumnTextView = [[NSTextView alloc] initWithFrame:NSMakeRect(240, 0, 240, 360) textContainer:secondColumnTextContainer];
secondColumnTextView.delegate = self;
[firstColumnTextContainer setContainerSize:NSMakeSize(240, 360)];
[secondColumnTextContainer setContainerSize:NSMakeSize(240, 360)];
[twoColumnLayoutManager addTextContainer:firstColumnTextContainer];
[twoColumnLayoutManager addTextContainer:secondColumnTextContainer];
[twoColumnLayoutManager replaceTextStorage:[firstTextView textStorage]];
[[secondWindow contentView] addSubview:firstColumnTextView];
[[secondWindow contentView] addSubview:secondColumnTextView];
But my goal is to get to know in which one text views the user edits a text. If it's the left one, I need to call one method, but if it's the right one, I want to call another method. And it seems impossible to recognize the correct text view, because delegate always get notified by the first text view.
- (BOOL) textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector {
NSLog(#"edit: %#", textView);
return NO;
}
This method is always prints the first text view, even if I change text in the second one. And I see it's going according to docs, where Apple says there always will be just the first NSTextView in series.
But how can I solve my problem then?

Just tell me, if this solution is the one I am looking for. Because, in fact, it works just fine. The one thing I don't understand is why Cocoa text system is so tricky where it is not necessary?
- (void)textStorageDidProcessEditing:(NSNotification *)aNotification {
// that's the active text view
NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
NSTextView *activeTextView = (NSTextView *)[keyWindow firstResponder];
NSLog(#"%p", activeTextView);
}
UPDATE: this works only if user clicked the mouse button. Arrow keys do not update window's first responder:(

Related

Animated SearchField doesn't keep its new position

I'm animating the location of an NSSearchField to move across the window. The animation itself works fine but sometimes the search field does not keep its new location. I've found out that this has something to do with AutoLayout (has been enabled for the XIB) and on iOS there's a function called layoutIfNeeded for UIViews.
Is there something similar to OS X applications? I've tried this:
[self.searchField updateConstraints];
[self.searchField layout];
Which seems to work... almost.
During user navigation the search field switches between hidden and visible state. When the user switches between these states everything is fine (the search field stays at its new position).
But when the user sets the focus on the search field (by just clicking on it) and navigates forward and back the search field appears on its old position.
Does anybody have a clue why this may happen?
Update
I have just added an observer for the frame property of the search field in order to see when the frame changes again. This shows exactly what I've described above: when the user switches between views everything is fine. But if the user puts the focus on the search field and switches the views the frame is being set back to its original value.
I also tried to implement the animationDidEnd: notification and set the frame explicitly to its new value. But this doesn't work as well.
Update 2
This is the code I'm using to animate the search field:
NSMutableArray *array = [[NSMutableArray alloc] init];
// Set the properties for the search field animation
NSMutableDictionary *dictSearchFieldAnimation = [[NSMutableDictionary alloc] init];
dictSearchFieldAnimation[NSViewAnimationTargetKey] = self.searchField;
dictSearchFieldAnimation[NSViewAnimationStartFrameKey] = [NSValue valueWithRect:self.searchField.frame];
NSRect destinationFrame = self.searchField.frame;
destinationFrame.origin.y = self.searchResultView.frame.size.height + 15;
dictSearchFieldAnimation[NSViewAnimationEndFrameKey] = [NSValue valueWithRect:destinationFrame];
[array addObject:dictSearchFieldAnimation];
// Perform the animation
NSViewAnimation *animation = [[NSViewAnimation alloc] initWithViewAnimations:array];
animation.delegate = self;
[animation setDuration:0.3];
[animation setAnimationCurve:NSAnimationEaseInOut];
[animation setAnimationBlockingMode:NSAnimationBlocking];
[animation startAnimation];

Editable transparent NSTextField text appears with white highlight

I am trying to create editable transparent NSTextField in a semi transparent window:
What I have noticed is that whenever the field is editable there is a white "selection like" background drawn even though the element is not actually selected.
Additional observable symptoms:
This highlight is not present when the field is set as non-editable.
If there are multiple fields only the first one has the highlight.
The highlight is not present if the text is not set programmatically
Following code was used to generate the field:
f = [[NSTextField alloc] initWithFrame:b2];
f.backgroundColor = [NSColor clearColor];
f.drawsBackground = YES;
f.bordered = NO;
f.bezeled = NO;
f.focusRingType = NSFocusRingTypeNone;
f.textColor = [NSColor whiteColor];
f.editable = YES;
f.selectable = YES;
f.backgroundColor = [NSColor clearColor];
f.allowsEditingTextAttributes = YES;
f.stringValue = #"Foo";
[self.contentView addSubview:f];
Additional observations (potentially a separate problem):
When field is not the first field on the screen and the initial text is set programmatically and removed by editing the field there is a shadow of the text:
I can't seem to find any documentation on this I wonder if any of you have had this happen and potentially have a solution or a pointer to docs I might have not stumbled upon.
part 1: removing highlight
there are two options here depending on the behavior you are looking for
option 1 - nil first responder
TextField is not first responder
No highlighted text
No Cursor at the end of text
Assuming you are using an NSWindow, set the first responder to nil after calling makeKeyAndOrderFront
[self.window makeKeyAndOrderFront:self];
[self.window makeFirstResponder:nil];
It appears as though makeKeyAndOrderToFront: looks for the first NSResponder in the window willing to accept first responder. Then becomeFirstResponder is called on that responder; leading to option 2
option 2 - override becomeFirstResponder
TextField is first responder
No highlighted text
Cursor appears at the trailing edge of text
Subclass NSTextfield and override it's becomeFirstResponder method
#implementation BPTextField
- (BOOL)becomeFirstResponder {
BOOL isResponder = [super becomeFirstResponder];
//Get Field editor, set selected range
NSText* fieldEditor = [[self window] fieldEditor:YES forObject:self];
[fieldEditor setSelectedRange:NSMakeRange(fieldEditor.string.length ,0)];
return isResponder;
}
#end
I prefer this option from a usability perspective
part 2: removing shadow
option 1 - add a solid background color
I'm not clear ; ) on why this is the case, but if you add a solid background color, the text will update.
option 2 - override textDidChange
override textDidChange:notification in your textfield
#implementation BPTextField
- (void)textDidChange:(NSNotification *)notification {
[super textDidChange:notification];
[self setNeedsDisplay:YES];
}
#end
Final notes
You'll notice that the text looks bad, or rigid. Adding a background color to the textfield, or to the superview's layer will fix this.
This is an answer to part 2 of the question.
The shadow artifact is from rendering window's shadow which is not updated when the text in the NSTextField changes.
If the window's hasShadow method returns "NO" the text's shadow will not create shadow for the text either.

iOS7: UISearchBar scope buttons misaligned

Ok, I bumped into another iOS7 weirdness:
I am adding a UISearchdisplayController + UISearchBar with some scope buttons programmatically to a table view.
Now, if I select the search field, the scope buttons are too large. If I switch to landscape, things get even worse, the buttons are badly misaligned.
Here is my code (just a few lines added to the standard 'Master Detail Application"-template):
- (void)viewDidLoad
{
// ...
UISearchBar *searchBar = [[UISearchBar alloc] init];
searchBar.showsScopeBar = YES;
searchBar.scopeButtonTitles = #[#"one", #"two"];
self.tableView.tableHeaderView = searchBar;
self.mySearchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
// ... add delegate, datasource, irrelevant for this example
}
This is what it looks like:
Addition:
By the way, the misalignment also appears if I hook things up with IB instead. The button width is correct though.
Does anyone have an idea for a workaround?
Change the initializer you have used to instantiate the search bar with something like this UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];. Seems to be a problem related with the designated initializer for the search bar.

Mac OS X: How to force a Field Editor to scroll instead of wrap text?

I have a Cocoa, Document-based Mac OS X application.
One feature that I have in my app is a list of text items which can be double-clicked to edit. When the user double-clicks one of the text items, I place the current window's fieldEditor text field over the clicked text item to allow editing.
Everything is working fine except for one problem. I cannot figure out how to make the fieldEditor text field clip + scroll rather than wrap its text. Here's what it currently looks like:
See how the text is wrapping to a second line? I don't want that. I'd like it to remain one line which scrolls (and appears clipped).
Here's an example of it working correctly on a list item which has less text:
Here's what I'm trying in my view controller:
NSWindow *win = [listItemView window];
NSText *fieldEditor = [win fieldEditor:YES forObject:listItemView];
[fieldEditor setFont:[TDListItemView titleFont]];
[fieldEditor setAlignment:NSLeftTextAlignment];
[fieldEditor setDrawsBackground:YES];
[fieldEditor setBackgroundColor:[NSColor whiteColor]];
[fieldEditor setString:str];
[fieldEditor setDelegate:self];
[fieldEditor selectAll:nil];
if ([fieldEditor isKindOfClass:[NSTextView class]]) {
NSTextView *tv = (NSTextView *)fieldEditor;
NSMutableParagraphStyle *style = [[[tv defaultParagraphStyle] mutableCopy] autorelease];
[style setLineBreakMode:NSLineBreakByClipping];
[tv setDefaultParagraphStyle:style];
}
CGRect r = [self fieldEditorRectForBounds:[listItemView bounds] index:idx]; // height here is 10.0
[fieldEditor setFrame:r];
[fieldEditor setNeedsDisplay:YES];
[[self view] addSubview:fieldEditor];
[win makeFirstResponder:fieldEditor];
Notice that part in the middle: I check to see if this fieldEditor is an instance of NSTextView in order to call the setDefaultParagraphStyle: method on it. This is my attempt to get the fieldEditor to clip its text -- via the NSLineBreakByClipping value. It's not having any effect. And I'm not even sure this is what I should be doing to get the fieldEditor to scroll on one line.
Also note that the height of the rect which I compute in my -fieldEditorRectForBounds:index: method is correct, and is providing a rect which is correctly sized for a single line of text (14.0 pixels in this case).
What am I missing to make the fieldEditor display a single line of scrolled/clipped text?
I've also tried adding these lines in the middle section:
[[tv textContainer] setHeightTracksTextView:YES];
[[tv textContainer] setWidthTracksTextView:YES];
This has the desired effect of resizing the visible portion of the fieldEditor which is good. But the bad news is that it doesn't change the fact that the text is still wrapped, rather than clipped + scrolled. :(
This seems related to this constant:
NSStringDrawingUsesLineFragmentOrigin
which can be used in the options: argument of:
-[NSAttributedString drawWithRect:options:attributes:]
but in my case, I'm working from a NSText field editor, not an NSAttributedString. I can't figure out how to do this sort of thing with an NSText field editor.
Hmmm ... NSTextView relies on an NSScrollView entirely for its scrolling behavior. I'm not sure if there's more to this that I'm not seeing, but it looks like the "historic" solution to your problem is either to:
Use A Different Control
You can use an editable NSTextField in its standard IB label configuration with editing enabled and scrolling selected as the behavior. It does all the heavy lifting for you already when configured properly - no need to mess around with the field editor directly.
...or to...
Cheat
Slap the field editor into an appropriately-sized and configured NSScrollView (allow only horizontal scroll; don't show the scrollers) dynamically, then remove the scroll view when finished editing.
NSMutableParagraphStyle* style = [[NSMutableParagraphStyle alloc] init];
[style setLineBreakMode:NSLineBreakByTruncatingHead];
NSMutableDictionary* attributes = [[NSMutableDictionary alloc] init];
[attributes setObject:style forKey:NSParagraphStyleAttributeName];
NSTextView* textView = [[NSTextView alloc] init];
[textView setTypingAttributes:attributes];
If you use NSTextView, please try below codes ....
[self.textView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
[self.textView setHorizontallyResizable:YES];
[[self.textView textContainer] setWidthTracksTextView:NO];
[[self.textView textContainer] setContainerSize:NSMakeSize(FLT_MAX, FLT_MAX)];

Switch View issue

OK i asked this yesturday but i updated it with more detail as to the problems im having. The problem im having is this. When i run my app, the main view looks fine, just as it is suppose to. But, when i click a button to go to the next view, that view is shifted up about 20pixels. When i goback to the main screen it is shifted up the same.
The only time that my app looks like it is suppose to is when i first load it, once i click a button and start changing views, every view after i leave the mainview that first time is shifted up 20 pixels, even the mainview when i go back to it. I started having this issue when i upgraded from xcode 3.2 to xcode 4.0 beta. There is one way i have found to switchviews that doesnt make the views shift up BUT, i have an issue with this way. I have users input data on view1, on button click it switches to view2 and sends that data from 1 to 2. Using the switchview method that shows my views as they are suppose to be my data dont want to transfer to view2. Using the switchview method that gives me the data transfer from 1 to 2 that i need, it shifts the views up by 20 pixels. below are the examples of what im using.
-- with xcode 4 this way causes my views to shift up 20 pixels where as xcode 3.25 it worked great, had no issues and it transfered the data from view1 to view2.
- (IBAction)calculate:(id)sender {
MaleResultsController *maleResults = [[MaleResultsController alloc] initWithNibName:#"MaleResultsController" bundle:nil];
[UIView beginAnimations:#"flipping view" context:nil];
[UIView setAnimationDuration:.75];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown
forView:self.view cache:YES];
[self.view addSubview:maleResults.view];
maleResults.displayAge.text = ageInput.text;
maleResults.displayHeight.text = heightInput.text;
maleResults.displayWeight.text = weightInput.text;
NSString *minWeightString = [[NSString alloc] initWithFormat:#"%.0f", [self getMinWeight]];
maleResults.displayMinWeight.text = minWeightString;
[minWeightString release];
NSString *maxWeightString = [[NSString alloc] initWithFormat:#"%.0f", [self getMaxWeight]];
maleResults.displayMaxWeight.text = maxWeightString;
[maxWeightString release];
NSString *maxBodyFatString = [[NSString alloc] initWithFormat:#"%.0f", [self getMaxBodyFatPercentage]];
maleResults.displayMaxBodyFatPercentage.text = maxBodyFatString;
[maxBodyFatString release];
NSString *bodyFatString = [[NSString alloc] initWithFormat:#"%.0f", [self getBodyFatPercentage]];
maleResults.displayBodyFat.text = bodyFatString;
[bodyFatString release];
NSString *abdomenAvgString = [[NSString alloc] initWithFormat:#"%.2f", [self getAbdomenAvg]];
maleResults.abdomenAvg.text = abdomenAvgString;
[abdomenAvgString release];
NSString *neckAvgString = [[NSString alloc] initWithFormat:#"%.2f", [self getNeckAvg]];
maleResults.neckAvg.text = neckAvgString;
[neckAvgString release];
NSString *abNeckFactorString = [[NSString alloc] initWithFormat:#"%.2f", [self getAbNeckFactor]];
maleResults.abdomenNeckFactor.text = abNeckFactorString;
[abNeckFactorString release];
//
// [self.navigationController pushViewController:maleResults animated:YES];
[UIView commitAnimations];
}
-- with xcode 4 this method works to switch views correctly but doesnt transfer textfield input on view1 to label output on view2..
- (IBAction)calculate:(id)sender {
MaleBFCResults *maleBFCresults = [[MaleBFCResults alloc] initWithNibName:#"MaleBFCResults" bundle:nil];
MaleBFCdata *maleBFCData = [[MaleBFCdata alloc] init];
maleBFCresults.maleData = maleBFCData;
maleBFCresults.displayAge = ageInput.text;
maleBFCresults.displayHeight = heightInput.text;
maleBFCresults.displayWeight = weightInput.text;
maleBFCresults.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:maleBFCresults animated:YES];
[maleBFCresults release];
}
I have been searching for ways to fix this issue for a couple weeks now, and havnt been able to find anything to help. I havnt put all my forumlas and calculations into place yet on this new one because i want to make sure that the UI is functioning properly before i spend the time writing out all the code for the calculations. I like the transitions that "modalTransitionStyle" gives me over the "setAnimationTransition". Which is good because it works properly to switch views i just cant get it to transfer data from view1 to view2.
Im sure if i had to i could always revert back to the previous version of xcode but im trying not to have to do have to do that, if anyone has had a similar issue and has a solution i would really appreciate it. there may even be a different way to send data from view1 to view2 that would work that i havnt tried yet, but i havnt found a good way to do that either.
thanks in advance for any help with this issue..
I also faced the same problem of shifting view adn resolved it as below. The following code snippet switches from viewController to msgViewController.
Open the mainWindow.xib and add the UIViewController Object from the Library. Change its class to your Class that handles the specified viewController and then comes the click. Go to the properties section of the Attribute Inspector and set the respective Nib Name for the Controller and now save and exit the IB.
And the code changes to
-(void) flipToBack
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.8];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:window cache:YES];
[viewController.view removeFromSuperview];
[tabBarController.view removeFromSuperview];
[self.window addSubview:[msgViewController view]];
[UIView commitAnimations];
}
Hope this helps you!!
If it does please communicate.
Adjust the frame of those views regarding to the status bar.
However, I wouldn't rely on the application delegate object to handle multiple views. Have a root view controller which takes care of those views.