celestia/macosx/BrowserWindowController.mm

406 lines
14 KiB
Plaintext

//
// BrowserWindowController.mm
// celestia
//
// Created by Hank Ramsey on Tue Dec 28 2004.
// Copyright (c) 2002 Chris Laurel. All rights reserved.
// Modifications Copyright (c) 2004 Hank Ramsey. All rights reserved.
//
#import "BrowserWindowController.h"
#import "BrowserItem.h"
#import "NSString_ObjCPlusPlus.h"
#import "CelestiaAppCore.h"
#import "CelestiaStar_PrivateAPI.h"
#import "CelestiaBody_PrivateAPI.h"
#import "CelestiaDSO.h"
#import "CelestiaLocation.h"
#include "celestiacore.h"
#include "celestia.h"
#include "selection.h"
#include "starbrowser.h"
#define BROWSER_MAX_DSO_COUNT 300
#define BROWSER_MAX_STAR_COUNT 100
@interface BrowserWindowController(Private)
- (NSDictionary *) deepSkyObjects;
- (NSDictionary *) starsOfKind: (int) kind;
- (BrowserItem *) sol;
@end
@implementation BrowserWindowController
static NSDictionary *rootItems;
static CelestiaCore *appCore;
- (id) init
{
self = [super initWithWindowNibName: @"BrowserWindow" ];
if (self)
{
appCore = (CelestiaCore*) [[CelestiaAppCore sharedAppCore] appCore];
rootId = @"solarSystem";
}
return self;
}
- (void) windowDidLoad
{
if ([self window]==nil) NSLog(@"loaded browser window is nil");
}
//--------------------------------------------------------------
- (NSDictionary *) deepSkyObjects
{
int objCount;
int i = 0;
NSMutableDictionary *countPerType;
NSMutableDictionary *result;
NSMutableDictionary *tempDict;
NSDictionary *typeMap;
NSMutableDictionary *group;
DSODatabase* catalog = appCore->getSimulation()->getUniverse()->getDSOCatalog();
DeepSkyObject *obj;
CelestiaDSO *dsoWrapper;
NSString *name;
NSString *type;
objCount = catalog->size();
typeMap = [[NSDictionary alloc] initWithObjectsAndKeys:
NSLocalizedString(@"Galaxies (Barred Spiral)",@""), @"SB",
NSLocalizedString(@"Galaxies (Spiral)",@""), @"S",
NSLocalizedString(@"Galaxies (Elliptical)",@""), @"E",
NSLocalizedString(@"Galaxies (Irregular)",@""), @"Irr",
NSLocalizedString(@"Nebulae",@""), @"Neb",
NSLocalizedStringFromTable(@"Globulars",@"po",@""), @"Glob",
NSLocalizedString(@"Open Clusters",@""), @"Clust",
NSLocalizedString(@"Unknown",@""), @"Unknown",
nil];
tempDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSMutableDictionary dictionary], @"SB",
[NSMutableDictionary dictionary], @"S",
[NSMutableDictionary dictionary], @"E",
[NSMutableDictionary dictionary], @"Irr",
[NSMutableDictionary dictionary], @"Neb",
[NSMutableDictionary dictionary], @"Glob",
[NSMutableDictionary dictionary], @"Clust",
[NSMutableDictionary dictionary], @"Unknown",
nil];
countPerType = [NSMutableDictionary dictionaryWithCapacity: [tempDict count]];
result = [NSMutableDictionary dictionaryWithCapacity: [tempDict count]];
for (; i < objCount; ++i)
{
obj = catalog->getDSO(i);
if (obj)
{
dsoWrapper = [[[CelestiaDSO alloc] initWithDSO: obj] autorelease];
type = [dsoWrapper type];
NSNumber *typeCount = [countPerType objectForKey: type];
if (nil == typeCount)
{
typeCount = [NSNumber numberWithInt: 0];
}
if ([typeCount intValue] == BROWSER_MAX_DSO_COUNT) continue;
[countPerType setObject:[NSNumber numberWithInt:([typeCount intValue]+1)] forKey:type];
if ([type hasPrefix: @"SB"])
group = [tempDict objectForKey: @"SB"];
else if ([type hasPrefix: @"S"])
group = [tempDict objectForKey: @"S"];
else if ([type hasPrefix: @"E"])
group = [tempDict objectForKey: @"E"];
else if ([type hasPrefix: @"Irr"])
group = [tempDict objectForKey: @"Irr"];
else if ([type hasPrefix: @"Neb"])
group = [tempDict objectForKey: @"Neb"];
else if ([type hasPrefix: @"Clust"])
group = [tempDict objectForKey: @"Clust"];
else if ([type hasPrefix: @"Glob"])
group = [tempDict objectForKey: @"Glob"];
else
group = [tempDict objectForKey: @"Unknown"];
name = [NSString stringWithStdString: catalog->getDSOName(obj)];
[group setObject: [[[BrowserItem alloc] initWithCelestiaDSO: dsoWrapper] autorelease]
forKey: name];
}
}
NSEnumerator *tempEnum = [tempDict keyEnumerator];
while ((type = [tempEnum nextObject]))
{
if ([[tempDict objectForKey: type] count] > 0)
{
[result setObject: [[[BrowserItem alloc] initWithName: [typeMap objectForKey: type] children: [tempDict objectForKey: type]] autorelease]
forKey: [typeMap objectForKey: type]];
}
}
[typeMap release];
return result;
}
- (BrowserItem *) sol
{
Selection sol = appCore->getSimulation()->getUniverse()->find("Sol");
return [[[BrowserItem alloc] initWithCelestiaStar: [[[CelestiaStar alloc] initWithStar: sol.star()] autorelease]] autorelease];
}
- (NSDictionary *) starsOfKind: (int) kind
{
std::vector<const Star*>* nearStars;
int starCount = 0;
Simulation *sim = appCore->getSimulation();
StarBrowser* sb = new StarBrowser(sim,kind);
nearStars = sb->listStars( BROWSER_MAX_STAR_COUNT );
if (nearStars == nil ) return [NSDictionary dictionary];
starCount = nearStars->size();
NSMutableDictionary* starDict = [NSMutableDictionary dictionaryWithCapacity: starCount+2];
const Star *aStar;
NSString *starName;
int i;
for (i=0;i<starCount;i++)
{
aStar = (*nearStars)[i];
starName = [NSString stringWithStdString: sim->getUniverse()->getStarCatalog()->getStarName(*aStar) ];
[starDict setObject:
[[[BrowserItem alloc] initWithCelestiaStar: [[[CelestiaStar alloc] initWithStar: aStar] autorelease]] autorelease]
forKey: starName];
}
delete sb;
delete nearStars;
return starDict;
}
-(BrowserItem *) root
{
if (rootItems) return [rootItems objectForKey: rootId];
BrowserItem *sol;
BrowserItem *stars;
BrowserItem *dsos;
sol = [self sol];
[BrowserItem addChildrenToStar: sol];
stars = [[BrowserItem alloc] initWithName: @""];
[stars addChild: [[[BrowserItem alloc] initWithName:
NSLocalizedString(@"Nearest Stars",@"") children:
[self starsOfKind: StarBrowser::NearestStars]] autorelease]];
[stars addChild: [[[BrowserItem alloc] initWithName:
NSLocalizedString(@"Brightest Stars",@"") children:
[self starsOfKind: StarBrowser::BrighterStars]] autorelease]];
[stars addChild: [[[BrowserItem alloc] initWithName:
NSLocalizedString(@"Stars With Planets",@"") children:
[self starsOfKind: StarBrowser::StarsWithPlanets]] autorelease]];
dsos = [[BrowserItem alloc] initWithName: @"" children: [self deepSkyObjects]];
rootItems = [[NSDictionary alloc] initWithObjectsAndKeys:
sol, @"solarSystem",
stars, @"star",
dsos, @"dso",
nil];
[stars release];
[dsos release];
return [rootItems objectForKey: rootId];
}
- (BrowserItem *) itemForPathArray: (NSArray*) pathNames
{
BrowserItem *lastItem = [self root];
BrowserItem *nextItem = lastItem;
NSString *lastKey = nil;
id body;
unsigned i;
for (i=1;i<[pathNames count];i++)
{
lastKey = [pathNames objectAtIndex: i];
nextItem = [lastItem childNamed: lastKey];
if (nil==nextItem) break;
lastItem = nextItem;
}
if (nextItem)
{
body = [nextItem body];
if (body)
{
if ([body respondsToSelector: @selector(star)])
[BrowserItem addChildrenToStar: nextItem];
else if ([body respondsToSelector: @selector(body)])
[BrowserItem addChildrenToBody: nextItem];
}
}
return lastItem;
}
- (Selection *) selFromPathArray: (NSArray*) pathNames
{
Selection *sel = NULL;
BrowserItem *item = [self itemForPathArray: pathNames];
id body = [item body];
if (body)
{
if ([body respondsToSelector: @selector(star)])
sel = new Selection([(CelestiaStar *)body star]);
else if ([body respondsToSelector: @selector(body)])
sel = new Selection([(CelestiaBody *)body body]);
else if ([body respondsToSelector: @selector(DSO)])
sel = new Selection([(CelestiaDSO *)body DSO]);
else if ([body respondsToSelector: @selector(location)])
sel = new Selection([(CelestiaLocation *)body location]);
}
return sel;
}
- (int) browser: (NSBrowser*) sender numberOfRowsInColumn: (int) column
{
if (browser != sender)
{
browser = sender;
// if ([browser respondsToSelector:@selector(setColumnResizingType:)])
// [browser setColumnResizingType: 2];
// [browser setMinColumnWidth: 80];
[browser setDoubleAction:@selector(doubleClick:)];
}
BrowserItem *itemForColumn = [self itemForPathArray: [[sender pathToColumn: column ] componentsSeparatedByString: [sender pathSeparator] ] ];
return [itemForColumn childCount];
}
- (BOOL) isLeaf: (BrowserItem *) aItem
{
if ([aItem childCount] > 0) return NO;
id body = [aItem body];
if (body)
{
if ([body respondsToSelector: @selector(star)])
{
if (appCore->getSimulation()->getUniverse()->getSolarSystem([(CelestiaStar *)body star]))
return NO;
}
else if ([body respondsToSelector: @selector(body)])
{
if ([(CelestiaBody *)body body]->getSatellites() || [(CelestiaBody *)body body]->getLocations())
return NO;
}
}
return YES;
}
- (void) browser: (NSBrowser*) sender willDisplayCell: (id) cell atRow: (int) row column: (int) column
{
BrowserItem *itemForColumn = [self itemForPathArray: [[sender pathToColumn: column ] componentsSeparatedByString: [sender pathSeparator] ] ];
NSArray* colKeys = [itemForColumn allChildNames];
BOOL isLeaf = YES;
NSString* itemName = [colKeys objectAtIndex: row];
if (!itemName)
itemName = @"????";
else
isLeaf = [self isLeaf: [itemForColumn childNamed: itemName ]];
NSRange rightParenRange = {NSNotFound, 0};
NSRange leftParenRange = {NSNotFound, 0};
NSRange parenRange = {NSNotFound, 0};
if (isLeaf)
{
rightParenRange = [itemName rangeOfString:@")"
options:NSBackwardsSearch];
if (rightParenRange.length == 1)
{
leftParenRange = NSMakeRange(0, rightParenRange.location - 1);
parenRange = [itemName rangeOfString:@"("
options:NSBackwardsSearch
range:leftParenRange];
if (parenRange.length == 1)
{
parenRange.length = rightParenRange.location - parenRange.location + 1;
}
}
}
if (parenRange.location != NSNotFound)
{
NSDictionary *parenAttr = [NSDictionary dictionaryWithObjectsAndKeys:
[NSColor grayColor], NSForegroundColorAttributeName,
nil];
NSMutableAttributedString *attrStr = [[[NSMutableAttributedString alloc] initWithString: itemName] autorelease];
[attrStr setAttributes:parenAttr range:parenRange];
[cell setAttributedStringValue:attrStr];
}
else
{
[cell setTitle: itemName ];
}
[cell setLeaf: isLeaf];
}
- (IBAction) go: (id) sender
{
Selection *sel = [self selFromPathArray: [[browser path] componentsSeparatedByString: [browser pathSeparator] ]];
if (sel)
{
appCore->getSimulation()->setSelection(*sel);
if ([sender tag]!=0) appCore->charEntered([sender tag]);
delete sel;
}
}
- (void) doubleClick: (id) sender
{
browser = sender;
NSArray *pathArray = [[browser path] componentsSeparatedByString: [browser pathSeparator]];
Selection *sel = [self selFromPathArray: pathArray];
if (sel)
{
appCore->getSimulation()->setSelection(*sel);
appCore->charEntered('g');
delete sel;
}
}
- (void)tabView: (NSTabView *)aTabView didSelectTabViewItem: (NSTabViewItem *)aTabViewItem
{
rootId = [aTabViewItem identifier];
}
- (void)windowDidBecomeKey:(NSNotification *)aNotification
{
if ([aNotification object] == [self window])
{
NSTabViewItem *curTab = [tabView selectedTabViewItem];
if (nil == curTab) return;
rootId = [curTab identifier];
if (browser && [rootId isEqualToString: @"star"])
{
BrowserItem *rootItem = [self root];
[rootItem addChild: [[[BrowserItem alloc] initWithName:
NSLocalizedString(@"Nearest Stars",@"") children:
[self starsOfKind: StarBrowser::NearestStars]] autorelease]];
// Immediately synch browser display with reloaded star list,
// but only if star list is showing
NSArray *selection = [[browser path] componentsSeparatedByString: [browser pathSeparator]];
if ([selection count]>1 && [[selection objectAtIndex: 1] isEqualToString: NSLocalizedString(@"Nearest Stars",@"")])
{
for (int i=1; i<[browser numberOfVisibleColumns]; ++i)
[browser reloadColumn: i];
}
}
}
}
@end