NSDocument based application and NSToolbar - objective-c

I have application based on NSDocument (NSPersistentDocument), in application I can create (as usually) more than one document.
Main document window (based on NSPersistentDocument) has, added IB, toolbar. In code I add to toolbar item (NSToolbarItems) using methods insertItemWithItemIdentifier and - (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag.
Code samples:
[_toolbar insertItemWithItemIdentifier:#"addTape" atIndex:2];
and
- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag {
NSToolbarItem *item =nil;
if ([itemIdentifier isEqual:#"addTape"]) {
item = [[NSToolbarItem alloc] initWithItemIdentifier: itemIdentifier];
item.label = NSLocalizedString(#"Add Tape",#"Add Tape");
item.paletteLabel = NSLocalizedString(#"Add Tape",#"Add Tape");
item.toolTip = NSLocalizedString(#"Adds new tape",#"Adds new tape");
item.image = [NSImage imageNamed:#"NSAddTemplate"];
item.target = self;
item.action = #selector(addTape:);
item.tag = 101;
}
}
Everything is correct until I have opened only one document. When I open second document (or create new document) on first document window toolbar items are doubled (after opening third document, items are tripled on first window and doubled on second, and so on).
Edit: I noticed, that itemForItemIdentifier is called on each window, everytime I try to add toolbar item. In example: if I have two windows (two opened document) and on one I try to add one button itemForItemIdentifier is called two times.
It is strange to me, because every document has own toolbar with delegate set only to this document.
I don't have any idea what I have done wrong. Maybe someone will point me where I made a mistake.

You don't typically insert toolbar items yourself; implement the delegate methods toolbarAllowedItemIdentifiers: and toolbarDefaultItemIdentifiers: and the toolbar will be initialized according to those lists.

I found solution: I cannot use tooolbar created from nib, because each created this method toolbar has this same identifier. When I created toolbars in code, using different identifiers, the problem has gone.

Related

NSCollectionView does not change background colors when select or deselect 'Use Alternating Colors'

Right now I am working on a Startup Window for my document based application. The window's purpose is to give the user something visual to start with, instead of the menu bar.
The window contains a NSCollectionView whose purpose is to show recent files. I did manage to get the recent documents in the collection view using a separate .xib file as a reference NSCollectionViewItem. My collection view has the Flow layout vertical.
However, the items don't look the way I want them too. In my storyboard I did select the checkbox 'Use Alternating Colors', a property for the collection view. For testing purposes I selected Red as primary color and Yellow as Secondary color. In the storyboard I immediately see the complete collection view turning Red. When I run the application my startup window shows the collection view containing all the recent documents, but all backgrounds are the primary color, which would be Red.
I did look through some tuts, also the Ray Wenderlich one, but I can't seem to find any information about the alternating colors.
This is how I create my collection view items:
- (NSCollectionViewItem *)collectionView:(NSCollectionView *)collectionView itemForRepresentedObjectAtIndexPath:(NSIndexPath *)indexPath
{
RecentFileCollectionViewItem *item = [collectionView makeItemWithIdentifier:#"RecentFileCollectionViewItem" forIndexPath:indexPath];
NSURL *url = [self.recentFiles objectAtIndex:indexPath.item];
[item.logoImageView setImage:[NSImage imageNamed:#"NSComputer"]];
[item.fileNameLabel setStringValue:[url pathComponents][[url pathComponents].count -1]];
[item.filePathLabel setStringValue:[url path]];
return item;
}
Did anyone came across this problem? Is there a solution?
Thanks a lot !

Click on UILabel and perform action

I have a simple problem, I have a string like "#my#name#is#umesh#verma" and assign to a UITableview cell label,
cell.detaillabel.text = #"#my#name#is#umesh#verma";
My Problem is how to get each word name when I click on single item.
If I click on #umesh then I get "umesh" word..
More better solution is add custom label which supports touches. For example TTTAttributedLabel supports touches on links.
Main task is get notification when user touch a word and to identify the word.
You can add URLs (with special format) to any word and subscribe to a notification when user click it (as delegate to the label). For example you can create this URL for "word":
touchscheme://word
I haven't checked about how to perform an action when clicking on a UILabel. However, I experienced that with UITextView. You can use "NSLinkAttributeName" to do that.
Basically, from your original string, try to find the range of string that you need to trigger actions. Then add a link value.
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc]initWithString:yourString];
[attributedString addAttribute:NSLinkAttributeName value:url range:range];
[textView setAttributedText:attributedString];
Set delegate to your textView and handle the following method
-(BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange{
// You can retrive your string here or perform an action
return YES;
}
Hope this would be helpful for you.

NSDocument-based app, open dialog with 'New Document' button on launch

TextEdit and Pixelmator both open an open-file-dialog on launch that has a 'New Document' button in the bottom left corner.
Is there any particular code available to achieve the very same effect?
The reason I ask is that Pixelmator's way of going about it, the 'New Document' button included, is exactly the same as TextEdit, and I figure there must be some simple way to achieve this but I must be missing it.
Turns out you need to enable iCloud.
I found that adding an empty accessoryView to the openPanel also makes the "New Document" button visible. To do this, in your NSDocumentController descendant override beginPanel:forTypes:completionHandler: for example like below
- (void)beginOpenPanel:(NSOpenPanel*)openPanel forTypes:(NSArray<NSString*>*)inTypes completionHandler:(void(^)(NSInteger result))completionHandler {
// adding any accessory view makes the "New Document" button visible.
NSView* workaround = [[NSView alloc] initWithFrame:NSZeroRect];
openPanel.accessoryView = workaround;
// for non-arc: [workaround release];
[super beginOpenPanel:openPanel forTypes:inTypes completionHandler:^(NSInteger result) {
openPanel.accessoryView = nil;
completionHandler(result);
}];
}
You'll get warnings like this in the log:
[Layout] The Open/Save panel was supplied an accessory view with bad layout constraints, resulting in a view that is zero width. ...
I have not found a way to avoid that, but at least the New Document button is visible and working OK.

How can I bind to the Image property of a NSPopUpButtonCell?

I've created a NSTableView, and have set up all my bindings (via an NSArrayController). I want one of the columns to have a NSPopUpButtonCell, but, instead of showing text, I want it to show an image - so the user can change the image from the popup control.
My column is bound (using the SelectedObject binding) to the correct property, and the the NSPopUpButtonCell is bound (using the ContentValues binding) to my complete list of images (which is from another NSArrayController containing an array of image names - NSStrings).
I've created a NSValueTransformer to convert an image name (NSString) to an NSImage, and have tested this works by creating an addition column with an NSImageCell, and that displays the image correctly.
Is there a way to do this?
I'm hoping I can target the binding at the NSPopUpButtonCell's image property, rather than its title property.
Edit: I had the idea of trying to use an NSAttributedString, with an embedded image. But, the problem remains, in that I want the binding to use setAttributedTitle, rather than setTitle.
After a lot of trial and error, I've managed to solve this problem. I'm convinced there remains a more correct solution, but, for now, this'll do.
My solution:
Change the Pop Up Button Cell > Menu to a custom class
In the custom class, inherit from NSMenu:
#interface RSMenu : NSMenu
Override insertItemWithTitle, and customize to your own needs.
For example:
-(NSMenuItem *)insertItemWithTitle:(NSString *)aString
action:(SEL)aSelector
keyEquivalent:(NSString *)charCode
atIndex:(NSInteger)index {
NSImage *image = [NSImage imageNamed:aString];
NSMenuItem* menuItem = [super insertItemWithTitle:image ? #"" : aString
action:aSelector
keyEquivalent:charCode atIndex:index];
if ( nil != image ) {
[menuItem setImage:image];
}
return menuItem;
}
And here is the result:
Hope this helps someone else.

Cocoa Window not remembering its position when reopening

I started objective C last week so I'm just beginning to understand how the MVC design pattern works. Basically I downloaded this open source web app wrapper in cocoa:
https://github.com/maccman/macgap
and I want to alter it so it remembers its window position when I re-open it.
I've already tried opening up the nib and assigning a value to Autosave however this did not work. After researching the issue I discovered this is because the window controller automatically turns cascading on, so within WindowController.m I put
[[self.window windowController] setShouldCascadeWindows:NO];
[self.window setFrameAutosaveName:[self.window representedFilename]];
I tried putting this in windowDidLoad and the init methods however this did not work either and the window still did not remember its position.
Finally within AppDelegate I noticed that this is the code that actually creates the controller:
- (void) applicationDidFinishLaunching:(NSNotification *)aNotification {
NSRect frame = NSMakeRect(0, 0, 800, 600);
self.windowController = [[WindowController alloc] initWithURL: kStartPage
andFrame:frame];
[self.windowController showWindow: [NSApplication sharedApplication].delegate];
self.windowController.contentView.webView.alphaValue = 1.0;
self.windowController.contentView.alphaValue = 1.0;
[self.windowController showWindow:self];
}
As I said I started objective-c last week (for iOS development) and from that I know that the NSMakeRect is what's determining the window position. Now, I also know from Java that I could do something like write the coordinates to a binary file when it moves, then read that file when I start up the program and just feed these values into NSMakeRect, however I don't think this is the most elegant solution.