/* ** PlopWindowController.m ** ** Copyright (c) 2002 ** ** Author: Ludovic Marcotte ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #import "PlopWindowController.h" #import "Channel.h" #import "Constants.h" #import "NSStringExtensions.h" #import "Plop.h" #import "PlopView.h" #import "PlopWindow.h" static id lastPlopWindowOnTop = nil; @implementation PlopWindowController - (id) initWithWindowNibName: (NSString *) theNibName { PlopWindow *plopWindow; plopWindow = [[PlopWindow alloc] initWithContentRect:NSMakeRect(10,10,DEFAULT_PLOP_WIDTH,DEFAULT_PLOP_HEIGHT) styleMask: NSBorderlessWindowMask backing: NSBackingStoreBuffered defer: NO]; self = [super initWithWindow: plopWindow]; RELEASE(plopWindow); [plopWindow layoutWindow]; [plopWindow setDelegate: self]; // We link our outlets textView = [plopWindow textView]; // We set our text view color [textView setBackgroundColor: [NSColor colorWithDeviceRed: 0.90 green: 0.90 blue: 0.90 alpha: 1.0]]; // We set the title to an empty string [[self window] setTitle: @""]; #ifdef MACOSX // We link the dock menu dockMenu = [[NSApp delegate] applicationDockMenu: nil]; #endif return self; } // // // - (void) dealloc { NSLog(@"PlopWindowController: -dealloc"); lastPlopWindowOnTop = nil; [channel setPlopWindowController: nil]; RELEASE(channel); #ifdef MACOSX RELEASE(dockSubMenu); #endif [super dealloc]; } // // delegate methods // - (BOOL) textView: (NSTextView *) textView clickedOnLink: (id) link atIndex: (unsigned) charIndex { return [self openURL: link]; } // // // - (void) windowDidBecomeKey: (NSNotification *) aNotification { lastPlopWindowOnTop = [self window]; //[[PlopInfoWindowController singleInstance] setPlop: [self plop]]; } // // // - (void) windowDidLoad { lastPlopWindowOnTop = [self window]; [super windowDidLoad]; } // // // - (void) windowDidMove: (NSNotification *) aNotification { [self _updateWindowFrame]; } // // // - (void) windowDidResize: (NSNotification *) aNotification { [self _updateWindowFrame]; } // // // - (void) windowWillClose: (NSNotification *) theNotification { AUTORELEASE(self); } // // access / mutation // + (id) lastPlopWindowOnTop { return lastPlopWindowOnTop; } // // // - (Channel *) channel { return channel; } // // // - (void) setChannel: (Channel *) theChannel { if ( theChannel ) { RETAIN(theChannel); RELEASE(channel); channel = theChannel; [channel setPlopWindowController: self]; // We set our count variable and our icon [[self plopView] setCount: [channel itemCount]]; [[self plopView] setIcon: [channel icon]]; // We now update the text view with the content of the channel [self update]; // We finally set the window title and frame if ( [channel title] ) { [[self window] setTitle: [channel title]]; } [[self window] setFrame: [[channel plop] frame] display: NO]; #ifdef MACOSX // We create a submenu in the dock menu [dockMenu addItemWithTitle: [[channel plop] title] action: nil keyEquivalent: @""]; dockSubMenu = [[NSMenu alloc] init]; [dockMenu setSubmenu: dockSubMenu forItem: [dockMenu itemWithTitle: [[channel plop] title]]]; #endif } else { RELEASE(channel); channel = nil; } } // // // - (NSTextView *) textView { return textView; } // // // - (PlopView *) plopView { return [(PlopWindow *)[self window] plopView]; } // // action methods // #ifdef MACOSX - (IBAction) dockItemSelected: (id) sender { if ( [sender isKindOfClass: [NSMenuItem class]] ) { [self openURL: (NSURL *)[(NSMenuItem *)sender representedObject]]; } } - (IBAction) dockItemUpdate: (id) sender { if ( [sender isKindOfClass: [NSMenuItem class]] ) { [channel update: [self plopView]]; } } #endif // // Other methods // - (BOOL) openURL: (NSURL *) theURL { NSLog(@"Opening %@...", [theURL description]); if ( [[NSUserDefaults standardUserDefaults] integerForKey: @"BROWSER_SOURCE"] == USE_DEFAULT_BROWSER ) { return [[NSWorkspace sharedWorkspace] openURL: theURL]; } else { NSString *handler; handler = [[NSUserDefaults standardUserDefaults] objectForKey: @"BROWSER_PATH"]; if ( !handler || [[handler stringByTrimmingWhiteSpaces] length] == 0 ) { NSBeep(); return NO; } [NSTask launchedTaskWithLaunchPath: @"/bin/sh" arguments: [NSArray arrayWithObjects: @"-c", [NSString stringWithFormat: handler, [theURL description]], nil] ]; } return YES; } // // // - (void) update { NSMutableAttributedString *aMutableAttributedString; int i; if ( ![self channel] ) { return; } #ifdef MACOSX // We empty the dock sub menu for (i = [dockSubMenu numberOfItems] - 1; i > -1; i--) { [dockSubMenu removeItem: [dockSubMenu itemAtIndex: i]]; } #endif aMutableAttributedString = [[NSMutableAttributedString alloc] init]; for (i = 0; i < [[self channel] count]; i++) { NSDictionary *linkAttributes; Element *aElement; aElement = [[self channel] elementAtIndex: i]; if ( [aElement type] == ITEM && [aElement link] ) { NSAttributedString *aAttributedString; linkAttributes= [NSDictionary dictionaryWithObjectsAndKeys: [aElement link], NSLinkAttributeName, #ifdef MACOSX [NSNumber numberWithInt: NSNoUnderlineStyle], #else [NSNumber numberWithInt: GSNoUnderlineStyle], #endif NSUnderlineStyleAttributeName, [NSColor blackColor], NSForegroundColorAttributeName, NULL]; aAttributedString = [[NSAttributedString alloc] initWithString: [[aElement title] stringByAppendingString: @"\n"] attributes: linkAttributes]; [aMutableAttributedString appendAttributedString: aAttributedString]; #ifdef MACOSX // We add a menu item in the dock sub menu [dockSubMenu addItem: [self _constructMenuItem: [aElement title] action: @selector(dockItemSelected:) url: [aElement link]]]; #endif } } #ifdef MACOSX // We complete the dock sub menu but a Refresh menu item [dockSubMenu addItem: [NSMenuItem separatorItem]]; [dockSubMenu addItem: [self _constructMenuItem: @"Refresh" action: @selector(dockItemUpdate:) url: nil]]; #endif [[textView textStorage] setAttributedString: aMutableAttributedString]; RELEASE(aMutableAttributedString); // We set the count of plopview and ask to refresh it [[self plopView] setCount: [channel itemCount]]; [[self plopView] setNeedsDisplay: YES]; } @end // // private methods // @implementation PlopWindowController (Private) #ifdef MACOSX - (NSMenuItem *) _constructMenuItem: (NSString *) theTitle action: (SEL) theSelector url: (NSURL *) theURL { NSMenuItem *item; // This is the "correct" way to create the menu items - this code is used if we're // running on a fixed system if (NSAppKitVersionNumber >= kFixedDockMenuAppKitVersion) { item = [[NSMenuItem alloc] initWithTitle: theTitle action: theSelector keyEquivalent: @""]; AUTORELEASE(item); [item setTarget: self]; [item setRepresentedObject: theURL]; [item setEnabled: YES]; } else // we're running on an OS version that isn't fixed; use NSInvocation { // This invocation is going to be of the form aSelector NSInvocation *myInv; myInv = [NSInvocation invocationWithMethodSignature: [self methodSignatureForSelector: theSelector]]; item = [[NSMenuItem alloc] initWithTitle: theTitle action: @selector(invoke) keyEquivalent: @""]; AUTORELEASE(item); // This invocation is going to be an invocation of aSelector [myInv setSelector: theSelector]; // This invocation is going to send its message to self [myInv setTarget: self]; // The parameter to this invocation will be item, i.e. the NSMenuItem that should // be the sender to -menuSelected: Note that we pass it at index 2 - indices 0 and 1 // are taken by the hidden arguments self and _cmd, accessible through -setTarget: // and -setSelector: [myInv setArgument: &item atIndex: 2]; // here we retain the invocation so it won't go away. Later on we'll have to // release it to avoid leaking [item setTarget: RETAIN(myInv)]; [item setTag: 1]; [item setRepresentedObject: theURL]; [item setEnabled: YES]; } return item; } #endif - (void) _updateWindowFrame { if ( [[self channel] plop] ) { NSRect theFrame; theFrame = [[self window] frame]; [[[self channel] plop] setFrame: theFrame]; } } @end