Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Initial commit. Simple OS X GUI wrapper for ShairPort

  • Loading branch information...
commit 771545ae6a905b068f0fe95b7d8047f3489e8f59 0 parents
Robert Carlsen authored

Showing 28 changed files with 7,442 additions and 0 deletions. Show diff stats Hide diff stats

  1. +20 0 .gitignore
  2. +33 0 Classes/Controllers/AboutPanelController.h
  3. +67 0 Classes/Controllers/AboutPanelController.m
  4. +44 0 Classes/Controllers/ShairPortController.h
  5. +143 0 Classes/Controllers/ShairPortController.m
  6. +38 0 Classes/Controllers/ShairPreferencesController.h
  7. +90 0 Classes/Controllers/ShairPreferencesController.m
  8. +36 0 Classes/Models/ShairPortModel.h
  9. +56 0 Classes/Models/ShairPortModel.m
  10. +54 0 Classes/ShairPortMenuAppDelegate.h
  11. +167 0 Classes/ShairPortMenuAppDelegate.m
  12. +485 0 Classes/Views/AboutPanel.xib
  13. +3,902 0 Classes/Views/MainMenu.xib
  14. +790 0 Classes/Views/ShairPreferencesWindow.xib
  15. +621 0 LICENSE.txt
  16. +12 0 Resources/Defaults.plist
  17. +2 0  Resources/English.lproj/InfoPlist.strings
  18. +27 0 Resources/about.rtf
  19. BIN  Resources/hairtunes
  20. BIN  Resources/images/hairplay-active.png
  21. BIN  Resources/images/hairplay-off.png
  22. BIN  Resources/images/hairplay-on.png
  23. BIN  Resources/images/hairplay-over.png
  24. +420 0 Resources/shairport.pl
  25. +34 0 ShairPortMenu-Info.plist
  26. +378 0 ShairPortMenu.xcodeproj/project.pbxproj
  27. +9 0 ShairPortMenu_Prefix.pch
  28. +14 0 main.m
20 .gitignore
... ... @@ -0,0 +1,20 @@
  1 +# xcode noise
  2 +build/*
  3 +*.pbxuser
  4 +*.mode1v3
  5 +*.mode2v3
  6 +#Info.plist
  7 +#*.xcodeproj
  8 +*.xcworkspace
  9 +xcuserdata*
  10 +
  11 +# old skool
  12 +.svn
  13 +
  14 +# osx noise
  15 +.DS_Store
  16 +profile
  17 +
  18 +# ignore other object files
  19 +*.o
  20 +
33 Classes/Controllers/AboutPanelController.h
... ... @@ -0,0 +1,33 @@
  1 +//
  2 +// AboutPanelController.h
  3 +// This file is part of ShairPortMenu.
  4 +//
  5 +// A Simple OS X GUI wrapper for ShairPort / HairTunes
  6 +//
  7 +// Copyright 2011 Robert Carlsen.
  8 +//
  9 +// ShairPortMenu is free software: you can redistribute it and/or modify
  10 +// it under the terms of the GNU General Public License as published by
  11 +// the Free Software Foundation, either version 3 of the License, or
  12 +// (at your option) any later version.
  13 +//
  14 +// ShairPortMenu is distributed in the hope that it will be useful,
  15 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 +// GNU General Public License for more details.
  18 +//
  19 +// You should have received a copy of the GNU General Public License
  20 +// along with ShairPortMenu. If not, see <http://www.gnu.org/licenses/>.
  21 +//
  22 +
  23 +#import <Cocoa/Cocoa.h>
  24 +
  25 +
  26 +@interface AboutPanelController : NSWindowController {
  27 +@private
  28 + IBOutlet NSTextView *aboutTextView;
  29 + IBOutlet NSTextField *versionLabel;
  30 +}
  31 +
  32 +@property(nonatomic,retain)IBOutlet NSTextField *versionLabel;
  33 +@end
67 Classes/Controllers/AboutPanelController.m
... ... @@ -0,0 +1,67 @@
  1 +//
  2 +// AboutPanelController.m
  3 +// This file is part of ShairPortMenu.
  4 +//
  5 +// A Simple OS X GUI wrapper for ShairPort / HairTunes
  6 +//
  7 +// Copyright 2011 Robert Carlsen.
  8 +//
  9 +// ShairPortMenu is free software: you can redistribute it and/or modify
  10 +// it under the terms of the GNU General Public License as published by
  11 +// the Free Software Foundation, either version 3 of the License, or
  12 +// (at your option) any later version.
  13 +//
  14 +// ShairPortMenu is distributed in the hope that it will be useful,
  15 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 +// GNU General Public License for more details.
  18 +//
  19 +// You should have received a copy of the GNU General Public License
  20 +// along with ShairPortMenu. If not, see <http://www.gnu.org/licenses/>.
  21 +//
  22 +
  23 +#import "AboutPanelController.h"
  24 +
  25 +
  26 +@implementation AboutPanelController
  27 +@synthesize versionLabel;
  28 +
  29 +- (id)initWithWindow:(NSWindow *)window
  30 +{
  31 + self = [super initWithWindow:window];
  32 + if (self) {
  33 + // Initialization code here.
  34 + }
  35 +
  36 + return self;
  37 +}
  38 +
  39 +- (void)dealloc
  40 +{
  41 + self.versionLabel = nil;
  42 +
  43 + [super dealloc];
  44 +}
  45 +
  46 +- (void)windowDidLoad
  47 +{
  48 + [super windowDidLoad];
  49 +
  50 + [self.versionLabel setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Version: %@","Version label"),kSPMVersion]];
  51 +
  52 + // set up the about text:
  53 + NSBundle *bundle = [NSBundle mainBundle];
  54 + NSString *aboutTextPath = [bundle pathForResource:@"about" ofType:@"rtf"];
  55 + [aboutTextView readRTFDFromFile:aboutTextPath];
  56 +
  57 + [aboutTextView setAutomaticLinkDetectionEnabled:YES];
  58 + [aboutTextView setAutomaticDataDetectionEnabled:YES];
  59 +
  60 + [aboutTextView setLinkTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
  61 + [NSCursor pointingHandCursor], NSCursorAttributeName,
  62 + [NSNumber numberWithInt:NSUnderlineStyleSingle], NSUnderlineStyleAttributeName,
  63 + [NSColor darkGrayColor], NSForegroundColorAttributeName,
  64 + nil]];
  65 +}
  66 +
  67 +@end
44 Classes/Controllers/ShairPortController.h
... ... @@ -0,0 +1,44 @@
  1 +//
  2 +// ShairPortController.h
  3 +// This file is part of ShairPortMenu.
  4 +//
  5 +// A Simple OS X GUI wrapper for ShairPort / HairTunes
  6 +//
  7 +// Copyright 2011 Robert Carlsen.
  8 +//
  9 +// ShairPortMenu is free software: you can redistribute it and/or modify
  10 +// it under the terms of the GNU General Public License as published by
  11 +// the Free Software Foundation, either version 3 of the License, or
  12 +// (at your option) any later version.
  13 +//
  14 +// ShairPortMenu is distributed in the hope that it will be useful,
  15 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 +// GNU General Public License for more details.
  18 +//
  19 +// You should have received a copy of the GNU General Public License
  20 +// along with ShairPortMenu. If not, see <http://www.gnu.org/licenses/>.
  21 +//
  22 +
  23 +#import <Foundation/Foundation.h>
  24 +@class ShairPortModel;
  25 +
  26 +@interface ShairPortController : NSObject {
  27 + ShairPortModel *shairportModel;
  28 + id delegate;
  29 +
  30 + NSTask *shairportTask;
  31 + NSFileHandle *readFile;
  32 +}
  33 +
  34 +@property(nonatomic,retain)NSTask *shairportTask;
  35 +@property(assign)id delegate;
  36 +
  37 +-(void)setServerRunning:(BOOL)state;
  38 +
  39 +@end
  40 +
  41 +@protocol ShairPortControllerDelegate <NSObject>
  42 +-(void)shairPortStarted;
  43 +-(void)shairPortStopped;
  44 +@end
143 Classes/Controllers/ShairPortController.m
... ... @@ -0,0 +1,143 @@
  1 +//
  2 +// ShairPortController.m
  3 +// This file is part of ShairPortMenu.
  4 +//
  5 +// A Simple OS X GUI wrapper for ShairPort / HairTunes
  6 +//
  7 +// Copyright 2011 Robert Carlsen.
  8 +//
  9 +// ShairPortMenu is free software: you can redistribute it and/or modify
  10 +// it under the terms of the GNU General Public License as published by
  11 +// the Free Software Foundation, either version 3 of the License, or
  12 +// (at your option) any later version.
  13 +//
  14 +// ShairPortMenu is distributed in the hope that it will be useful,
  15 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 +// GNU General Public License for more details.
  18 +//
  19 +// You should have received a copy of the GNU General Public License
  20 +// along with ShairPortMenu. If not, see <http://www.gnu.org/licenses/>.
  21 +//
  22 +
  23 +#import "ShairPortController.h"
  24 +#import "ShairPortMenuAppDelegate.h"
  25 +#import "ShairPortModel.h"
  26 +
  27 +@implementation ShairPortController
  28 +
  29 +@synthesize shairportTask, delegate;
  30 +
  31 +- (id)init
  32 +{
  33 + self = [super init];
  34 + if (self) {
  35 + // Initialization code here.
  36 + shairportModel = [(ShairPortMenuAppDelegate*)[NSApp delegate] shairportModel];
  37 +
  38 + [[NSNotificationCenter defaultCenter] addObserver:self
  39 + selector:@selector(incomingData:)
  40 + name:NSFileHandleDataAvailableNotification object:nil];
  41 +
  42 + [[NSNotificationCenter defaultCenter] addObserver:self
  43 + selector:@selector(processStopped:)
  44 + name:NSTaskDidTerminateNotification object:nil];
  45 +
  46 + }
  47 +
  48 + return self;
  49 +}
  50 +
  51 +- (void)dealloc
  52 +{
  53 + delegate = nil;
  54 +
  55 + [super dealloc];
  56 +}
  57 +
  58 +
  59 +
  60 +-(void)setServerRunning:(BOOL)state;
  61 +{
  62 + if(state) {
  63 + if (shairportTask == nil) {
  64 + shairportTask = [[NSTask alloc] init];
  65 +
  66 + NSBundle *bundle = [NSBundle mainBundle];
  67 + NSString *shairportPath;
  68 + shairportPath = [bundle pathForResource:@"shairport" ofType:@"pl"];
  69 +
  70 + [shairportTask setLaunchPath: shairportPath];
  71 +
  72 + // TODO: look for other instances, then kill them?
  73 + // ps axwww|grep -v grep |grep shairport.pl
  74 +
  75 + // add args for hostname {optionally, password}
  76 + NSMutableArray *args = [NSMutableArray arrayWithCapacity:4];
  77 + NSString *name = shairportModel.serverName;
  78 + if (name == nil || [name isEqualToString:@""]) {
  79 + name = [[NSProcessInfo processInfo] hostName];
  80 + }
  81 + [args addObject:@"--apname"];
  82 + [args addObject:name];
  83 +
  84 + if (shairportModel.usePassword) {
  85 + [args addObject:@"--password"];
  86 + [args addObject:shairportModel.serverPassword];
  87 + }
  88 +
  89 + [shairportTask setArguments:args];
  90 + NSLog(@"command: %@",[[shairportTask arguments] description]);
  91 +
  92 + NSPipe *shairportPipe = [NSPipe pipe];
  93 + readFile = [shairportPipe fileHandleForReading];
  94 + [readFile waitForDataInBackgroundAndNotify];
  95 +
  96 + [shairportTask setStandardOutput:shairportPipe];
  97 + [shairportTask launch];
  98 +
  99 + // fire off a message so the app delegate can update the menu
  100 + if ([delegate respondsToSelector:@selector(shairPortStarted)]) {
  101 + [delegate shairPortStarted];
  102 + }
  103 + }
  104 + }
  105 + else {
  106 + [shairportTask terminate];
  107 + [shairportTask release]; shairportTask = nil;
  108 + }
  109 +}
  110 +
  111 +#pragma mark - Notification handlers
  112 +-(void)incomingData:(NSNotification*)notification
  113 +{
  114 + // TODO: parse the console messages
  115 + // look for pertinent messages...namely connection events and status updates.
  116 + // can we get song information from the stream?
  117 +
  118 + NSData *incomingData = readFile.availableData;
  119 + NSString *logString = [[NSString alloc] initWithData:incomingData encoding:NSUTF8StringEncoding];
  120 + NSLog(@"log: %@",logString);
  121 +
  122 +
  123 + // look for messages:
  124 + // REQ: TEARDOWN
  125 + // ***CHILD EXITED*** disconnection event
  126 + // new connection from fe80::e2f8:47ff:fe08:f2aa
  127 +
  128 + [logString release];
  129 +}
  130 +
  131 +-(void)processStopped:(NSNotification*)notification;
  132 +{
  133 + NSLog(@"the task terminated");
  134 + [shairportTask release]; shairportTask = nil;
  135 +
  136 + // tell the app delegate to update the UI
  137 + if ([delegate respondsToSelector:@selector(shairPortStopped)]) {
  138 + [delegate shairPortStopped];
  139 + }
  140 +}
  141 +
  142 +
  143 +@end
38 Classes/Controllers/ShairPreferencesController.h
... ... @@ -0,0 +1,38 @@
  1 +//
  2 +// ShairPreferencesController.h
  3 +// This file is part of ShairPortMenu.
  4 +//
  5 +// A Simple OS X GUI wrapper for ShairPort / HairTunes
  6 +//
  7 +// Copyright 2011 Robert Carlsen.
  8 +//
  9 +// ShairPortMenu is free software: you can redistribute it and/or modify
  10 +// it under the terms of the GNU General Public License as published by
  11 +// the Free Software Foundation, either version 3 of the License, or
  12 +// (at your option) any later version.
  13 +//
  14 +// ShairPortMenu is distributed in the hope that it will be useful,
  15 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 +// GNU General Public License for more details.
  18 +//
  19 +// You should have received a copy of the GNU General Public License
  20 +// along with ShairPortMenu. If not, see <http://www.gnu.org/licenses/>.
  21 +//
  22 +
  23 +#import <Cocoa/Cocoa.h>
  24 +
  25 +
  26 +@interface ShairPreferencesController : NSWindowController {
  27 + IBOutlet id model;
  28 +
  29 + IBOutlet NSTextField *serverNameField;
  30 + IBOutlet NSTextField *serverPasswordField;
  31 + IBOutlet NSButton *serverUsePasswordButton;
  32 +}
  33 +
  34 +@property(assign)IBOutlet id model;
  35 +
  36 +-(IBAction)savePreferences:(id)sender;
  37 +
  38 +@end
90 Classes/Controllers/ShairPreferencesController.m
... ... @@ -0,0 +1,90 @@
  1 +//
  2 +// ShairPreferencesController.m
  3 +// This file is part of ShairPortMenu.
  4 +//
  5 +// A Simple OS X GUI wrapper for ShairPort / HairTunes
  6 +//
  7 +// Copyright 2011 Robert Carlsen.
  8 +//
  9 +// ShairPortMenu is free software: you can redistribute it and/or modify
  10 +// it under the terms of the GNU General Public License as published by
  11 +// the Free Software Foundation, either version 3 of the License, or
  12 +// (at your option) any later version.
  13 +//
  14 +// ShairPortMenu is distributed in the hope that it will be useful,
  15 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 +// GNU General Public License for more details.
  18 +//
  19 +// You should have received a copy of the GNU General Public License
  20 +// along with ShairPortMenu. If not, see <http://www.gnu.org/licenses/>.
  21 +//
  22 +
  23 +#import "ShairPreferencesController.h"
  24 +
  25 +#import "ShairPortMenuAppDelegate.h"
  26 +#import "ShairPortModel.h"
  27 +
  28 +@implementation ShairPreferencesController
  29 +@synthesize model;
  30 +
  31 +- (id)initWithWindow:(NSWindow *)window
  32 +{
  33 + self = [super initWithWindow:window];
  34 + if (self) {
  35 + // Initialization code here.
  36 + model = (ShairPortModel*)[(ShairPortMenuAppDelegate*)[NSApp delegate] shairportModel];
  37 + }
  38 +
  39 + return self;
  40 +}
  41 +
  42 +- (void)dealloc
  43 +{
  44 + [super dealloc];
  45 +}
  46 +
  47 +- (void)windowDidLoad
  48 +{
  49 + [super windowDidLoad];
  50 +
  51 + [serverNameField.cell setPlaceholderString:[[NSProcessInfo processInfo] hostName]];
  52 + [serverNameField setStringValue:[model serverName]];
  53 +
  54 + [serverPasswordField setStringValue:[model serverPassword]];
  55 + [serverUsePasswordButton setState:[model usePassword]];
  56 +}
  57 +
  58 +
  59 +-(IBAction)savePreferences:(id)sender;
  60 +{
  61 + NSLog(@"saving prefs");
  62 + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  63 +
  64 + // the values for the prefs have bindings to the defaults...
  65 + // do we have to manually read them back in?
  66 +
  67 + [model setServerPassword:serverPasswordField.stringValue];
  68 + [model setServerName:serverNameField.stringValue];
  69 + [model setUsePassword:(BOOL)serverUsePasswordButton.state];
  70 +
  71 + [defaults setValue:[model serverName] forKey:@"SPServerName"];
  72 + [defaults setValue:[model serverPassword] forKey:@"SPServerPassword"];
  73 + [defaults setValue:[NSNumber numberWithBool:[model usePassword]] forKey:@"SPUsePassword"];
  74 +
  75 + [defaults synchronize];
  76 +
  77 + [self.window performClose:nil];
  78 +
  79 + // have to restart the server if the values have changed.
  80 +// if ([shairportTask isRunning]) {
  81 +// [self setServerRunning:NO];
  82 +//
  83 +// dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^(void) {
  84 +// sleep(1);
  85 +// [self setServerRunning:YES];
  86 +// });
  87 +// }
  88 +}
  89 +
  90 +@end
36 Classes/Models/ShairPortModel.h
... ... @@ -0,0 +1,36 @@
  1 +//
  2 +// ShairPortModel.h
  3 +// This file is part of ShairPortMenu.
  4 +//
  5 +// A Simple OS X GUI wrapper for ShairPort / HairTunes
  6 +//
  7 +// Copyright 2011 Robert Carlsen.
  8 +//
  9 +// ShairPortMenu is free software: you can redistribute it and/or modify
  10 +// it under the terms of the GNU General Public License as published by
  11 +// the Free Software Foundation, either version 3 of the License, or
  12 +// (at your option) any later version.
  13 +//
  14 +// ShairPortMenu is distributed in the hope that it will be useful,
  15 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 +// GNU General Public License for more details.
  18 +//
  19 +// You should have received a copy of the GNU General Public License
  20 +// along with ShairPortMenu. If not, see <http://www.gnu.org/licenses/>.
  21 +//
  22 +
  23 +#import <Foundation/Foundation.h>
  24 +
  25 +
  26 +@interface ShairPortModel : NSObject {
  27 + NSString *serverName;
  28 + NSString *serverPassword;
  29 + BOOL usePassword;
  30 +}
  31 +
  32 +@property(copy)NSString *serverName;
  33 +@property(copy)NSString *serverPassword;
  34 +@property BOOL usePassword;
  35 +
  36 +@end
56 Classes/Models/ShairPortModel.m
... ... @@ -0,0 +1,56 @@
  1 +//
  2 +// ShairPortModel.m
  3 +// This file is part of ShairPortMenu.
  4 +//
  5 +// A Simple OS X GUI wrapper for ShairPort / HairTunes
  6 +//
  7 +// Copyright 2011 Robert Carlsen.
  8 +//
  9 +// ShairPortMenu is free software: you can redistribute it and/or modify
  10 +// it under the terms of the GNU General Public License as published by
  11 +// the Free Software Foundation, either version 3 of the License, or
  12 +// (at your option) any later version.
  13 +//
  14 +// ShairPortMenu is distributed in the hope that it will be useful,
  15 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 +// GNU General Public License for more details.
  18 +//
  19 +// You should have received a copy of the GNU General Public License
  20 +// along with ShairPortMenu. If not, see <http://www.gnu.org/licenses/>.
  21 +//
  22 +
  23 +#import "ShairPortModel.h"
  24 +
  25 +
  26 +@implementation ShairPortModel
  27 +
  28 +@synthesize serverName, serverPassword, usePassword;
  29 +
  30 +-(id)init;
  31 +{
  32 + self = [super init];
  33 + if(self) {
  34 + // set up the defaults:
  35 + // cleartext passwd:
  36 + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  37 + [defaults registerDefaults:[NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Defaults" ofType:@"plist"]]];
  38 +
  39 + // init the model
  40 + // TODO: use coding to directly archive the model
  41 + self.serverName = [defaults stringForKey:@"SPServerName"];
  42 + self.serverPassword = [defaults stringForKey:@"SPServerPassword"];
  43 + self.usePassword = [defaults boolForKey:@"SPUsePassword"];
  44 + }
  45 + return self;
  46 +}
  47 +
  48 +-(void)dealloc;
  49 +{
  50 + [serverName release];
  51 + [serverPassword release];
  52 +
  53 + [super dealloc];
  54 +}
  55 +
  56 +@end
54 Classes/ShairPortMenuAppDelegate.h
... ... @@ -0,0 +1,54 @@
  1 +//
  2 +// ShairPortMenuAppDelegate.h
  3 +// This file is part of ShairPortMenu.
  4 +//
  5 +// A Simple OS X GUI wrapper for ShairPort / HairTunes
  6 +//
  7 +// Copyright 2011 Robert Carlsen.
  8 +//
  9 +// ShairPortMenu is free software: you can redistribute it and/or modify
  10 +// it under the terms of the GNU General Public License as published by
  11 +// the Free Software Foundation, either version 3 of the License, or
  12 +// (at your option) any later version.
  13 +//
  14 +// ShairPortMenu is distributed in the hope that it will be useful,
  15 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 +// GNU General Public License for more details.
  18 +//
  19 +// You should have received a copy of the GNU General Public License
  20 +// along with ShairPortMenu. If not, see <http://www.gnu.org/licenses/>.
  21 +//
  22 +
  23 +
  24 +
  25 +#import <Cocoa/Cocoa.h>
  26 +
  27 +#import "ShairPortController.h"
  28 +@class ShairPortModel;
  29 +
  30 +
  31 +@interface ShairPortMenuAppDelegate : NSObject
  32 +<NSApplicationDelegate, ShairPortControllerDelegate>
  33 +{
  34 + NSWindow *window;
  35 +
  36 + NSStatusItem *statusItem;
  37 + IBOutlet NSMenu *statusMenu;
  38 + IBOutlet NSMenuItem *controlMenuItem;
  39 + IBOutlet NSMenuItem *statusMenuItem;
  40 +
  41 + id aboutPanel;
  42 + id preferencesWindow;
  43 +
  44 + id shairPortController;
  45 +}
  46 +
  47 +@property (assign) IBOutlet NSWindow *window;
  48 +@property(nonatomic,retain)ShairPortModel *shairportModel;
  49 +
  50 +-(IBAction)listeningMenu:(id)sender;
  51 +-(IBAction)openAboutPanel:(id)sender;
  52 +-(IBAction)openPreferencesWindow:(id)sender;
  53 +
  54 +@end
167 Classes/ShairPortMenuAppDelegate.m
... ... @@ -0,0 +1,167 @@
  1 +//
  2 +// ShairPortMenuAppDelegate.m
  3 +// This file is part of ShairPortMenu.
  4 +//
  5 +// A Simple OS X GUI wrapper for ShairPort / HairTunes
  6 +//
  7 +// Copyright 2011 Robert Carlsen.
  8 +//
  9 +// ShairPortMenu is free software: you can redistribute it and/or modify
  10 +// it under the terms of the GNU General Public License as published by
  11 +// the Free Software Foundation, either version 3 of the License, or
  12 +// (at your option) any later version.
  13 +//
  14 +// ShairPortMenu is distributed in the hope that it will be useful,
  15 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 +// GNU General Public License for more details.
  18 +//
  19 +// You should have received a copy of the GNU General Public License
  20 +// along with ShairPortMenu. If not, see <http://www.gnu.org/licenses/>.
  21 +//
  22 +
  23 +#import "ShairPortMenuAppDelegate.h"
  24 +
  25 +#import "ShairPortModel.h"
  26 +#import "ShairPortController.h"
  27 +
  28 +#import "ShairPreferencesController.h"
  29 +#import "AboutPanelController.h"
  30 +
  31 +
  32 +@interface ShairPortMenuAppDelegate (private)
  33 +-(void)updateMenuForServer:(BOOL)isOn;
  34 +-(void)setTooltipStatus:(BOOL)_onOff;
  35 +@end
  36 +
  37 +
  38 +@implementation ShairPortMenuAppDelegate
  39 +
  40 +@synthesize window, shairportModel;
  41 +
  42 +
  43 +#pragma mark - Application Delegate
  44 +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
  45 + // Insert code here to initialize your application
  46 +
  47 + // set up the app data model
  48 + // TODO: use coding
  49 + self.shairportModel = [[ShairPortModel alloc] init];
  50 + shairPortController = [[ShairPortController alloc] init];
  51 + [shairPortController setDelegate:self];
  52 +}
  53 +
  54 +-(void)applicationWillTerminate:(NSNotification *)notification
  55 +{
  56 + [shairPortController setServerRunning:NO];
  57 +
  58 + // save defaults, then cleanup;
  59 + [shairPortController release];
  60 + [shairportModel release];
  61 +
  62 +}
  63 +
  64 +-(void)awakeFromNib{
  65 + statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength] retain];
  66 + [statusItem sendActionOn:NSLeftMouseDraggedMask];
  67 + [statusItem setMenu:statusMenu];
  68 + [statusItem setHighlightMode:YES];
  69 + [statusItem setAlternateImage:[NSImage imageNamed:@"hairplay-over"]];
  70 +
  71 +
  72 + [self updateMenuForServer:[shairPortController shairportTask].isRunning];
  73 +}
  74 +
  75 +
  76 +#pragma mark - Private methods
  77 +-(void)updateMenuForServer:(BOOL)isOn;
  78 +{
  79 + [self setTooltipStatus:isOn];
  80 +
  81 + if(isOn){
  82 + [statusItem setImage:[NSImage imageNamed:@"hairplay-on"]];
  83 +
  84 + [controlMenuItem setTitle:NSLocalizedString(@"Turn ShairPort off", "Menu item title")];
  85 + [controlMenuItem setState:1];
  86 + [statusMenuItem setTitle:[NSString stringWithFormat:
  87 + NSLocalizedString(@"ShairPort: %@", "Menu item title"),
  88 + shairportModel.serverName]];
  89 + }
  90 + else {
  91 + [self setTooltipStatus:isOn];
  92 +
  93 + [statusItem setImage:[NSImage imageNamed:@"hairplay-off"]];
  94 + [controlMenuItem setTitle:NSLocalizedString(@"Turn ShairPort on", "Menu item title")];
  95 + [controlMenuItem setState:0];
  96 + [statusMenuItem setTitle:NSLocalizedString(@"ShairPort: off", "Menu item title")];
  97 + }
  98 +}
  99 +
  100 +
  101 +
  102 +-(void)setTooltipStatus:(BOOL)_onOff;
  103 +{
  104 + NSString *tooltipTitle = NSLocalizedString(@"ShairPort Control", "Menulet tool tip title");
  105 + NSString *tooltipStatus = [NSString stringWithFormat:
  106 + NSLocalizedString(@"HairTunes is %@", "tooltip status"),
  107 + (_onOff) ? @"on" : @"off" ];
  108 + [statusItem setToolTip:[NSString stringWithFormat:@"%@\n%@",tooltipTitle,tooltipStatus]];
  109 +}
  110 +
  111 +
  112 +#pragma mark - Actions
  113 +-(IBAction)listeningMenu:(id)sender;
  114 +{
  115 + NSLog(@"Menu option: %ld",[sender state]);
  116 + switch ([sender state]) {
  117 + case 0:
  118 + [shairPortController setServerRunning:YES];
  119 + break;
  120 + case 1:
  121 + [shairPortController setServerRunning:NO];
  122 + break;
  123 + case 2:
  124 + break;
  125 + default:
  126 + break;
  127 + }
  128 +}
  129 +
  130 +-(IBAction)openAboutPanel:(id)sender;
  131 +{
  132 + NSLog(@"open about panel");
  133 +
  134 + if (aboutPanel == nil) {
  135 + aboutPanel = [[AboutPanelController alloc] initWithWindowNibName:@"AboutPanel"];
  136 + }
  137 +
  138 + [aboutPanel showWindow:nil];
  139 + [NSApp activateIgnoringOtherApps:YES];
  140 +}
  141 +
  142 +-(IBAction)openPreferencesWindow:(id)sender;
  143 +{
  144 + NSLog(@"open prefs window");
  145 +
  146 + if (preferencesWindow == nil) {
  147 + preferencesWindow = [[ShairPreferencesController alloc] initWithWindowNibName:@"ShairPreferencesWindow"];
  148 + }
  149 +
  150 + [preferencesWindow showWindow:nil];
  151 + [NSApp activateIgnoringOtherApps:YES];
  152 +}
  153 +
  154 +
  155 +#pragma mark - ShairPortController delegate
  156 +-(void)shairPortStarted;
  157 +{
  158 + [self updateMenuForServer:YES];
  159 +}
  160 +
  161 +-(void)shairPortStopped;
  162 +{
  163 + [self updateMenuForServer:NO];
  164 +}
  165 +
  166 +
  167 +@end
485 Classes/Views/AboutPanel.xib
... ... @@ -0,0 +1,485 @@
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
  3 + <data>
  4 + <int key="IBDocument.SystemTarget">1060</int>
  5 + <string key="IBDocument.SystemVersion">10J3250</string>
  6 + <string key="IBDocument.InterfaceBuilderVersion">1306</string>
  7 + <string key="IBDocument.AppKitVersion">1038.35</string>
  8 + <string key="IBDocument.HIToolboxVersion">461.00</string>
  9 + <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
  10 + <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
  11 + <string key="NS.object.0">1306</string>
  12 + </object>
  13 + <object class="NSArray" key="IBDocument.IntegratedClassDependencies">
  14 + <bool key="EncodedWithXMLCoder">YES</bool>
  15 + <string>NSView</string>
  16 + <string>NSTextField</string>
  17 + <string>NSScrollView</string>
  18 + <string>NSWindowTemplate</string>
  19 + <string>NSTextFieldCell</string>
  20 + <string>NSTextView</string>
  21 + <string>NSScroller</string>
  22 + <string>NSCustomObject</string>
  23 + </object>
  24 + <object class="NSArray" key="IBDocument.PluginDependencies">
  25 + <bool key="EncodedWithXMLCoder">YES</bool>
  26 + <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
  27 + </object>
  28 + <object class="NSMutableDictionary" key="IBDocument.Metadata">
  29 + <bool key="EncodedWithXMLCoder">YES</bool>
  30 + <object class="NSArray" key="dict.sortedKeys" id="0">
  31 + <bool key="EncodedWithXMLCoder">YES</bool>
  32 + </object>
  33 + <reference key="dict.values" ref="0"/>
  34 + </object>
  35 + <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
  36 + <bool key="EncodedWithXMLCoder">YES</bool>
  37 + <object class="NSCustomObject" id="1001">
  38 + <string key="NSClassName">AboutPanelController</string>
  39 + </object>
  40 + <object class="NSCustomObject" id="1003">
  41 + <string key="NSClassName">FirstResponder</string>
  42 + </object>
  43 + <object class="NSCustomObject" id="1004">
  44 + <string key="NSClassName">NSApplication</string>
  45 + </object>
  46 + <object class="NSWindowTemplate" id="166824799">
  47 + <int key="NSWindowStyleMask">271</int>
  48 + <int key="NSWindowBacking">2</int>
  49 + <string key="NSWindowRect">{{102, 528}, {431, 230}}</string>
  50 + <int key="NSWTFlags">-1535639552</int>
  51 + <string key="NSWindowTitle">About ShairPort Menu</string>
  52 + <string key="NSWindowClass">NSPanel</string>
  53 + <nil key="NSViewClass"/>
  54 + <string key="NSWindowContentMaxSize">{600, 400}</string>
  55 + <string key="NSWindowContentMinSize">{431, 200}</string>
  56 + <object class="NSView" key="NSWindowView" id="851737080">
  57 + <reference key="NSNextResponder"/>
  58 + <int key="NSvFlags">256</int>
  59 + <object class="NSMutableArray" key="NSSubviews">
  60 + <bool key="EncodedWithXMLCoder">YES</bool>
  61 + <object class="NSTextField" id="1018652184">
  62 + <reference key="NSNextResponder" ref="851737080"/>
  63 + <int key="NSvFlags">265</int>
  64 + <string key="NSFrame">{{277, 218}, {135, 11}}</string>
  65 + <reference key="NSSuperview" ref="851737080"/>
  66 + <reference key="NSWindow"/>
  67 + <reference key="NSNextKeyView" ref="1035560772"/>
  68 + <int key="NSViewLayerContentsRedrawPolicy">2</int>
  69 + <bool key="NSEnabled">YES</bool>
  70 + <object class="NSTextFieldCell" key="NSCell" id="885947397">
  71 + <int key="NSCellFlags">68288064</int>
  72 + <int key="NSCellFlags2">71304192</int>
  73 + <string key="NSContents">#version</string>
  74 + <object class="NSFont" key="NSSupport">
  75 + <string key="NSName">LucidaGrande</string>
  76 + <double key="NSSize">9</double>
  77 + <int key="NSfFlags">16</int>
  78 + </object>
  79 + <reference key="NSControlView" ref="1018652184"/>
  80 + <object class="NSColor" key="NSBackgroundColor">
  81 + <int key="NSColorSpace">6</int>
  82 + <string key="NSCatalogName">System</string>
  83 + <string key="NSColorName">controlColor</string>
  84 + <object class="NSColor" key="NSColor" id="353341875">
  85 + <int key="NSColorSpace">3</int>
  86 + <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
  87 + </object>
  88 + </object>
  89 + <object class="NSColor" key="NSTextColor">
  90 + <int key="NSColorSpace">6</int>
  91 + <string key="NSCatalogName">System</string>
  92 + <string key="NSColorName">controlTextColor</string>
  93 + <object class="NSColor" key="NSColor" id="180817943">
  94 + <int key="NSColorSpace">3</int>
  95 + <bytes key="NSWhite">MAA</bytes>
  96 + </object>
  97 + </object>
  98 + </object>
  99 + </object>
  100 + <object class="NSScrollView" id="1035560772">
  101 + <reference key="NSNextResponder" ref="851737080"/>
  102 + <int key="NSvFlags">274</int>
  103 + <object class="NSMutableArray" key="NSSubviews">
  104 + <bool key="EncodedWithXMLCoder">YES</bool>
  105 + <object class="NSClipView" id="725516723">
  106 + <reference key="NSNextResponder" ref="1035560772"/>
  107 + <int key="NSvFlags">2304</int>
  108 + <object class="NSMutableArray" key="NSSubviews">
  109 + <bool key="EncodedWithXMLCoder">YES</bool>
  110 + <object class="NSTextView" id="83581019">
  111 + <reference key="NSNextResponder" ref="725516723"/>
  112 + <int key="NSvFlags">2322</int>
  113 + <string key="NSFrameSize">{389, 0}</string>
  114 + <reference key="NSSuperview" ref="725516723"/>
  115 + <reference key="NSWindow"/>
  116 + <reference key="NSNextKeyView"/>
  117 + <int key="NSViewLayerContentsRedrawPolicy">2</int>
  118 + <object class="NSTextContainer" key="NSTextContainer" id="969239895">
  119 + <object class="NSLayoutManager" key="NSLayoutManager">
  120 + <object class="NSTextStorage" key="NSTextStorage">
  121 + <object class="NSMutableString" key="NSString">
  122 + <characters key="NS.bytes"/>
  123 + </object>
  124 + <nil key="NSDelegate"/>
  125 + </object>
  126 + <object class="NSMutableArray" key="NSTextContainers">
  127 + <bool key="EncodedWithXMLCoder">YES</bool>
  128 + <reference ref="969239895"/>
  129 + </object>
  130 + <int key="NSLMFlags">134</int>
  131 + <nil key="NSDelegate"/>
  132 + </object>
  133 + <reference key="NSTextView" ref="83581019"/>
  134 + <double key="NSWidth">389</double>
  135 + <int key="NSTCFlags">1</int>
  136 + </object>
  137 + <object class="NSTextViewSharedData" key="NSSharedData">
  138 + <int key="NSFlags">46149509</int>
  139 + <int key="NSTextCheckingTypes">0</int>
  140 + <nil key="NSMarkedAttributes"/>
  141 + <object class="NSColor" key="NSBackgroundColor" id="358233471">
  142 + <int key="NSColorSpace">6</int>
  143 + <string key="NSCatalogName">System</string>
  144 + <string key="NSColorName">textBackgroundColor</string>
  145 + <object class="NSColor" key="NSColor">
  146 + <int key="NSColorSpace">3</int>
  147 + <bytes key="NSWhite">MQA</bytes>
  148 + </object>
  149 + </object>
  150 + <object class="NSDictionary" key="NSSelectedAttributes">
  151 + <bool key="EncodedWithXMLCoder">YES</bool>
  152 + <object class="NSArray" key="dict.sortedKeys">
  153 + <bool key="EncodedWithXMLCoder">YES</bool>
  154 + <string>NSBackgroundColor</string>
  155 + <string>NSColor</string>
  156 + </object>
  157 + <object class="NSMutableArray" key="dict.values">
  158 + <bool key="EncodedWithXMLCoder">YES</bool>
  159 + <object class="NSColor">
  160 + <int key="NSColorSpace">6</int>
  161 + <string key="NSCatalogName">System</string>
  162 + <string key="NSColorName">selectedTextBackgroundColor</string>
  163 + <reference key="NSColor" ref="353341875"/>
  164 + </object>
  165 + <object class="NSColor">
  166 + <int key="NSColorSpace">6</int>
  167 + <string key="NSCatalogName">System</string>
  168 + <string key="NSColorName">selectedTextColor</string>
  169 + <reference key="NSColor" ref="180817943"/>
  170 + </object>
  171 + </object>
  172 + </object>
  173 + <reference key="NSInsertionColor" ref="180817943"/>
  174 + <object class="NSDictionary" key="NSLinkAttributes">
  175 + <bool key="EncodedWithXMLCoder">YES</bool>
  176 + <object class="NSArray" key="dict.sortedKeys">
  177 + <bool key="EncodedWithXMLCoder">YES</bool>
  178 + <string>NSColor</string>
  179 + <string>NSCursor</string>
  180 + <string>NSUnderline</string>
  181 + </object>
  182 + <object class="NSMutableArray" key="dict.values">
  183 + <bool key="EncodedWithXMLCoder">YES</bool>
  184 + <object class="NSColor">
  185 + <int key="NSColorSpace">1</int>
  186 + <bytes key="NSRGB">MCAwIDEAA</bytes>
  187 + </object>
  188 + <object class="NSCursor">
  189 + <string key="NSHotSpot">{8, -8}</string>
  190 + <int key="NSCursorType">13</int>
  191 + </object>
  192 + <integer value="1"/>
  193 + </object>
  194 + </object>
  195 + <nil key="NSDefaultParagraphStyle"/>
  196 + </object>
  197 + <int key="NSTVFlags">6</int>
  198 + <string key="NSMaxSize">{600, 1e+07}</string>
  199 + <string key="NSMinize">{200, 0}</string>
  200 + <nil key="NSDelegate"/>
  201 + </object>
  202 + </object>
  203 + <string key="NSFrame">{{1, 1}, {389, 188}}</string>
  204 + <reference key="NSSuperview" ref="1035560772"/>
  205 + <reference key="NSWindow"/>
  206 + <reference key="NSNextKeyView" ref="83581019"/>
  207 + <int key="NSViewLayerContentsRedrawPolicy">2</int>
  208 + <reference key="NSDocView" ref="83581019"/>
  209 + <reference key="NSBGColor" ref="358233471"/>
  210 + <object class="NSCursor" key="NSCursor">
  211 + <string key="NSHotSpot">{4, -5}</string>
  212 + <int key="NSCursorType">1</int>
  213 + </object>
  214 + <int key="NScvFlags">4</int>
  215 + </object>
  216 + <object class="NSScroller" id="152104600">
  217 + <reference key="NSNextResponder" ref="1035560772"/>
  218 + <int key="NSvFlags">-2147483392</int>
  219 + <string key="NSFrame">{{-100, -100}, {15, 225}}</string>
  220 + <reference key="NSSuperview" ref="1035560772"/>
  221 + <reference key="NSWindow"/>
  222 + <reference key="NSNextKeyView" ref="822743387"/>
  223 + <int key="NSViewLayerContentsRedrawPolicy">2</int>
  224 + <reference key="NSTarget" ref="1035560772"/>
  225 + <string key="NSAction">_doScroller:</string>
  226 + <double key="NSCurValue">1</double>
  227 + <double key="NSPercent">0.85256409645080566</double>
  228 + </object>
  229 + <object class="NSScroller" id="822743387">
  230 + <reference key="NSNextResponder" ref="1035560772"/>
  231 + <int key="NSvFlags">-2147483392</int>
  232 + <string key="NSFrame">{{-100, -100}, {87, 18}}</string>
  233 + <reference key="NSSuperview" ref="1035560772"/>
  234 + <reference key="NSWindow"/>
  235 + <reference key="NSNextKeyView" ref="725516723"/>
  236 + <int key="NSViewLayerContentsRedrawPolicy">2</int>
  237 + <int key="NSsFlags">1</int>
  238 + <reference key="NSTarget" ref="1035560772"/>
  239 + <string key="NSAction">_doScroller:</string>
  240 + <double key="NSCurValue">1</double>
  241 + <double key="NSPercent">0.94565218687057495</double>
  242 + </object>
  243 + </object>
  244 + <string key="NSFrame">{{20, 20}, {391, 190}}</string>
  245 + <reference key="NSSuperview" ref="851737080"/>
  246 + <reference key="NSWindow"/>
  247 + <reference key="NSNextKeyView" ref="152104600"/>
  248 + <int key="NSViewLayerContentsRedrawPolicy">2</int>
  249 + <int key="NSsFlags">530</int>
  250 + <reference key="NSVScroller" ref="152104600"/>
  251 + <reference key="NSHScroller" ref="822743387"/>
  252 + <reference key="NSContentView" ref="725516723"/>
  253 + </object>
  254 + </object>
  255 + <string key="NSFrame">{{7, 11}, {431, 230}}</string>
  256 + <reference key="NSSuperview"/>
  257 + <reference key="NSWindow"/>
  258 + <reference key="NSNextKeyView" ref="1018652184"/>
  259 + <int key="NSViewLayerContentsRedrawPolicy">2</int>
  260 + </object>
  261 + <string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
  262 + <string key="NSMinSize">{431, 222}</string>
  263 + <string key="NSMaxSize">{600, 422}</string>
  264 + </object>
  265 + </object>
  266 + <object class="IBObjectContainer" key="IBDocument.Objects">
  267 + <object class="NSMutableArray" key="connectionRecords">
  268 + <bool key="EncodedWithXMLCoder">YES</bool>
  269 + <object class="IBConnectionRecord">
  270 + <object class="IBOutletConnection" key="connection">
  271 + <string key="label">window</string>
  272 + <reference key="source" ref="1001"/>
  273 + <reference key="destination" ref="166824799"/>
  274 + </object>
  275 + <int key="connectionID">9</int>
  276 + </object>
  277 + <object class="IBConnectionRecord">
  278 + <object class="IBOutletConnection" key="connection">
  279 + <string key="label">aboutTextView</string>
  280 + <reference key="source" ref="1001"/>
  281 + <reference key="destination" ref="83581019"/>
  282 + </object>
  283 + <int key="connectionID">10</int>
  284 + </object>
  285 + <object class="IBConnectionRecord">
  286 + <object class="IBOutletConnection" key="connection">
  287 + <string key="label">versionLabel</string>
  288 + <reference key="source" ref="1001"/>
  289 + <reference key="destination" ref="1018652184"/>
  290 + </object>
  291 + <int key="connectionID">13</int>
  292 + </object>
  293 + </object>
  294 + <object class="IBMutableOrderedSet" key="objectRecords">
  295 + <object class="NSArray" key="orderedObjects">
  296 + <bool key="EncodedWithXMLCoder">YES</bool>
  297 + <object class="IBObjectRecord">
  298 + <int key="objectID">0</int>
  299 + <reference key="object" ref="0"/>
  300 + <reference key="children" ref="1000"/>
  301 + <nil key="parent"/>
  302 + </object>
  303 + <object class="IBObjectRecord">
  304 + <int key="objectID">-2</int>
  305 + <reference key="object" ref="1001"/>
  306 + <reference key="parent" ref="0"/>
  307 + <string key="objectName">File's Owner</string>
  308 + </object>
  309 + <object class="IBObjectRecord">
  310 + <int key="objectID">-1</int>
  311 + <reference key="object" ref="1003"/>
  312 + <reference key="parent" ref="0"/>
  313 + <string key="objectName">First Responder</string>
  314 + </object>
  315 + <object class="IBObjectRecord">
  316 + <int key="objectID">-3</int>
  317 + <reference key="object" ref="1004"/>
  318 + <reference key="parent" ref="0"/>
  319 + <string key="objectName">Application</string>
  320 + </object>
  321 + <object class="IBObjectRecord">
  322 + <int key="objectID">3</int>
  323 + <reference key="object" ref="166824799"/>
  324 + <object class="NSMutableArray" key="children">
  325 + <bool key="EncodedWithXMLCoder">YES</bool>
  326 + <reference ref="851737080"/>
  327 + </object>
  328 + <reference key="parent" ref="0"/>
  329 + <string key="objectName">Panel - About Window</string>
  330 + </object>
  331 + <object class="IBObjectRecord">
  332 + <int key="objectID">4</int>
  333 + <reference key="object" ref="851737080"/>
  334 + <object class="NSMutableArray" key="children">
  335 + <bool key="EncodedWithXMLCoder">YES</bool>
  336 + <reference ref="1035560772"/>
  337 + <reference ref="1018652184"/>
  338 + </object>
  339 + <reference key="parent" ref="166824799"/>
  340 + </object>
  341 + <object class="IBObjectRecord">
  342 + <int key="objectID">5</int>
  343 + <reference key="object" ref="1035560772"/>
  344 + <object class="NSMutableArray" key="children">
  345 + <bool key="EncodedWithXMLCoder">YES</bool>
  346 + <reference ref="83581019"/>
  347 + <reference ref="822743387"/>
  348 + <reference ref="152104600"/>
  349 + </object>
  350 + <reference key="parent" ref="851737080"/>
  351 + </object>
  352 + <object class="IBObjectRecord">
  353 + <int key="objectID">6</int>
  354 + <reference key="object" ref="83581019"/>
  355 + <reference key="parent" ref="1035560772"/>
  356 + <string key="objectName">Text View</string>
  357 + </object>
  358 + <object class="IBObjectRecord">
  359 + <int key="objectID">7</int>
  360 + <reference key="object" ref="822743387"/>
  361 + <reference key="parent" ref="1035560772"/>
  362 + </object>
  363 + <object class="IBObjectRecord">
  364 + <int key="objectID">8</int>
  365 + <reference key="object" ref="152104600"/>