From 93ac6a696a382a4daaaa6191dc87c632879958d1 Mon Sep 17 00:00:00 2001 From: Bob Ippolito Date: Sun, 23 Jun 2002 04:40:07 +0000 Subject: [PATCH] Major changes to the favorites system. Menus and outline view should work pretty much as expected now, except that it does not save because it's been disentangled from the STL vector implementation and I haven't written the serialization code yet, but it will be pretty easy. Uses a tree implementation, unlimited folder depth, no problems with multiple folders at the same level with the same name. Added boundaries.cpp/h to the pbproj. Changes don't touch any non-OSX portions of the codebase. --- macosx/CelestiaAppCore.h | 2 +- macosx/CelestiaAppCore.mm | 26 +- macosx/CelestiaController.m | 6 +- macosx/CelestiaFavorite.h | 35 +-- macosx/CelestiaFavorite.mm | 286 +++--------------- macosx/CelestiaFavorite_PrivateAPI.h | 9 +- macosx/CelestiaFavorites.h | 20 ++ macosx/CelestiaFavorites.m | 53 ++++ macosx/ContextOutlineView.h | 1 + macosx/English.lproj/MainMenu.nib/classes.nib | 3 +- macosx/English.lproj/MainMenu.nib/info.nib | 10 +- macosx/English.lproj/MainMenu.nib/objects.nib | Bin 14993 -> 15085 bytes macosx/FavoriteInfoWindowController.m | 5 +- macosx/FavoritesDrawerController.h | 25 +- macosx/FavoritesDrawerController.m | 277 +++++++++-------- macosx/MyTree.h | 62 ++++ macosx/MyTree.m | 279 +++++++++++++++++ macosx/celestia.pbproj/project.pbxproj | 80 +++++ 18 files changed, 737 insertions(+), 442 deletions(-) create mode 100644 macosx/CelestiaFavorites.h create mode 100644 macosx/CelestiaFavorites.m create mode 100644 macosx/MyTree.h create mode 100644 macosx/MyTree.m diff --git a/macosx/CelestiaAppCore.h b/macosx/CelestiaAppCore.h index 3148ff1a..6996fcaf 100644 --- a/macosx/CelestiaAppCore.h +++ b/macosx/CelestiaAppCore.h @@ -10,11 +10,11 @@ #import "CelestiaDestination.h" #import "CelestiaFavorite.h" +#import "CelestiaFavorites.h" #import "CelestiaSimulation.h" #import "CelestiaRenderer.h" @interface CelestiaAppCore : NSObject { - CelestiaFavorites* _favorites; CelestiaDestinations* _destinations; } +(CelestiaAppCore *)sharedAppCore; diff --git a/macosx/CelestiaAppCore.mm b/macosx/CelestiaAppCore.mm index 107fa686..227b0cd7 100644 --- a/macosx/CelestiaAppCore.mm +++ b/macosx/CelestiaAppCore.mm @@ -32,8 +32,6 @@ runScript(CommandSequence *); CommandParser CommandSequence -do addFavorites - */ CelestiaAppCore *_sharedCelestiaAppCore; @@ -75,17 +73,12 @@ void ContextMenuCallback(float x,float y, Selection selection) { self = [super init]; appCore = new CelestiaCore(); contextMenuCallbackInvocation = NULL; - _favorites = nil; _destinations = nil; return self; } - (void)dealloc { - if (_favorites != nil) { - [_favorites release]; - _favorites = nil; - } if (_destinations != nil) { [_destinations release]; _destinations = nil; @@ -193,18 +186,6 @@ void ContextMenuCallback(float x,float y, Selection selection) { appCore->showText([text stdString]); } --(void)readFavoritesFile -{ -// Will do this with MacOS X functionality soon - appCore->readFavoritesFile(); -} - --(void)writeFavoritesFile -{ -// Will do this with MacOS X functionality soon - appCore->writeFavoritesFile(); -} - -(void)activateFavorite:(id)fav { //NSLog(@"[CelestiaAppCore activateFavorite:%@]",fav); @@ -215,12 +196,7 @@ void ContextMenuCallback(float x,float y, Selection selection) { -(CelestiaFavorites *)favorites { - if (_favorites == nil || [_favorites favorites] != appCore->getFavorites()) { - if (_favorites != nil) - [_favorites release]; - _favorites = [[CelestiaFavorites alloc] initWithFavorites:appCore->getFavorites()]; - } - return _favorites; + return [CelestiaFavorites sharedFavorites]; } -(CelestiaDestinations *)destinations diff --git a/macosx/CelestiaController.m b/macosx/CelestiaController.m index bf6475bb..f8d516da 100644 --- a/macosx/CelestiaController.m +++ b/macosx/CelestiaController.m @@ -97,10 +97,10 @@ // Set the simulation starting time to the current system time [appCore start:[NSDate date] withTimeZone:[NSTimeZone defaultTimeZone]]; ready = YES; - menuCallback = [NSInvocation invocationWithMethodSignature:[FavoritesDrawerController instanceMethodSignatureForSelector:@selector(synchronizeFavoritesMenu:)]]; - [menuCallback setSelector:@selector(synchronizeFavoritesMenu:)]; + menuCallback = [NSInvocation invocationWithMethodSignature:[FavoritesDrawerController instanceMethodSignatureForSelector:@selector(synchronizeFavoritesMenu)]]; + [menuCallback setSelector:@selector(synchronizeFavoritesMenu)]; [menuCallback setTarget:favoritesDrawerController]; - [[appCore favorites] setSynchronize:menuCallback]; + [[CelestiaFavorites sharedFavorites] setSynchronize:menuCallback]; } - (void)dealloc diff --git a/macosx/CelestiaFavorite.h b/macosx/CelestiaFavorite.h index eeaba213..3fff9d26 100644 --- a/macosx/CelestiaFavorite.h +++ b/macosx/CelestiaFavorite.h @@ -9,11 +9,18 @@ #import #import "CelestiaUniversalCoord.h" +// parentFolder is totally vestigal crap + @interface CelestiaFavorite : NSObject { NSValue* _data; + BOOL _freeWhenDone; } -//-(void)activate:(id)sender; +-(void)activate; -(void)setName:(NSString*)name; +-(id)initWithName:(NSString*)name; +-(id)initWithName:(NSString*)name parentFolder:(CelestiaFavorite*)folder; +-(id)initWithFolderName:(NSString*)name; +-(id)initWithFolderName:(NSString*)name parentFolder:(CelestiaFavorite*)folder; -(NSString*)name; -(NSString*)selectionName; -(CelestiaUniversalCoord*)position; @@ -30,30 +37,4 @@ -(void)setName:(NSString*)name; -(NSString*)selectionName; -(NSString*)coordinateSystem; -@end - - -@interface CelestiaFavorites : NSMutableArray { - NSValue* _data; - NSMutableArray* _retain; -} --(void)synchronize; --(void)setSynchronize:(NSInvocation*)sync; --(unsigned)count; --(id)objectAtIndex:(unsigned)index; --(void)addObject:(CelestiaFavorite*)o; --(void)insertObject:(CelestiaFavorite*)o atIndex:(unsigned)index; --(void)removeLastObject; --(void)removeObjectAtIndex:(unsigned)index; --(void)replaceObjectAtIndex:(unsigned)index withObject:(CelestiaFavorite*)o; --(unsigned)depthAtIndex:(unsigned)idx; --(unsigned)firstIndexWithParentFolder:(CelestiaFavorite*)folder; --(unsigned)lastIndexWithParentFolder:(CelestiaFavorite*)folder; --(void)addNewFavorite:(NSString*)name withParentFolder:(CelestiaFavorite*)folder atIndex:(unsigned)idx; --(void)addNewFavorite:(NSString*)name withParentFolder:(CelestiaFavorite*)folder; --(void)addNewFolder:(NSString*)name withParentFolder:(CelestiaFavorite*)parentFolder atIndex:(unsigned)idx; --(void)addNewFolder:(NSString*)name withParentFolder:(CelestiaFavorite*)parentFolder; --(id)objectAtIndex:(unsigned)index parent:(CelestiaFavorite*)parent; --(unsigned)numberOfChildrenOfItem:(CelestiaFavorite*)folder; - @end \ No newline at end of file diff --git a/macosx/CelestiaFavorite.mm b/macosx/CelestiaFavorite.mm index f73b9791..9b0f731c 100644 --- a/macosx/CelestiaFavorite.mm +++ b/macosx/CelestiaFavorite.mm @@ -16,14 +16,12 @@ #import "CelestiaSimulation.h" #import "CelestiaSimulation_PrivateAPI.h" -NSInvocation *_synchronize; - @implementation CelestiaFavorite(PrivateAPI) - -(CelestiaFavorite *)initWithFavorite:(FavoritesEntry *)fav { self = [super init]; _data = [[NSValue alloc] initWithBytes:reinterpret_cast(&fav) objCType:@encode(FavoritesEntry*)]; + _freeWhenDone = NO; return self; } -(FavoritesEntry *)favorite @@ -32,21 +30,53 @@ NSInvocation *_synchronize; } @end -@implementation CelestiaFavorites(PrivateAPI) --(CelestiaFavorites *)initWithFavorites:(const FavoritesList *)dsts +@implementation CelestiaFavorite +-(void)activate { - self = [super init]; - _data = [[NSValue alloc] initWithBytes:reinterpret_cast(&dsts) objCType:@encode(FavoritesList*)]; - _retain = [[NSMutableArray arrayWithCapacity:[self count]] retain]; + [[CelestiaAppCore sharedAppCore] activateFavorite:self]; +} +-(id)initWithName:(NSString*)name +{ + return [self initWithName:name parentFolder:nil]; +} +-(id)initWithFolderName:(NSString*)name +{ + return [self initWithFolderName:name parentFolder:nil]; +} +-(id)initWithFolderName:(NSString*)name parentFolder:(CelestiaFavorite*)folder +{ + FavoritesEntry* fav = new FavoritesEntry(); + NSString *parentFolder = (folder == nil) ? @"" : [folder name]; + if (name == nil || [name isEqualToString:@""]) + name = @"untitled folder"; + fav->name = [name stdString]; + fav->isFolder = true; + fav->parentFolder = [parentFolder stdString]; + self = [self initWithFavorite:fav]; + _freeWhenDone = YES; return self; } --(FavoritesList *)favorites +-(id)initWithName:(NSString*)name parentFolder:(CelestiaFavorite*)folder { - return reinterpret_cast([_data pointerValue]); + FavoritesEntry* fav = new FavoritesEntry(); + Simulation* sim = [[[CelestiaAppCore sharedAppCore] simulation] simulation]; + NSString *parentFolder = (folder == nil) ? @"" : [folder name]; + if (name == nil) + name = [[[[CelestiaAppCore sharedAppCore] simulation] selection] name]; + if (name == nil) + name = [[[[CelestiaAppCore sharedAppCore] simulation] julianDate] description]; + fav->jd = sim->getTime(); + fav->position = sim->getObserver().getPosition(); + fav->orientation = sim->getObserver().getOrientation(); + fav->name = [name stdString]; + fav->isFolder = false; + fav->parentFolder = [parentFolder stdString]; + fav->selectionName = sim->getSelection().getName(); + fav->coordSys = sim->getFrame().coordSys; + self = [self initWithFavorite:fav]; + _freeWhenDone = YES; + return self; } -@end - -@implementation CelestiaFavorite -(unsigned)hash { return (unsigned)[_data pointerValue]; @@ -54,6 +84,10 @@ NSInvocation *_synchronize; -(void)dealloc { if (_data != nil) { + if (_freeWhenDone) { + FavoritesEntry* fav = [self favorite]; + delete fav; + } [_data release]; _data = nil; } @@ -61,15 +95,7 @@ NSInvocation *_synchronize; } -(BOOL)isEqualToFavorite:(CelestiaFavorite*)fav { - /* - return ( - [[self name] isEqualToString:[fav name]] && - [[self parentFolder] isEqualToString:[fav parentFolder]] && - [[self selectionName] isEqualToString:[fav selectionName]] && - ([self isFolder] == [fav isFolder]) && - [[self jd] isEqualToNumber:[fav jd]] - ); - */ + // pointer equality is enough in this case return ([self favorite] == [fav favorite]); } -(BOOL)isEqualToString:(NSString*)str @@ -135,220 +161,4 @@ NSInvocation *_synchronize; { return [Astro stringWithCoordinateSystem:[NSNumber numberWithInt:(int)[self favorite]->coordSys]]; } -@end - -@implementation CelestiaFavorites -+(void)initialize -{ - _synchronize = nil; -} - --(unsigned)depthAtIndex:(unsigned)idx -{ - unsigned i,d; - NSString *lastName=@""; - d=0; - for(i=0;i<=idx;++i) { - CelestiaFavorite* fav = [self objectAtIndex:i]; - if ([[fav parentFolder] isEqualToString:@""]) { - d=0; - } else if ([[fav parentFolder] isEqualToString:lastName] && [lastName length]>0) { - ++d; - } else { - --d; - } - lastName = [fav name]; - } - return d; -} --(id)objectAtIndex:(unsigned)index parent:(CelestiaFavorite*)parent -{ - /* FIXME, needs to step over children folders */ - unsigned idx = 0; - if (parent != nil) { - idx = [self firstIndexWithParentFolder:parent]; - if (idx == NSNotFound) return nil; - } - return [self objectAtIndex:(index+idx)]; -} --(unsigned)firstIndexWithParentFolder:(CelestiaFavorite*)folder -{ - unsigned begin; - NSString *folderName; - if (folder == nil) return 0; - folderName = [folder name]; - begin = [self indexOfObjectIdenticalTo:folder]; - if (begin == NSNotFound) - return NSNotFound; - return ++begin; -} --(unsigned)lastIndexWithParentFolder:(CelestiaFavorite*)folder -{ - /* FIXME, needs to step over children folders */ - unsigned begin,end,i; - NSString *folderName; - if (folder == nil) - return [self count]; - folderName = [folder name]; - begin = [self indexOfObjectIdenticalTo:folder]; - if (begin == NSNotFound) - return NSNotFound; - end = [self count]; - for (i=++begin;ijd = sim->getTime(); - fav->position = sim->getObserver().getPosition(); - fav->orientation = sim->getObserver().getOrientation(); - fav->name = [name stdString]; - fav->isFolder = false; - fav->parentFolder = [parentFolder stdString]; - fav->selectionName = sim->getSelection().getName(); - fav->coordSys = sim->getFrame().coordSys; - [self insertObject:cfav atIndex:idx]; -} - --(void)addNewFavorite:(NSString*)name withParentFolder:(CelestiaFavorite*)folder -{ - unsigned idx; - FavoritesEntry* fav = new FavoritesEntry(); - CelestiaFavorite* cfav = [[[CelestiaFavorite alloc] initWithFavorite:fav] autorelease]; - Simulation* sim = [[[CelestiaAppCore sharedAppCore] simulation] simulation]; - NSString *parentFolder = (folder == nil) ? @"" : [folder name]; - if (name == nil) - name = [[[[CelestiaAppCore sharedAppCore] simulation] selection] name]; - if (name == nil) - name = [[[[CelestiaAppCore sharedAppCore] simulation] julianDate] description]; - NSLog(@"[CelestiaFavorites addNewFavorite:%@ inFolder:%@]",name,folder); - fav->jd = sim->getTime(); - fav->position = sim->getObserver().getPosition(); - fav->orientation = sim->getObserver().getOrientation(); - fav->name = [name stdString]; - fav->isFolder = false; - fav->parentFolder = [parentFolder stdString]; - fav->selectionName = sim->getSelection().getName(); - fav->coordSys = sim->getFrame().coordSys; - idx = [self lastIndexWithParentFolder:folder]; - [self insertObject:cfav atIndex:((idx==NSNotFound)?[self count]:idx)]; -} --(void)addNewFolder:(NSString*)name withParentFolder:(CelestiaFavorite*)folder atIndex:(unsigned)idx -{ - FavoritesEntry* fav = new FavoritesEntry(); - CelestiaFavorite* cfav = [[[CelestiaFavorite alloc] initWithFavorite:fav] autorelease]; - NSString *parentFolder = ((folder == nil) ? @"" : [folder name]); - fav->parentFolder = [parentFolder stdString]; - fav->isFolder = true; - fav->name = [name stdString]; - [self insertObject:cfav atIndex:idx]; -} --(void)addNewFolder:(NSString*)name withParentFolder:(CelestiaFavorite*)folder -{ - unsigned idx; - FavoritesEntry* fav = new FavoritesEntry(); - CelestiaFavorite* cfav = [[[CelestiaFavorite alloc] initWithFavorite:fav] autorelease]; - NSString *parentFolder = (folder == nil) ? @"" : [folder name]; - fav->parentFolder = [parentFolder stdString]; - fav->isFolder = true; - fav->name = [name stdString]; - idx = [self firstIndexWithParentFolder:folder]; - [self insertObject:cfav atIndex:idx]; -} --(unsigned)count -{ - if (![self favorites]) - return 0; - return [self favorites]->size(); -} --(id)objectAtIndex:(unsigned)index -{ - CelestiaFavorite* orig = [[[CelestiaFavorite alloc] initWithFavorite:(*[self favorites])[index]] autorelease]; - unsigned idx = [_retain indexOfObject:orig]; - if (idx == NSNotFound) { - [_retain addObject:orig]; - return orig; - } - return [_retain objectAtIndex:idx]; -} --(void)addObject:(CelestiaFavorite*)o -{ - [_retain addObject:o]; - [self favorites]->push_back([o favorite]); - [self synchronize]; -} --(void)insertObject:(CelestiaFavorite*)o atIndex:(unsigned)index -{ - [_retain addObject:o]; - [self favorites]->insert([self favorites]->begin()+index, [o favorite]); - [self synchronize]; -} --(void)removeLastObject -{ - [_retain removeObject:[self lastObject]]; - [self favorites]->pop_back(); - [self synchronize]; -} --(void)removeObjectAtIndex:(unsigned)index -{ - [_retain removeObject:[self objectAtIndex:index]]; - [self favorites]->erase([self favorites]->begin()+index); - [self synchronize]; -} --(void)replaceObjectAtIndex:(unsigned)index withObject:(CelestiaFavorite*)o -{ - [self removeObjectAtIndex:index]; - [self insertObject:o atIndex:index]; -} --(void)setSynchronize:(NSInvocation*)sync -{ - if (_synchronize != nil) { - [_synchronize release]; - _synchronize = nil; - } - _synchronize = [sync retain]; - [_synchronize setArgument:&self atIndex:2]; -} --(void)synchronize -{ - NSLog(@"[CelestiaFavorites synchronize]"); - //NSLog(@"%@",self); - if (_synchronize == nil) - return; - [_synchronize invoke]; -} --(void)dealloc -{ - if (_data != nil) { - [_data release]; - _data = nil; - } - if (_retain != nil) { - [_retain release]; - _retain = nil; - } - [super dealloc]; -} @end \ No newline at end of file diff --git a/macosx/CelestiaFavorite_PrivateAPI.h b/macosx/CelestiaFavorite_PrivateAPI.h index b0387a22..ef71c62b 100644 --- a/macosx/CelestiaFavorite_PrivateAPI.h +++ b/macosx/CelestiaFavorite_PrivateAPI.h @@ -12,11 +12,4 @@ @interface CelestiaFavorite(PrivateAPI) -(CelestiaFavorite*)initWithFavorite:(FavoritesEntry*)fav; -(FavoritesEntry*)favorite; -@end - - -@interface CelestiaFavorites(PrivateAPI) --(CelestiaFavorites*)initWithFavorites:(const FavoritesList*)favs; --(FavoritesList*)favorites; -@end - +@end \ No newline at end of file diff --git a/macosx/CelestiaFavorites.h b/macosx/CelestiaFavorites.h new file mode 100644 index 00000000..2361b20e --- /dev/null +++ b/macosx/CelestiaFavorites.h @@ -0,0 +1,20 @@ +// +// CelestiaFavorites.h +// celestia +// +// Created by Bob Ippolito on Thu Jun 20 2002. +// Copyright (c) 2002 Chris Laurel. All rights reserved. +// + +#import +#import "CelestiaFavorite.h" +#import "myTree.h" + + +@interface CelestiaFavorites : MyTree +-(void)setSynchronize:(NSInvocation*)synchronize; +-(void)synchronize; ++(CelestiaFavorites*)sharedFavorites; +-(MyTree*)addNewFavorite:(NSString*)name; +-(MyTree*)addNewFolder:(NSString*)name; +@end diff --git a/macosx/CelestiaFavorites.m b/macosx/CelestiaFavorites.m new file mode 100644 index 00000000..a11af7fe --- /dev/null +++ b/macosx/CelestiaFavorites.m @@ -0,0 +1,53 @@ +// +// CelestiaFavorites.m +// celestia +// +// Created by Bob Ippolito on Thu Jun 20 2002. +// Copyright (c) 2002 Chris Laurel. All rights reserved. +// + +#import "CelestiaFavorites.h" +#import "CelestiaFavorite.h" +@implementation CelestiaFavorites +static NSInvocation* _synchronize; +static CelestiaFavorites* _celestiaFavorites; +-(void)setSynchronize:(NSInvocation*)synchronize +{ + if (_synchronize != nil) + [_synchronize autorelease]; + _synchronize = [synchronize retain]; +} +-(void)synchronize +{ + if (_synchronize != nil) + [_synchronize invoke]; +} +-(NSString*)description +{ + return [NSString stringWithFormat:@"",[self numberOfChildren]]; +} +-(MyTree*)addNewFavorite:(NSString*)name +{ + MyTree* obj = [[[MyTree alloc] initWithNode:[[[CelestiaFavorite alloc] initWithName:name] autorelease] parent:self] autorelease]; + [[self children] addObject:obj]; + return obj; +} +-(MyTree*)addNewFolder:(NSString*)name +{ + MyTree* obj = [[[MyTree alloc] initWithNode:[[[CelestiaFavorite alloc] initWithFolderName:name] autorelease] parent:self children:[NSArray array]] autorelease]; + [[self children] addObject:obj]; + return obj; +} ++(void)initialize +{ + _celestiaFavorites = nil; + _synchronize = nil; +} ++(CelestiaFavorites*)sharedFavorites +{ + if (_celestiaFavorites != nil) + return _celestiaFavorites; + _celestiaFavorites = [[CelestiaFavorites alloc] initWithNode:nil parent:nil children:[NSArray array]]; + return _celestiaFavorites; +} +@end diff --git a/macosx/ContextOutlineView.h b/macosx/ContextOutlineView.h index 08b3b89d..732eb8e0 100644 --- a/macosx/ContextOutlineView.h +++ b/macosx/ContextOutlineView.h @@ -1,6 +1,7 @@ /* ContextOutlineView */ #import +#import "NSOutlineView_Extensions.h" @interface ContextOutlineView : NSOutlineView { } diff --git a/macosx/English.lproj/MainMenu.nib/classes.nib b/macosx/English.lproj/MainMenu.nib/classes.nib index 69768ba6..15c490e8 100644 --- a/macosx/English.lproj/MainMenu.nib/classes.nib +++ b/macosx/English.lproj/MainMenu.nib/classes.nib @@ -29,6 +29,7 @@ LANGUAGE = ObjC; OUTLETS = { coordinateField = NSTextField; + favoritesDrawerController = id; jdField = NSTextField; nameField = NSTextField; orientationField = NSTextField; @@ -42,7 +43,7 @@ LANGUAGE = ObjC; OUTLETS = { drawer = NSDrawer; - favoriteInfoWindowController = FavoriteInfoWindowController; + favoriteInfoWindowController = id; favoritesContextMenu = NSMenu; favoritesMenu = NSMenu; outlineView = ContextOutlineView; diff --git a/macosx/English.lproj/MainMenu.nib/info.nib b/macosx/English.lproj/MainMenu.nib/info.nib index e970437e..9544d1e2 100644 --- a/macosx/English.lproj/MainMenu.nib/info.nib +++ b/macosx/English.lproj/MainMenu.nib/info.nib @@ -3,7 +3,7 @@ IBDocumentLocation - 45 242 515 457 0 0 1152 746 + 66 156 515 457 0 0 1152 746 IBEditorPositions 242 @@ -11,7 +11,7 @@ 29 19 661 452 44 0 0 1152 746 296 - 491 337 170 341 0 0 1152 746 + 491 338 170 341 0 0 1152 746 335 522 588 98 114 0 0 1152 746 342 @@ -25,11 +25,9 @@ IBOpenObjects - 242 - 296 - 352 + 21 IBSystem Version - 5S60 + 5S66 diff --git a/macosx/English.lproj/MainMenu.nib/objects.nib b/macosx/English.lproj/MainMenu.nib/objects.nib index 34c3179624e5700b0ab33ff715f7948fe588cedf..109d3aa12f225abf4b520be05c10ca058ab227fd 100644 GIT binary patch literal 15085 zcmb_j4RjpEk?vl}vi>E@Kj6P)4;vIG#IenvP=1gspKXDWjaSJL2srEAku-R14|2SHKm+W}uBo8@fVQr&HnWF)frz=l$_8ZxD7AQ6uzwvk%k{RlHfG+nx8kq#c+?oQRF5v__Cz9l zD>Kd6U?sl}kCc&2)rv!BO6wQ=)bP-VSqDCyoy4rIRR_bpdn>Qj<9ffoOSAC8`>hOX zWGwU5GiT1QELb#lh19UNYDpuVh-fQ@Z6Knj&i-((B%%>Q&W=7UvZFto*kM^&^LzH+ z0}I5|a`a;R_LZlqJe93M}WMMHA2we|^~HuI<~p+-_|PW5StQjrT)ASWr*XAF`Vlnk#BSK8Jz)Kzy)TF;v?68h$egeEQ3LQAw@ zwLBFm^C@4i$Fvfu3Y4x;pzunvnK5ZIWnCK9GrEmW)NKxT_T~XCPNqWm#?<&Vgdg0h zMYM5NOMzqsm=KUtr?2nJ+^$w=bw^AKCxUX!6PX|hwE)^t-K{esX{?x(yZWRljZMRd zl~QJP#Ehi!NrO`lvpf{usgRRXBUcl0uwAY=Qe$Xpl8UX`PAvg{GtP2`$ChJLHc;Ia z-l_L0S6-~AoW6ez1y_)QPf81@-CzW}ji8Dga%y9f$)t#Qu*B5z7l1;l+GMD>GWp6< z$aNtjhB*%1nnb{u4nZxPdLpBs5!u#>$O^|_ zwLZMlNa(3aop}Q^fOvn;P@}S@_GmQd(McJj6Lpp&YTBIW4aboN_>@UWx^4>6_lk|& zvq3qIhp2-CQmXQeT5O=|l8u)x z6-%l59kFbF#y+>vJ~~PXS4~%_Te~H-Ue{vLg{E1B)CWmM!icSq$=K&~Z4lppg^BgL)!Vn zBg@TM*I#sLb5uMOm0_UvL1k+1hYqM{mMN$DN>(D3|l&zp`O-HYo`IsQ+abE?c&0<*HSyNbc&7=Uy>x(`;79Pcv(hZTz9n?Sa*@~~Vqp={ zM4usIQ2~py%#9=b34Vkf;ZIgRMHtA`YsA1e#AO3Wys=JHa&V!=q2KI3%9O9=5MOl( zRQ(7g-f{!7Hl0ctakkvIQNeyz+Z|-AJLp-cRJt6kLMHpW;=%_q<@_|uRKlN+xx=yJ!>aM+^){^UP{zS5g3nz<@} z=Ez{B($y3_hWUZk$DNDEUA;lUq&E(&34T}vBI0|+I+bngYlS+!Do>qT^VOLf(46a9 z>KSXPFHj(?Rw|6ODTP&ULUNEwN43^!%lyR1@`t9gOb^sxdD0SP7_pktZHJh@uxca9 zPvxzx-B*0{{{8ujuhGRJN2BmAqs1pJA~yuVzI$B<2GKFqAdGmg8ilpplc?_yi}aMT z>}(b6ThjS`Yx4ChCwjJApK66xe%yQUrrB?OjL)8Qrr8r%A4eEwnyK0R7dg{kw9@Vp zxr*gh$Bqf6^HbB9&Z>2KG8M)Kt~IBK!F)xSCN}t6jDgP%s8xjR{MC7j?!Q{P;G?@1 z71)gQY@tV2)+P8)g&V?W;fK*ntM)+3gfYaP3u5&WB1@k|BQANG2%aQc&- zzQNVy49-RjmmBB1_EyVX8U;dR2b6ROmZ1T`!69=A3NnZOcGdC1Jy^w-C8Z&06d zXDw=VR&>x@#&RxAusfb9a%GF99+x1>u4z$Gb{@J!l--Dk8e=>0H-%UmVc`RLT12Qr zCcwGiaE<#QqI{}c00VS0g*mregw=P^2%+<7^RYqs4YN4eaqVU_}FhK8g9 zYq8n%Q@ngtGE$|Nyya6=O9~mMCd9Y)TYK!+#_VU1N8K}&l|5mr8;_Pyv9d4%sJ9*jr(2%iIk3`(Dy3*u$PN3x1wp_s*g9c<&rI ziHDWBd)Zt;TrBSj_iOp3U+_fwjg8Mf<-Kg7jvb%7cXG@Xx?(p^NfOh zgVGbh4pAPO>uio-d*I~c7&23hp>}gZN5w<#{;TuH@_7DOirD{V+U%=x_ToEw!H!JG z``T%9uDLQD)5Gx~irWRsdU_(>O9lH+!QO(eqQ6D+P@M8C2qEc>xpjpg?NWl2h2#RJ zV9!p{(GUKd9UYypqnpvq5;>kFQ;cWn_~WVGq{p@3n*3osKVffc|D1z*al&o{ul;j& z^ir-PFPfbr_*!U<)3YR+3HJ1~ZLq1skYyE^pld1xOXyIpYphP&wCNb430aUV*t;9` z7|Kvtgd#r(O{;z)*nh}mMkX?^t1x+XH59=V*^H_v9`PhKD2f1$_LHM__f{%Y;5e!y z7EUHZgW-VzE%8x0Yg#7NfwhH|wK<)N!4{=US7i-4f1=kaxsb7ZbSqC<|JV}%?i3!wF43;r?h=~)0x4k{8vNwF=zW@1_3bGza* z3w+*oB~k)t3Bg`kPV7fA%*CQjPgXE%PJ`gpjL~00@PY|Lj)+&Ytf!}y?Y`p1Ew7rj z+oFcYuT^fFhD^cU9fvLQvBiRA8)yL8hH==w0+wI-#!p|R?H4ji!T#6f@`R@fOb7}Q z-K64;S{U1T8ugO%fp*Fr1H_k_%E~a3r7&{J)s$ezRANZ|=bCA7g8f1LHD|T8Q4PVX zqbzW@a>Yd#4X10^)sQ~xPzviX5^*IABVoo-C~HKIjU6%fG+H z`}_F3jn653&X}`g>QP-icW&ls7zpMU+b`cvj!92}IGUBSr=FlwLp&yV9(zr&52Wxp z8eFqqXu>bgPY#Y9Vi)(IS_7TH7Rmw_`;4l36M9}j?eK0|f7sN|$!0UJwK1kN zfpHvn{oz7S$mF_2cu-6HX>O4(@ZBOmXGU((C7YRBbcv^Mizn?v2W(_P6cko8+mDUf z_mANHaTz3Lz8B%k&UP>2Qk>OZ#HBgwy@*RU^Sy}6U}k%fM*Gb%dk1oVPrcKNvi#DV zIbAk0b5dk8G$%zog*kC|CC%Glq}<(3(IR^Hq>U)>gMX_J^a%EZ2;46CFT5>QrI(LT z(8C20@3Mxszfy+G-+$Y%A<>ryjWpbOxybP@}Gyqpir)lG#(NHx*@KDZl zx~1vVcw}Copmn0%vn(xeMO7~^sRTV*x$XYsbO;v}65{kY_<188?8aT861lx1ib~oZ zI$&>Vwp*IvlfEt35FRJ;Mt}B268^=rc1()m>>QJ#IeW*X=>7!9q!`T1F=6p~E@^sZ zmCTt{YDQ+IsAgbRig2c8#qF^d>^H_B;Y%_S%R?uXl<*6NvWHPq#s7!btich?wWw8_<(-{Wc47@~QnSZiywGlK zv9~qbr%r;+aV(s(onBR=rfnVn>lsb2qME_xRJEIsqu_U%@y)!|flA+K)fx#^)vZcBleNQJfb1+r$%}Jz)7L zS)st89<=(0llISFw-+9;%eXyA9qb{*x5n(IM*H>G?EW1=zE$ea-gqG5Z8oE8D%x zest8{H!^a)eJ&OkPKvzaoz<&XTlO&&DEUPe5NYW(x!ZagCpP)Ayl?MPWO;{0K<9G> zpJy*5YH$%e0VE_8K5t^lI{>WC3(NLN0NgvLmc3Px&>lwKhX6?hK*bWi0~j{<9_KYA z>uZ4J-8?1GF@+{KWHQ0A&y)~yK>Y48VR%Ibr4G$3dxguvlgF~lN;upv>$&LeaWp|v zU-&hU>rGc1JJ1GQ_-z+k_HzK0L*dZXyZDOgiZ>nwgbyoXxEfS~yE^ibp`#ZBKWMiU zbs@F#Z2$|k!fym9PkEPF_RA#X<(550Y*33X>UIsyCVRdJx*Gi7S1?}`8q0Zr<&PAg zdVq?AnB{V#@`c(fTlSy}^OU_BBdb*0ay^hJPZuGsk$SnL5LHUecLUhqEn0VbYT2)- zfj+A!{7I4H{2G9H>LD%i+W>3wxR5tj

0q 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 Gr~H3R+c<{+ diff --git a/macosx/FavoriteInfoWindowController.m b/macosx/FavoriteInfoWindowController.m index 9d3e600c..c446f931 100644 --- a/macosx/FavoriteInfoWindowController.m +++ b/macosx/FavoriteInfoWindowController.m @@ -31,9 +31,8 @@ - (IBAction)navigateTo:(id)sender { [[self window] performClose:self]; - if (_fav == nil) - return; - [(FavoritesDrawerController*)favoritesDrawerController activateFavorite:_fav]; + if (_fav != nil) + [(FavoritesDrawerController*)favoritesDrawerController activateFavorite:_fav]; } @end diff --git a/macosx/FavoritesDrawerController.h b/macosx/FavoritesDrawerController.h index f8c04e2d..60d971c7 100644 --- a/macosx/FavoritesDrawerController.h +++ b/macosx/FavoritesDrawerController.h @@ -8,45 +8,52 @@ @interface FavoritesDrawerController : NSObject { + NSArray *draggedNodes; IBOutlet NSDrawer *drawer; IBOutlet ContextOutlineView *outlineView; IBOutlet NSMenu *favoritesMenu; IBOutlet NSMenu *favoritesContextMenu; IBOutlet id favoriteInfoWindowController; } +-(NSArray*)selectedNodes; +-(NSArray*)draggedNodes; -(void)activateFavorite:(CelestiaFavorite*)fav; -(void)close; -(IBAction)close:(id)sender; -- (NSMenu *)outlineView:(NSOutlineView *)outlineView +-(NSMenu *)outlineView:(NSOutlineView *)outlineView contextMenuForItem:(id)item; -(IBAction)addNewFavorite:(id)sender; -(IBAction)addNewFolder:(id)sender; -(IBAction)doubleClick:(id)sender; --(void)synchronizeFavoritesMenu:(CelestiaFavorites*)favs; +-(void)synchronizeFavoritesMenu; -(id)outlineView:(NSOutlineView*)olv child:(int)index ofItem:(id)item; -(BOOL)outlineView:(NSOutlineView*)olv isItemExpandable:(id)item; -(int)outlineView:(NSOutlineView *)olv numberOfChildrenOfItem:(id)item; -(id)outlineView:(NSOutlineView *)olv objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item; -(void)outlineView:(NSOutlineView *)olv setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item; --(void)outlineView:(NSOutlineView*)olv deleteItem:(CelestiaFavorite*)item; +-(void)outlineView:(NSOutlineView*)olv deleteItem:(id)item; -(void)outlineView:(NSOutlineView*)olv editItem:(id)item; -(void)outlineViewSelectionDidChange:(NSNotification*)notification; /* -(BOOL)outlineView:(NSOutlineView *)olv shouldExpandItem:(id)item; -(void)outlineView:(NSOutlineView *)olv willDisplayCell:(NSCell *)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item; +*/ -(BOOL)outlineView:(NSOutlineView *)olv writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard; -(unsigned int)outlineView:(NSOutlineView*)olv validateDrop:(id )info proposedItem:(id)item proposedChildIndex:(int)childIndex; --(void)_performDropOperation:(id )info onNode:(TreeNode*)parentNode atIndex:(int)childIndex; +-(void)_performDropOperation:(id )info onNode:(id)pnode atIndex:(int)childIndex; -(BOOL)outlineView:(NSOutlineView*)olv acceptDrop:(id )info item:(id)targetItem childIndex:(int)childIndex; -*/ - @end @interface CelestiaFavorite(ViewAPI) --(NSMenuItem*)menuItem; --(NSMenuItem*)setupMenuItem:(NSMenuItem*)menuItem; +-(NSMenuItem*)favoriteMenuItem; +-(NSMenuItem*)setupFavoriteMenuItem:(NSMenuItem*)menuItem; @end @interface CelestiaFavorites(ViewAPI) --(void)synchronizeMenu:(NSMenu*)menu atIndex:(unsigned)count; +-(NSArray*)favoriteMenuItems; +@end + +@interface MyTree(ViewAPI) +-(void)activate; +-(NSMenuItem*)favoriteMenuItem; @end diff --git a/macosx/FavoritesDrawerController.m b/macosx/FavoritesDrawerController.m index a17c95f0..b1a47d0b 100644 --- a/macosx/FavoritesDrawerController.m +++ b/macosx/FavoritesDrawerController.m @@ -1,7 +1,8 @@ #import "FavoritesDrawerController.h" #import "CelestiaFavorite.h" -#import "CelestiaAppCore.h" - +#import "CelestiaFavorites.h" +#define SAFENODE(node) ((MyTree*)((node == nil) ? [CelestiaFavorites sharedFavorites] : node)) +#define DragDropSimplePboardType @"CelestiaFavoriteOutlineViewPboardType" /* @implementation NSMenuItem(DebuggingAPI) -(NSString*)description @@ -10,17 +11,16 @@ } @end */ - @implementation CelestiaFavorite(ViewAPI) --(NSMenuItem*)menuItem +-(NSMenuItem*)favoriteMenuItem { - NSMenuItem* menuItem = [[[NSMenuItem alloc] initWithTitle:[self name] action:@selector(activateFavorite:) keyEquivalent:@""] autorelease]; - return [self setupMenuItem:menuItem]; + NSMenuItem* menuItem = [[[NSMenuItem alloc] initWithTitle:[self name] action:([self isFolder] ? nil : @selector(activate)) keyEquivalent:@""] autorelease]; + return [self setupFavoriteMenuItem:menuItem]; } --(NSMenuItem*)setupMenuItem:(NSMenuItem*)menuItem +-(NSMenuItem*)setupFavoriteMenuItem:(NSMenuItem*)menuItem { - [menuItem setTarget:[CelestiaAppCore sharedAppCore]]; - [menuItem setAction:@selector(activateFavorite:)]; + [menuItem setTarget:self]; + [menuItem setAction:([self isFolder] ? nil : @selector(activate))]; [menuItem setTitle:[self name]]; [menuItem setRepresentedObject:self]; [menuItem setKeyEquivalent:@""]; @@ -30,33 +30,51 @@ @end @implementation CelestiaFavorites(ViewAPI) --(void)synchronizeMenu:(NSMenu*)menu atIndex:(unsigned)count +-(NSArray*)favoriteMenuItems { - NSEnumerator *enumerator = [self objectEnumerator]; - CelestiaFavorite *fav; - NSMutableArray *menuStack = [NSMutableArray arrayWithCapacity:[self count]]; - //NSLog(@"[CelestiaFavorites synchronizeMenu:%@ atIndex:%d]",menu,count); - while ((unsigned)[menu numberOfItems]>count) - [menu removeItemAtIndex:[menu numberOfItems]-1]; - //NSString *lastParent=@""; - [menuStack addObject:menu]; - /* FIXME */ - while ((fav = [enumerator nextObject]) != nil) { - NSMenuItem* menuItem = [fav menuItem]; - if ([[fav parentFolder] isEqualToString:@""]) - [menuStack removeObjectsInRange:NSMakeRange(1,[menuStack count]-1)]; - /*if ([fav isFolder]) { - NSMenu *subMenu = [[[NSMenu alloc] initWithTitle:[fav name]] autorelease]; - [menuItem setSubmenu:subMenu]; - [menuStack addObject:subMenu]; - }*/ - [[menuStack lastObject] addItem:menuItem]; - } - //NSLog(@"[CelestiaFavorites synchronizeMenu:%@ atIndex:%d]",menu,count); + NSEnumerator *enumerator = [[self children] objectEnumerator]; + MyTree* node = nil; + NSMutableArray* menuItems = [NSMutableArray arrayWithCapacity:[[self children] count]]; + //NSLog(@"[CelestiaFavorites favoriteMenuItems]"); + while ((node = [enumerator nextObject]) != nil) + [menuItems addObject:[node favoriteMenuItem]]; + return (NSArray*)menuItems; +} +@end +@implementation MyTree(ViewAPI) +-(void)activate +{ + [(CelestiaFavorite*)[self nodeValue] activate]; +} +-(NSMenuItem*)favoriteMenuItem +{ + NSEnumerator* enumerator = nil; + NSMenu* subMenu = nil; + NSMenuItem* menuItem = [[self nodeValue] favoriteMenuItem]; + MyTree* node = nil; + //NSLog(@"[MyTree favoriteMenuItem]"); + if ([self isLeaf]) + return menuItem; + enumerator = [[self children] objectEnumerator]; + subMenu = [[[NSMenu alloc] initWithTitle:[[self nodeValue] name]] autorelease]; + while ((node = [enumerator nextObject]) != nil) + [subMenu addItem:[node favoriteMenuItem]]; + [menuItem setSubmenu:subMenu]; + [menuItem setTarget:menuItem]; + [menuItem setAction:@selector(submenuAction:)]; + return menuItem; } @end @implementation FavoritesDrawerController +-(NSArray*)selectedNodes +{ + return [outlineView allSelectedItems]; +} +-(NSArray*)draggedNodes +{ + return draggedNodes; +} -(void)close { [drawer close]; @@ -67,61 +85,75 @@ } -(void)activateFavorite:(CelestiaFavorite*)fav { - [[CelestiaAppCore sharedAppCore] activateFavorite:fav]; + id menuItem = fav; + if ([menuItem isKindOfClass:[NSMenuItem class]]) + fav = [(NSMenuItem*)menuItem representedObject]; + [fav activate]; [outlineView deselectAll:self]; [drawer close]; } -(void)awakeFromNib { + draggedNodes = nil; [outlineView setVerticalMotionCanBeginDrag: YES]; [outlineView setTarget:self]; [outlineView setDoubleAction:@selector(doubleClick:)]; + [outlineView registerForDraggedTypes:[NSArray arrayWithObjects:DragDropSimplePboardType, nil]]; [favoritesMenu setAutoenablesItems:NO]; } -(IBAction)addNewFavorite:(id)sender { - CelestiaFavorites* favs = [[CelestiaAppCore sharedAppCore] favorites]; + CelestiaFavorites* favs = [CelestiaFavorites sharedFavorites]; + MyTree* node = nil; //NSLog(@"[FavoritesDrawerController addNewFavorite:%@]",sender); - [favs addNewFavorite:nil withParentFolder:nil]; - [self outlineView:outlineView editItem:[favs lastObject]]; + node = [favs addNewFavorite:nil]; + [[CelestiaFavorites sharedFavorites] synchronize]; + [self outlineView:outlineView editItem:node]; } -(IBAction)addNewFolder:(id)sender { - CelestiaFavorites* favs = [[CelestiaAppCore sharedAppCore] favorites]; + CelestiaFavorites* favs = [CelestiaFavorites sharedFavorites]; + MyTree* node = nil; //NSLog(@"[FavoritesDrawerController addNewFavorite:%@]",sender); - [favs addNewFolder:@"untitled folder" withParentFolder:nil]; - [self outlineView:outlineView editItem:[favs lastObject]]; + node = [favs addNewFolder:@"untitled folder"]; + [[CelestiaFavorites sharedFavorites] synchronize]; + [self outlineView:outlineView editItem:node]; } -(IBAction)doubleClick:(id)sender { - NSLog(@"[FavoritesDrawerController doubleClick:%@]",sender); + //NSLog(@"[FavoritesDrawerController doubleClick:%@]",sender); if ([outlineView numberOfSelectedRows]==1) - [self activateFavorite:[outlineView itemAtRow:[outlineView selectedRow]]]; + [self activateFavorite:[[outlineView itemAtRow:[outlineView selectedRow]] nodeValue]]; } --(void)synchronizeFavoritesMenu:(CelestiaFavorites*)favs +-(void)synchronizeFavoritesMenu { - //NSLog(@"[FavoritesDrawerController synchronizeFavoritesMenu:]"); - [[[CelestiaAppCore sharedAppCore] favorites] synchronizeMenu:favoritesMenu atIndex:3]; + NSEnumerator *enumerator = [[[CelestiaFavorites sharedFavorites] favoriteMenuItems] objectEnumerator]; + NSMenuItem *menuItem = nil; + // remove old menu items + while ([favoritesMenu numberOfItems]>3) + [favoritesMenu removeItemAtIndex:[favoritesMenu numberOfItems]-1]; + while ((menuItem = [enumerator nextObject]) != nil) + [favoritesMenu addItem:menuItem]; [outlineView reloadData]; } -(id)outlineView:(NSOutlineView*)olv child:(int)index ofItem:(id)item { id rval; //NSLog(@"[FavoritesDrawerController outlineview:%@ child:%d ofItem:%@]",olv,index,item); - rval = [[[CelestiaAppCore sharedAppCore] favorites] objectAtIndex:index parent:(CelestiaFavorite*)item]; + rval = [SAFENODE(item) childAtIndex:index]; //NSLog(@"rval = %@",rval); return rval; } -(BOOL)outlineView:(NSOutlineView*)olv isItemExpandable:(id)item { //NSLog(@"[FavoritesDrawerController outlineview:%@ itemIsExpandable:%@]",olv,item); - return [(CelestiaFavorite*)item isFolder]; + return ![SAFENODE(item) isLeaf]; } -(int)outlineView:(NSOutlineView *)olv numberOfChildrenOfItem:(id)item { int rval; //NSLog(@"[FavoritesDrawerController outlineview:%@ numberOfChildrenOfItem:%@]",olv,item); - rval = [[[CelestiaAppCore sharedAppCore] favorites] numberOfChildrenOfItem:(CelestiaFavorite*)item]; + rval = [SAFENODE(item) numberOfChildren]; //NSLog(@"rval = %d",rval); return rval; } @@ -130,9 +162,9 @@ id objectValue = nil; //NSLog(@"[FavoritesDrawerController outlineview:%@ objectValueForTableColumn:%@ byItem:%@]",olv,tableColumn,item); if([[tableColumn identifier] isEqualToString: @"NAME"]) { - objectValue = [(CelestiaFavorite*)item name]; - } else if([[tableColumn identifier] isEqualToString: @"SELECTION"] && ![(CelestiaFavorite*)item isFolder]) { - objectValue = [(CelestiaFavorite*)item selectionName]; + objectValue = [(CelestiaFavorite*)[SAFENODE(item) nodeValue] name]; + } else if([[tableColumn identifier] isEqualToString: @"SELECTION"] && [SAFENODE(item) isLeaf]) { + objectValue = [(CelestiaFavorite*)[SAFENODE(item) nodeValue] selectionName]; } //NSLog(@"rval = %@",objectValue); return objectValue; @@ -142,9 +174,9 @@ { //NSLog(@"[FavoritesDrawerController outlineview:%@ setObjectValue:%@ forTableColumn:%@ byItem:%@]",olv,object,tableColumn,item); if([[tableColumn identifier] isEqualToString: @"NAME"]) { - [(CelestiaFavorite*)item setName: object]; - [[[CelestiaAppCore sharedAppCore] favorites] synchronize]; - [(FavoriteInfoWindowController*)favoriteInfoWindowController updateFavorite:(CelestiaFavorite*)item]; + [(CelestiaFavorite*)[SAFENODE(item) nodeValue] setName: object]; + [[CelestiaFavorites sharedFavorites] synchronize]; + [(FavoriteInfoWindowController*)favoriteInfoWindowController updateFavorite:(CelestiaFavorite*)[SAFENODE(item) nodeValue]]; } } @@ -155,7 +187,7 @@ - (NSMenu *)outlineView:(NSOutlineView *)olv contextMenuForItem:(id)item { - CelestiaFavorite* fav = (CelestiaFavorite*)item; + MyTree* node = SAFENODE(item); NSMenu* contextMenu = [favoritesContextMenu copy]; NSInvocation* editInv = [NSInvocation invocationWithMethodSignature:[[self class] instanceMethodSignatureForSelector:@selector(outlineView:editItem:)]]; NSInvocation* delInv = [NSInvocation invocationWithMethodSignature:[[self class] instanceMethodSignatureForSelector:@selector(outlineView:deleteItem:)]]; @@ -184,7 +216,7 @@ contextMenuForItem:(id)item item = arr; else [olv selectRow:[olv rowForItem:item] byExtendingSelection:NO]; - if ([fav isFolder] || multipleItems) { + if (![node isLeaf] || multipleItems) { [contextMenu removeItemAtIndex:0]; [contextMenu removeItemAtIndex:0]; [contextMenu removeItemAtIndex:0]; @@ -194,9 +226,10 @@ contextMenuForItem:(id)item NSMenuItem* showItem = [contextMenu itemAtIndex:1]; [showItem setTarget:favoriteInfoWindowController]; [showItem setAction:@selector(showWindow:)]; - [fav setupMenuItem:navItem]; + [(CelestiaFavorite*)[node nodeValue] setupFavoriteMenuItem:navItem]; [navItem setTarget:self]; [navItem setTitle:title]; + [navItem setAction:@selector(activateFavorite:)]; } if (multipleItems) { [contextMenu removeItemAtIndex:0]; @@ -216,11 +249,15 @@ contextMenuForItem:(id)item [delItem setAction:@selector(invoke)]; return contextMenu; } -- (void)outlineView:(NSOutlineView*)olv editItem:(CelestiaFavorite*)item +- (void)outlineView:(NSOutlineView*)olv editItem:(id)item { int row = [olv rowForItem:item]; //NSLog(@"[FavoritesDrawerController outlineView:%@ editItem:%@]",olv,item); //NSLog(@"row = %d",row); // -1 ?? + if (row<0) { + NSLog(@"row is -1"); + return; + } [olv selectRow:row byExtendingSelection:NO]; [olv editColumn:[olv columnWithIdentifier:@"NAME"] row:row withEvent:nil select:YES]; } @@ -228,11 +265,11 @@ contextMenuForItem:(id)item - (void)outlineView:(NSOutlineView*)olv deleteItem:(id)item { //NSLog(@"[FavoritesDrawerController outlineView:%@ deleteItem:%@]",olv,item); - CelestiaFavorites *favs = [[CelestiaAppCore sharedAppCore] favorites]; - if ([item isKindOfClass:[CelestiaFavorite class]]) - [favs removeObject:(CelestiaFavorite*)item]; + if ([item isKindOfClass:[MyTree class]]) + [item removeFromParent]; else - [favs removeObjectsInArray:(NSArray*)item]; + [(NSArray*)item makeObjectsPerformSelector:@selector(removeFromParent)]; + [[CelestiaFavorites sharedFavorites] synchronize]; [olv deselectAll:self]; [(FavoriteInfoWindowController*)favoriteInfoWindowController updateFavorite:nil]; } @@ -241,7 +278,7 @@ contextMenuForItem:(id)item { NSOutlineView* olv = [notification object]; if ([olv numberOfSelectedRows]==1) { - [(FavoriteInfoWindowController*)favoriteInfoWindowController updateFavorite:[olv itemAtRow:[olv selectedRow]]]; + [(FavoriteInfoWindowController*)favoriteInfoWindowController updateFavorite:[[olv itemAtRow:[olv selectedRow]] nodeValue]]; } else { [(FavoriteInfoWindowController*)favoriteInfoWindowController updateFavorite:nil]; } @@ -251,11 +288,12 @@ contextMenuForItem:(id)item { BOOL rval; NSLog(@"[FavoritesDrawerController outlineview:%@ shouldExpandItem:%@]",olv,item); - rval = [(CelestiaFavorite*)item isFolder]; + rval = ![SAFENODE(item) isLeaf]; NSLog(@"rval = %@",((rval)?@"YES":@"NO")); return rval; } - +*/ +/* - (void)outlineView:(NSOutlineView *)olv willDisplayCell:(NSCell *)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item { // NSLog(@"[FavoritesDrawerController outlineview:%@ willDisplayCell:%@ forTableColumn:%@ item:0x%X]",olv,cell,tableColumn,item); @@ -273,9 +311,10 @@ contextMenuForItem:(id)item // ================================================================ // NSOutlineView data source methods. (dragging related) // ================================================================ -/* + - (BOOL)outlineView:(NSOutlineView *)olv writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard { + //NSLog(@"[FavoritesDrawerController outlineView:%@ writeItems:%@ toPasteboard:%@]",olv,items,pboard); draggedNodes = items; // Don't retain since this is just holding temporaral drag information, and it is only used during a drag! We could put this in the pboard actually. // Provide data for our custom type, and simple NSStrings. @@ -292,34 +331,40 @@ contextMenuForItem:(id)item - (unsigned int)outlineView:(NSOutlineView*)olv validateDrop:(id )info proposedItem:(id)item proposedChildIndex:(int)childIndex { // This method validates whether or not the proposal is a valid one. Returns NO if the drop should not be allowed. - SimpleTreeNode *targetNode = item; + MyTree *targetNode = item; BOOL targetNodeIsValid = YES; - if ([self onlyAcceptDropOnRoot]) { - targetNode = nil; - childIndex = NSOutlineViewDropOnItemIndex; - } else { - BOOL isOnDropTypeProposal = childIndex==NSOutlineViewDropOnItemIndex; - - // Refuse if: dropping "on" the view itself unless we have no data in the view. - if (targetNode==nil && childIndex==NSOutlineViewDropOnItemIndex && [treeData numberOfChildren]!=0) - targetNodeIsValid = NO; + BOOL isOnDropTypeProposal = childIndex==NSOutlineViewDropOnItemIndex; + //NSLog(@"[FavoritesDrawerController outlineView:%@ validateDrop:%@ proposedItem:%@ proposedChildIndex:%d]",olv,info,item,childIndex); + // Refuse if: dropping "on" the view itself unless we have no data in the view. + /* + if (targetNode==nil && isOnDropTypeProposal==YES && [self outlineView:olv numberOfChildrenOfItem:nil]!=0) + targetNodeIsValid = NO; + */ + if (targetNode==nil && isOnDropTypeProposal==YES)// && [self allowOnDropOnLeaf]==NO) + targetNodeIsValid = NO; + + if (targetNodeIsValid && [targetNode isLeaf]) + targetNodeIsValid = NO; + + if (isOnDropTypeProposal) + targetNodeIsValid = NO; - if (targetNode==nil && childIndex==NSOutlineViewDropOnItemIndex && [self allowOnDropOnLeaf]==NO) - targetNodeIsValid = NO; - - // Refuse if: we are trying to do something which is not allowed as specified by the UI check boxes. - if (targetNodeIsValid && isOnDropTypeProposal==NO && [self allowBetweenDrop]==NO || - [NODE_DATA(targetNode) isGroup] && isOnDropTypeProposal==YES && [self allowOnDropOnGroup]==NO || - [NODE_DATA(targetNode) isLeaf ] && isOnDropTypeProposal==YES && [self allowOnDropOnLeaf]==NO) - targetNodeIsValid = NO; - - // Check to make sure we don't allow a node to be inserted into one of its descendants! - if (targetNodeIsValid && ([info draggingSource]==outlineView) && [[info draggingPasteboard] availableTypeFromArray:[NSArray arrayWithObject: DragDropSimplePboardType]] != nil) { - NSArray *_draggedNodes = [[[info draggingSource] dataSource] draggedNodes]; - targetNodeIsValid = ![targetNode isDescendantOfNodeInArray: _draggedNodes]; - } + // Check to make sure we don't allow a node to be inserted into one of its descendants! + if (targetNodeIsValid && ([info draggingSource]==outlineView) && [[info draggingPasteboard] availableTypeFromArray:[NSArray arrayWithObject: DragDropSimplePboardType]] != nil) { + NSArray* _draggedNodes = [[[info draggingSource] dataSource] draggedNodes]; + //NSEnumerator* enumerator = [_draggedNodes objectEnumerator]; + //MyTree* node = nil; + targetNodeIsValid = ![targetNode isDescendantOfNodeInArray: _draggedNodes]; + /* + while ((node = [enumerator nextObject]) != nil) + if ([[node parent] isEqualTo:SAFENODE(item)] && !isOnDropTypeProposal && childIndex >= [SAFENODE(item) numberOfChildren]) { + targetNodeIsValid = NO; + break; + } + */ } + // Set the item and child index in case we computed a retargeted one. [outlineView setDropItem:targetNode dropChildIndex:childIndex]; @@ -327,55 +372,45 @@ contextMenuForItem:(id)item return targetNodeIsValid ? NSDragOperationGeneric : NSDragOperationNone; } -- (void)_performDropOperation:(id )info onNode:(TreeNode*)parentNode atIndex:(int)childIndex { +- (void)_performDropOperation:(id )info onNode:(id)pnode atIndex:(int)childIndex { // Helper method to insert dropped data into the model. - NSPasteboard * pboard = [info draggingPasteboard]; - NSMutableArray * itemsToSelect = nil; - - // Do the appropriate thing depending on wether the data is DragDropSimplePboardType or NSStringPboardType. + NSPasteboard* pboard = [info draggingPasteboard]; + NSMutableArray* itemsToSelect = nil; + MyTree* parentNode = SAFENODE(pnode); + //NSLog(@"[FavoritesDrawerController _performDropOperation:%@ onNode:%@ atIndex:%d]",info,pnode,childIndex); + //NSLog(@"parentNode = %@",parentNode); if ([pboard availableTypeFromArray:[NSArray arrayWithObjects:DragDropSimplePboardType, nil]] != nil) { - AppController *dragDataSource = [[info draggingSource] dataSource]; - NSArray *_draggedNodes = [TreeNode minimumNodeCoverFromNodesInArray: [dragDataSource draggedNodes]]; + FavoritesDrawerController *dragDataSource = [[info draggingSource] dataSource]; + NSArray *_draggedNodes = [MyTree minimumNodeCoverFromNodesInArray: [dragDataSource draggedNodes]]; NSEnumerator *draggedNodesEnum = [_draggedNodes objectEnumerator]; - SimpleTreeNode *_draggedNode = nil, *_draggedNodeParent = nil; - + MyTree *_draggedNode = nil, *_draggedNodeParent = nil; + //MyTree* favs = [CelestiaFavorites sharedFavorites]; itemsToSelect = [NSMutableArray arrayWithArray:[self selectedNodes]]; - + /* + NSLog(@"dragDataSource = %@",dragDataSource); + NSLog(@"_draggedNodes = %@",_draggedNodes); + NSLog(@"itemsToSelect = %@",itemsToSelect); + */ while ((_draggedNode = [draggedNodesEnum nextObject])) { - _draggedNodeParent = (SimpleTreeNode*)[_draggedNode nodeParent]; + _draggedNodeParent = [_draggedNode parent]; if (parentNode==_draggedNodeParent && [parentNode indexOfChild: _draggedNode])info item:(id)targetItem childIndex:(int)childIndex { - TreeNode * parentNode = nil; - + MyTree * parentNode = nil; + //NSLog(@"[FavoritesDrawerController outlineView:%@ acceptDrop:%@ item:%@ childIndex:%d]",olv,info,targetItem,childIndex); // Determine the parent to insert into and the child index to insert at. - if ([NODE_DATA(targetItem) isLeaf]) { - parentNode = (SimpleTreeNode*)(childIndex==NSOutlineViewDropOnItemIndex ? [targetItem nodeParent] : targetItem); - childIndex = (childIndex==NSOutlineViewDropOnItemIndex ? [[targetItem nodeParent] indexOfChild: targetItem]+1 : 0); - if ([NODE_DATA(parentNode) isLeaf]) [NODE_DATA(parentNode) setIsLeaf:NO]; - } else { - parentNode = SAFENODE(targetItem); - childIndex = (childIndex==NSOutlineViewDropOnItemIndex?0:childIndex); - } - - [self _performDropOperation:info onNode:parentNode atIndex:childIndex]; - + parentNode = (MyTree*)(targetItem ? targetItem : [CelestiaFavorites sharedFavorites]);//SAFENODE(targetItem); + childIndex = (childIndex==NSOutlineViewDropOnItemIndex ? 0 : childIndex); + [self _performDropOperation:info onNode:parentNode atIndex:childIndex]; return YES; } -*/ + @end diff --git a/macosx/MyTree.h b/macosx/MyTree.h new file mode 100644 index 00000000..0bdd16b7 --- /dev/null +++ b/macosx/MyTree.h @@ -0,0 +1,62 @@ +// +// MyTree.h +// celestia +// +// Created by Bob Ippolito on Thu Jun 20 2002. +// Copyright (c) 2002 Chris Laurel. All rights reserved. +// + +#import +#import "NSArray_Extensions.h" + +@interface MyVector : NSMutableArray { + NSMutableArray *_array; + Class _myClass; +} +-(id)initWithClass:(Class)myClass; +-(void)addObject:(id)obj; +-(void)insertObject:(id)obj atIndex:(unsigned)idx; +-(void)removeLastObject; +-(void)removeObjectAtIndex:(unsigned)idx; +-(void)replaceObjectAtIndex:(unsigned)idx withObject:(id)obj; +-(unsigned)count; +-(id)objectAtIndex:(unsigned)idx; +@end + +@interface MyTree : NSObject { + id _nodeValue; + MyVector* _children; + MyTree* _parent; +} +// for initializing a tree root node +-(id)init; +// initializing a leaf node +-(id)initWithNode:(id)obj parent:(MyTree*)parent; +// initializing a branch node +-(id)initWithNode:(id)obj parent:(MyTree*)parent children:(NSArray*)children; +-(MyVector*)children; +-(void)setNode:(id)obj; +-(void)setChildren:(NSArray*)children; +-(void)setParent:(MyTree*)parent; +-(MyTree*)parent; +-(id)nodeValue; +-(BOOL)isLeaf; +-(BOOL)isDescendantOfNode:(MyTree*)node; +-(BOOL)isDescendantOfNodeInArray:(NSArray*)array; ++(NSArray*)minimumNodeCoverFromNodesInArray:(NSArray*)allNodes; + +- (void)insertChild:(MyTree*)child atIndex:(int)index; +- (void)insertChildren:(NSArray*)children atIndex:(int)index; +- (void)removeChild:(MyTree*)child; +- (void)removeFromParent; + +- (int)indexOfChild:(MyTree*)child; +- (int)indexOfChildIdenticalTo:(MyTree*)child; + +- (int)numberOfChildren; +- (NSArray*)children; +- (MyTree*)firstChild; +- (MyTree*)lastChild; +- (MyTree*)childAtIndex:(int)index; + +@end diff --git a/macosx/MyTree.m b/macosx/MyTree.m new file mode 100644 index 00000000..ddbd4258 --- /dev/null +++ b/macosx/MyTree.m @@ -0,0 +1,279 @@ +// +// MyTree.m +// celestia +// +// Created by Bob Ippolito on Thu Jun 20 2002. +// Copyright (c) 2002 Chris Laurel. All rights reserved. +// + +#import "MyTree.h" +#import +@implementation MyVector +-(id)init +{ + self = [super init]; + _array = [[NSMutableArray arrayWithCapacity:0] retain]; + _myClass = [NSObject class]; + return self; +} +-(id)initWithClass:(Class)myClass +{ + self = [self init]; + _myClass = myClass; + return self; +} +-(void)addObject:(id)obj +{ + if (![obj isKindOfClass:_myClass]) + [NSException raise:@"TypeError" format:@"%s invalid, only %s allowed",NAMEOF(obj),_myClass->name]; + [_array addObject:obj]; +} +-(void)insertObject:(id)obj atIndex:(unsigned)idx +{ + if (![obj isKindOfClass:_myClass]) + [NSException raise:@"TypeError" format:@"%s invalid, only %s allowed",NAMEOF(obj),_myClass->name]; + [_array insertObject:obj atIndex:idx]; +} +-(void)removeLastObject +{ + [_array removeLastObject]; +} +-(void)removeObjectAtIndex:(unsigned)idx +{ + [_array removeObjectAtIndex:idx]; +} +-(void)replaceObjectAtIndex:(unsigned)idx withObject:(id)obj +{ + if (![obj isKindOfClass:_myClass]) + [NSException raise:@"TypeError" format:@"%s invalid, only %s allowed",NAMEOF(obj),_myClass->name]; + [_array replaceObjectAtIndex:idx withObject:obj]; +} +-(unsigned)count +{ + return [_array count]; +} +-(id)objectAtIndex:(unsigned)idx +{ + return [_array objectAtIndex:idx]; +} +@end + +@implementation MyTree +-(id)init +{ + self = [super init]; + _nodeValue = nil; + _children = nil; + _parent = nil; + return self; +} +-(void)dealloc +{ + NSLog(@"[MyTree dealloc]"); + NSLog(@"%@",self); + if ([self nodeValue] != nil) + [[self nodeValue] autorelease]; + if ([self children] != nil) + [[self children] autorelease]; + _nodeValue = nil; + _children = nil; + _parent = nil; + [super dealloc]; +} +-(id)initWithNode:(id)obj parent:(MyTree*)parent +{ + self = [self init]; + _nodeValue = [obj retain]; + _parent = parent; + _children = nil; + return self; +} +-(id)initWithNode:(id)obj parent:(MyTree*)parent children:(NSArray*)children +{ + NSEnumerator* enumerator; + self = [self initWithNode:obj parent:parent]; + _children = [[MyVector alloc] initWithClass:[MyTree class]]; + enumerator = [children objectEnumerator]; + while ((obj = [enumerator nextObject]) != nil) + [_children addObject:obj]; + return self; +} +-(id)initWithDictionary:(NSDictionary*)dict parent:(MyTree*)parent +{ + NSMutableArray* children = nil; + NSArray* origArray = nil; + NSEnumerator* enumerator = nil; + NSDictionary* childDict = nil; + id nodeValue = nil; + nodeValue = [dict objectForKey:@"nodeValue"]; + // Leaf + if ((origArray = [dict objectForKey:@"children"]) == nil) + return [self initWithNode:nodeValue parent:parent]; + children = [[MyVector alloc] initWithClass:[MyTree class]]; + enumerator = [origArray objectEnumerator]; + while ((childDict = [enumerator nextObject]) != nil) + [children addObject:[[[MyTree alloc] initWithDictionary:childDict parent:self] autorelease]]; + return [self initWithNode:nodeValue parent:parent children:children]; +} +-(MyTree*)parent +{ + return _parent; +} +-(MyVector*)children +{ + return _children; +} +-(id)nodeValue +{ + return _nodeValue; +} +-(BOOL)isLeaf +{ + return (([self children] == nil) ? YES : NO); +} +-(void)setNode:(id)obj +{ + if ([self nodeValue] != nil) + [[self nodeValue] autorelease]; + _nodeValue = [obj retain]; +} +-(void)setParent:(id)obj +{ + _parent = obj; +} +-(void)setChildren:(NSArray*)children +{ + NSEnumerator *enumerator = nil; + id obj = nil; + if ([self children] == nil) + [[self children] autorelease]; + if (children == nil) { + _children = nil; + return; + } + enumerator = [children objectEnumerator]; + _children = [[MyVector alloc] initWithClass:[MyTree class]]; + while ((obj = [enumerator nextObject]) != nil) + [_children addObject:obj]; +} +-(NSDictionary*)dictionary +{ + return [NSDictionary dictionaryWithObjectsAndKeys:[self nodeValue],@"nodeValue",[NSNumber numberWithBool:[self isLeaf]],@"isLeaf",[self children],@"children",nil,nil]; +} +-(NSDictionary*)recursiveDictionary +{ + NSMutableArray* array; + NSEnumerator* enumerator; + MyTree* obj; + if ([self isLeaf]) + return [self dictionary]; + enumerator = [[self children] objectEnumerator]; + array = [NSMutableArray arrayWithCapacity:[[self children] count]]; + while ((obj = [enumerator nextObject]) != nil) + [array addObject:[obj recursiveDictionary]]; + return [NSDictionary dictionaryWithObjectsAndKeys:_nodeValue,@"nodeValue",array,@"children",nil,nil]; +} +-(NSString*)description +{ + return [[self dictionary] description]; +} +-(BOOL)isDescendantOfNode:(MyTree*)node +{ + MyTree* parent = self; + if ([self isEqualTo:node]) + return YES; + while ((parent = [parent parent]) != nil) + if ([node isEqualTo:parent]) + return YES; + return NO; +} +-(BOOL)isDescendantOfNodeInArray:(NSArray*)array +{ + NSEnumerator* enumerator = [array objectEnumerator]; + MyTree* node = nil; + while ((node = [enumerator nextObject]) != nil) + if ([self isDescendantOfNode:node] == YES) + return YES; + return NO; +} + +- (void)insertChild:(MyTree*)child atIndex:(int)index { + [[self children] insertObject:child atIndex:index]; + [child setParent: self]; +} + +- (void)insertChildren:(NSArray*)children atIndex:(int)index { + [[self children] insertObjectsFromArray: children atIndex: index]; + [children makeObjectsPerformSelector:@selector(setParent:) withObject:self]; +} + +- (void)_removeChildrenIdenticalTo:(NSArray*)children { + MyTree *child; + NSEnumerator *childEnumerator = [children objectEnumerator]; + [children makeObjectsPerformSelector:@selector(setParent:) withObject:nil]; + while ((child = [childEnumerator nextObject]) != nil) { + [[self children] removeObjectIdenticalTo:child]; + } +} + +- (void)removeChild:(MyTree*)child { + [[self children] removeObject:child]; +/* + int index = [self indexOfChild: child]; + if (index != NSNotFound) { + [self _removeChildrenIdenticalTo: [NSArray arrayWithObject: [self childAtIndex:index]]]; + } +*/ +} + +- (void)removeFromParent { + [[self parent] removeChild:self]; +} + +- (int)indexOfChild:(MyTree*)child { + return [[self children] indexOfObject:child]; +} + +- (int)indexOfChildIdenticalTo:(MyTree*)child { + return [[self children] indexOfObjectIdenticalTo:child]; +} + +- (int)numberOfChildren { + return [[self children] count]; +} + +- (MyTree*)firstChild { + return [[self children] objectAtIndex:0]; +} + +- (MyTree*)lastChild { + return [[self children] lastObject]; +} + +- (MyTree*)childAtIndex:(int)index { + return [[self children] objectAtIndex:index]; +} + +// Returns the minimum nodes from 'allNodes' required to cover the nodes in 'allNodes'. +// This methods returns an array containing nodes from 'allNodes' such that no node in +// the returned array has an ancestor in the returned array. + +// There are better ways to compute this, but this implementation should be efficient for our app. ++ (NSArray *) minimumNodeCoverFromNodesInArray: (NSArray *)allNodes { + NSMutableArray *minimumCover = [NSMutableArray array]; + NSMutableArray *nodeQueue = [NSMutableArray arrayWithArray:allNodes]; + MyTree *node = nil; + while ([nodeQueue count]) { + node = [nodeQueue objectAtIndex:0]; + [nodeQueue removeObjectAtIndex:0]; + while ( [node parent] && [nodeQueue containsObjectIdenticalTo:[node parent]] ) { + [nodeQueue removeObjectIdenticalTo: node]; + node = [node parent]; + } + if (![node isDescendantOfNodeInArray: minimumCover]) [minimumCover addObject: node]; + [nodeQueue removeObjectIdenticalTo: node]; + } + return minimumCover; +} + +@end \ No newline at end of file diff --git a/macosx/celestia.pbproj/project.pbxproj b/macosx/celestia.pbproj/project.pbxproj index 9878dbb8..b2b5e24d 100644 --- a/macosx/celestia.pbproj/project.pbxproj +++ b/macosx/celestia.pbproj/project.pbxproj @@ -14,6 +14,7 @@ 080E96DDFE201D6D7F000001 = { children = ( F5040B0F02A484DA014901DC, + F5231C7102C2997601000006, F5274ED302AE88260100020A, F57F9FD402B94A0B01000006, F57FA4F002B9AB8601000006, @@ -21,6 +22,7 @@ F55C817602AF55890100020A, F57F9FD302B94A0B01000006, F5040B0E02A484DA014901DC, + F5231C7202C2997601000006, F5274ED202AE88260100020A, F57FA4EF02B9AB8601000006, F578B7B302B3E4DB0100020A, @@ -407,6 +409,9 @@ F578B7B502B3E4DB0100020A, F57F9FD502B94A0B01000006, F57FA4F102B9AB8601000006, + F5231C7402C2997601000006, + F56FFFAB02C571280100020A, + F56FFFB002C578050100020A, ); isa = PBXHeadersBuildPhase; }; @@ -515,6 +520,9 @@ F59DDEAA02B5F10E0100020A, F57F9FD602B94A0B01000006, F57FA4F202B9AB8601000006, + F5231C7302C2997601000006, + F56FFFAC02C571280100020A, + F56FFFAF02C578050100020A, ); isa = PBXSourcesBuildPhase; }; @@ -843,6 +851,7 @@ F51C6DB602959A17014901DC, F51C6DB702959A17014901DC, F51C6DB802959A17014901DC, + F56FFFAD02C578050100020A, F51C6DB902959A17014901DC, F51C6DBA02959A17014901DC, F51C6DBB02959A17014901DC, @@ -887,6 +896,7 @@ F51C6DE202959A17014901DC, F51C6DE302959A17014901DC, F51C6DE402959A17014901DC, + F56FFFAE02C578050100020A, F51C6DE502959A17014901DC, F51C6DE602959A17014901DC, F51C6DE702959A17014901DC, @@ -2269,6 +2279,28 @@ settings = { }; }; + F5231C7102C2997601000006 = { + isa = PBXFileReference; + path = CelestiaFavorites.m; + refType = 4; + }; + F5231C7202C2997601000006 = { + isa = PBXFileReference; + path = CelestiaFavorites.h; + refType = 4; + }; + F5231C7302C2997601000006 = { + fileRef = F5231C7102C2997601000006; + isa = PBXBuildFile; + settings = { + }; + }; + F5231C7402C2997601000006 = { + fileRef = F5231C7202C2997601000006; + isa = PBXBuildFile; + settings = { + }; + }; F5274ED202AE88260100020A = { isa = PBXFileReference; path = CelestiaOpenGLView.h; @@ -2903,13 +2935,61 @@ settings = { }; }; + F56FFFA902C571280100020A = { + isa = PBXFileReference; + path = MyTree.h; + refType = 4; + }; + F56FFFAA02C571280100020A = { + isa = PBXFileReference; + path = MyTree.m; + refType = 4; + }; + F56FFFAB02C571280100020A = { + fileRef = F56FFFA902C571280100020A; + isa = PBXBuildFile; + settings = { + }; + }; + F56FFFAC02C571280100020A = { + fileRef = F56FFFAA02C571280100020A; + isa = PBXBuildFile; + settings = { + }; + }; + F56FFFAD02C578050100020A = { + isa = PBXFileReference; + name = boundaries.cpp; + path = /Users/bob/src/celestia/src/celengine/boundaries.cpp; + refType = 0; + }; + F56FFFAE02C578050100020A = { + isa = PBXFileReference; + name = boundaries.h; + path = /Users/bob/src/celestia/src/celengine/boundaries.h; + refType = 0; + }; + F56FFFAF02C578050100020A = { + fileRef = F56FFFAD02C578050100020A; + isa = PBXBuildFile; + settings = { + }; + }; + F56FFFB002C578050100020A = { + fileRef = F56FFFAE02C578050100020A; + isa = PBXBuildFile; + settings = { + }; + }; F578B79D02B3E2AD0100020A = { children = ( F578B79E02B3E2DD0100020A, + F56FFFAA02C571280100020A, F578B7A102B3E2DD0100020A, F578B7A002B3E2DD0100020A, F55F041E02B152180100020A, F578B7A202B3E2DD0100020A, + F56FFFA902C571280100020A, F578B7A302B3E2DD0100020A, F578B79F02B3E2DD0100020A, F55F041D02B152180100020A,