Populate a NSMenu from an NSArray with NSMenuItems - Need Alternative Suggestions - objective-c

So I have the following code:
- (void)addSupportLinksMenuItems
{
NSString *subMenuTitle;
NSString *getURL;
if (!supportLinks) {
supportLinks = [[NSArray alloc] initWithArray:[settings objectForKey:#"supportLinks"]];
}
for(NSDictionary *object in supportLinks){
// A couple of Keys in the Dict inside the Array
subMenuTitle = [object objectForKey:#"subMenuTitle"];
getURL = [object objectForKey:#"getURL"];
NSInteger n = [ supportLinks indexOfObject:object];
NSInteger menuTag = n +255;
//[ supportLinkItem setImag
supportLinkArrayItem = [supportLinkItem
insertItemWithTitle:subMenuTitle
action:#selector(openSupportLink:)
keyEquivalent:#""
atIndex:n];
// Set a menu tag to programatically update in the future
[ supportLinkArrayItem setTag:menuTag];
[ supportLinkArrayItem setToolTip:getURL];
[ supportLinkArrayItem setTarget:self];
}
//supportLinkItem
}
This dynamically generates an submenu items from an NSArray and allows me to open the url based on the choice that was selected (in a specific browser):
-(IBAction)openSupportLink:(id)sender
{
NSLog(#"Was passed Menu: %#",sender);
NSInteger menuTag = [sender tag];
NSInteger n = menuTag - 255;
NSString *getURL = [[supportLinks objectAtIndex:n] objectForKey:#"getURL"];
[self openPageInSafari:getURL];
}
- (void)openPageInSafari:(NSString *)url
{
NSDictionary* errorDict;
NSAppleEventDescriptor* returnDescriptor = NULL;
NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource:
[NSString stringWithFormat:
#"\
tell app \"Safari\"\n\
activate \n\
make new document at end of documents\n\
set URL of document 1 to \"%#\"\n\
end tell\n\
",url]];
returnDescriptor = [scriptObject executeAndReturnError: &errorDict];
[scriptObject release];
}
My question is, while this seems to work great , I would like to set an image for the NSMenu supportLinkItem, here is what my .h file looks like:
IBOutlet NSMenu *supportLinkItem;
NSMenuItem *supportLinkArrayItem;
And the outlet is linked to the sub menu item, as I have created its (parent? -terminology?) as a NSmenu, it does not allow me to access this as the - (void)setImage:(NSImage *)menuImage method as its not a NSMenuitem. Now I think maybe I have just done something weird here as , technically when you drag the "Sub Menu Item" into interface builder its a NSMenuItem not a NSMenu, again my code works flawlessly except for my inability to set the image of the menu, Which I think is a no go but perhaps there is similar way to read from an NSArray to populate a set of sub menus.

I was able to resolve this by updating the image in the nib file as the nib thinks its a nsmenuitem.

Related

WebKit WebView paste: fails for dynamic UTIs

When copying a URL from chrome on OSX and pasting into an editable WebKit webview, nothing gets pasted.
I verified that there are items on the NSPasteboard and that the NSPasteboardItem has the following types:
"dyn.ah62d4rv4gu8zs3pcnzme2641rf4guzdmsv0gn64uqm10c6xenv61a3k",
"dyn.ah62d4rv4gu8yc6durvwwaznwmuuha2pxsvw0e55bsmwca7d3sbwu",
"public.utf8-plain-text",
"dyn.ah62d4rv4gu8yg55wqzkgc65yqzvg82pwqvdg22p0r73fk8puqyuda8b1gy5xerwdgk2a",
"dyn.ah62d4rv4gu8yg55wqzkgc65yqzvg82pwqvdg22p0r73fk8puqyuda8b1gy5xerwdg3cu"
I understand that these are auto-generated and map to WebURLsWithTitlesPboardType.
On performing the same operation from safari to webview, it works since it only contains
"public.utf8-plain-text"
Is there a known workaround for handling these UTIs better?
Webkit webviews don't seem to support paste operations for dynamic UTIs. I worked around it by recreating the pasteboard items without those UTIs when a paste: was intercepted in webview:doCommandBySelector:
- (void)cleanupPasteboard:(NSPasteboard *)pasteboard {
NSMutableArray *newItems = [[NSMutableArray alloc] init];
for (NSPasteboardItem *item in pasteboard.pasteboardItems) {
NSPasteboardItem *newItem = [[NSPasteboardItem alloc] init];
for (NSString *type in item.types) {
if (![type hasPrefix:#"dyn"]) {
[newItem setData:[item dataForType:type] forType:type];
}
}
[newItems addObject:newItem];
}
[pasteboard clearContents];
[pasteboard writeObjects:newItems];
}

NSWindow hide active window and focus on other

How to hide the active current NSWindow A and focus on the last other one B (one level behind the current window) and make it active?
I'm trying with this followed code but it does not work (B will become to front window but not active):
[_parentWindow orderBack:nil];
// Now i want to do some stuffs with last opened App (NSWindow) and it should be focused and activated now.
[_parentWindow orderFront:nil];
Try makeKeyAndOrderFront: instead.
[_window makeKeyAndOrderFront:nil];
Supplement to #bluedome response. You can get information about windows in the current user session:
CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
for (NSDictionary* entry in (__bridge NSArray *)windowList) {
NSString *ownerName = [entry objectForKey:(id)kCGWindowOwnerName];
NSInteger ownerPID = [[entry objectForKey:(id)kCGWindowOwnerPID] integerValue];
NSString *windowName = [entry objectForKey:(id)kCGWindowName];
NSLog(#"%#:%ld, %#", ownerName, (long)ownerPID, windowName);
}

Objective-C delegate incompatible type

I am using http://www.vfr.org/, pdf viewer, and I try to add a button to open PDF in IBOOK.
I added the button and action to it, but I stuck t the moment when I want open ibooks application with this pdf.
I tried 2 solutions:
button tapped action:
NSURL *fileURL = document.fileURL;
NSString *fileName = document.fileName; // Document
[[UIApplication sharedApplication] openURL:fileURL];
It opens the IBOOKS but the PDF never gets loaded.
I am assuming the URL format can be wrong I tried even hard code a PDF URL like:
NSString *stringURL = #"itms-books://linktopdf.pdf";
NSURL *url = [NSURL URLWithString:stringURL];
[[UIApplication sharedApplication] openURL:url];
But the same result.
2) Button tapped action:
NSURL *fileURL = document.fileURL;
NSString *fileName = document.fileName; // Document
UIDocumentInteractionController *docController = [[UIDocumentInteractionController alloc] init];
docController = [UIDocumentInteractionController interactionControllerWithURL:fileURL];
docController.delegate = self;
But I have an warning where I try to delegate: docController.delegate = self;
assigning to id UIDocumentInteractionControllerDelegate from Incompatible ReaderViewController
Can someone help me to make it work at least 1 of these solution.
Has the ReaderViewController this kind of line in the header file: #interface ReaderViewController : NSObject < UIDocumentInteractionControllerDelegate > ?
Your class must conform to the UIDocumentInteractionControllerDelegate protocol, so in your .h file make it look like
#interface ReaderViewController : PerantClass <UIDocumentInteractionControllerDelegate>
{
...
}
Then the compiler will know that your class conforms to that protocol. Of course, you still need to implement the needed methods.
ALso Check this Link - 1 And Link - 2.

Objects string value is not set correctly

I'm writing a small project time management program for myself and have run into a problem which has confounded me.
They way it's set up is that I have an object called TCObject which I use in another object called ProjectTimerController. ProjectTimerController is a NSWindowController and it has it's own NIB file.
What I'm doing is pretty straight forward. When you click a line in a NSTableView ProjectTimerController finds a TCObject which corresponds to that line. It then loads info from that TCObject into an interface where you can view and edit some stuff.
Here's a screenshot of what it looks like:
Now when I change the text in NSTextView and then press the Add button the -saveString function is called and currentSelection (which is a TCObject and represents the currently selected line) and it's notes variable is set. I know that _notes is set as the new value as NSLog function logs the correct string being in _notes when setString is run. The same, correct, string is logged in -tableViewSelectionDidChange: just before currentSelection is set as the newly selected object.
But if I select the line where I just changed the notes it just loads the same text, "Initial String" and checking _notes tells me it's "Initial String".
Thing I don't have this problem with isFinished. When the Finished check box is toggled I set the corresponding TCObjects' isFinished Boolean value to the same value as the checkbox. This the object remembers and correctly changes depending on what line I have selected.
[EDIT]
*I've added a clearer explanation here.
I click a line in the NSTableView (lets say the top one)
This loads a corresponding TCObject from the myProjects array and that object's variable are added to the Notes NSTextView box and Finished is toggled on or off.
If I now write into The Notes box and press "Add" the text there is set into that TCObject's _notes variable.
So If I click another line some other text is loaded into the Notes box. Clicking back on the top line should give me the string I just wrote into Notes in step 3. But it doesn't. _notes always seems to contain the string I set when I initialize it in the -init method.
The "Finished" checkbox works fine. When I click that the state is saved and loaded correctly when I click a line.
I know that _notes is correctly set when I press the Add button as the NSLog method in setString logs the string I have written into Notes when I press the Add button.
[/EDIT]
Here below is a barebones version of TCObject and ProjectTimerController.
//TCObject.h
#interface TCObject : NSObject
{
NSString *_notes;
Boolean _isFinished;
}
#property (retain, nonatomic) NSString *notes;
#property (nonatomic) Boolean isFinished;
#end
//TCObject.m
#import "TCObject.h"
#implementation TCObject
#synthesize notes = _notes, isFinished = _isFinished;
-(id)init{
if (self = [super init]) {
self.notes = #"Initial string";
self.isFinished = NO;
}
return self;
}
- (void)dealloc {
[_notes release]; _notes = nil;
[super dealloc];
}
-(void)setNotes:(NSString *)notes {
[notes retain];
[_notes release];
_notes = notes;
NSLog(#"Setting _notes as: %#", _notes);
}
-(NSString *)notes {
NSLog(#"Getting _notes, which is: %#", _notes);
return _notes;
}
#end
//ProjectTimerController.m
- (id)initWithWindow:(NSWindow *)window {
self = [super initWithWindow:window];
if (self)
{
myProjects = [[NSMutableArray alloc]init];
currentSelection = nil;
TCObject *newProject = [[TCObject alloc] init];
TCObject *newProject2 = [[TCObject alloc] init];
TCObject *newProject3 = [[TCObject alloc] init];
TCObject *newProject4 = [[TCObject alloc] init];
[myProjects addObject:newProject];
[myProjects addObject:newProject2];
[myProjects addObject:newProject3];
[myProjects addObject:newProject4];
}
return self;
}
-(IBAction)isFinishedToggle:(id)sender {
if(currentSelection != nil){
currentSelection.isFinished = finishedCheckBtn.state;
}
}
-(IBAction)saveString:(id)sender {
if(currentSelection != nil){
currentSelection.notes = [[notesField textStorage] string];
}
}
//delegate function for NSTableView
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification {
NSInteger selectedIndex = [table selectedRow];
if(selectedIndex == -1){
return;
}
//here the correct notes string is printed
NSLog(#"curr: %i", currentSelection.notes);
currentSelection = [myProjects objectAtIndex:selectedIndex];
NSString *notesInfo = currentSelection.notes;
Boolean isFinishedInfo = currentSelection.isFinished;
[notesField setString:notesInfo];
[finishedCheckBtn setState:isFinishedInfo];
}
Finally found the problem. Seems that changing notes in this way:
-(IBAction)saveString:(id)sender {
if(currentSelection != nil){
currentSelection.notes = [[notesField textStorage] string];
}
}
causes some problems. Everything works fine if I do it this way:
-(IBAction)saveString:(id)sender{
if(currentSelection != nil){
NSString *temps = [NSString stringWithFormat:#"%#", [[notesField textStorage] string]];
currentSelection.notes = temps;
}
}
So I'm guessing what was going on is that _notes was pointing to the text contained in my NSTextView. So when I changed the text there _notes also changed or something like that...

Add to arrayController, edit Core Data attribute

***** EDIT *****
What I'm not sure of is how to access an entity from the model in the code, and how to access a specific instance of an entity in that code. That sums up the main issues I'm having.
***** END EDIT *****
I have a tableview with a button to add to it. When the button is clicked, the user is presented with an open dialog where they select a file(s). A new Object is added to the array controller. What I'm not sure how to do is to edit the core data attributes for this new object. There are two attributes, filename and pathname, and I'm not sure how to edit them. If you look at the bottom of the openPanelDidEnd:returnCode:contextInfo: function you'll see what I'm trying to accomplish.
- (IBAction)addAttachment:(id)sender
{
panel = [NSOpenPanel openPanel];
[panel beginSheetForDirectory:nil
file:nil
modalForWindow:[NSApp mainWindow]
modalDelegate:self
didEndSelector:#selector(openPanelDidEnd:
returnCode:
contextInfo:)
contextInfo:NULL];
}
- (void)openPanelDidEnd:(NSOpenPanel *)openPanel
returnCode:(int)returnCode
contextInfo:(void *)x
{
if (returnCode == NSOKButton)
{
NSArray *files = [openPanel filenames];
int i;
for (i = 0; i < [files count]; i++)
{
NSString *file = [files objectAtIndex:i];
[attachmentController add:x];
// How do I add filenames here?
// I'm assuming it involves KVC like
// [something setValue:#"file" forKey:#"filename"];
// But I don't know hot to get the something
// i.e. since I have multiple attachments,
// how do I get the one I just created
}
}
}
*********** EDIT **************
Simplified, my model has 2 entities: Attachment and Item. Item has a to-many relationship with Attachment, as each Item may have many Attachment's.
My openPanelDidEnd:returnCode:contextInfo: method now looks like this:
NSString *filename = [files objectAtIndex:i];
MySchoolPlanner_AppDelegate *myAppDelegate = [[MySchoolPlanner_AppDelegate init] alloc];
[NSEntityDescription insertNewObjectForEntityForName:#"Attachment"
inManagedObjectContext:[myAppDelegate managedObjectContext]];
[myAppDelegate release];
For some reason, the table view bound to the Attachment array controller does not add any. Also, I'm not sure how to access the attachment I just created to use KVC on it.
NSArray's add: method is something you'd hook a button up to, when you have a Core Data entity that can be created and used without any initialization. In this case just call NSEntityDescription's
+ (id)insertNewObjectForEntityForName:(NSString *)entityName inManagedObjectContext:(NSManagedObjectContext *)context
with the managed object context you're using with your array controller and the appropriate entity name to create your managed object in code. You can set properties on it directly if you've created a subclass for your entity, or just use key value coding if you haven't done that yet.