[osx] Restore last window regardless of system preference
Even with the system preference set to close windows when quitting, the user would still expect this map-centric application to remember the last viewed map, because the world map isn’t quite as interesting.
This commit is contained in:
committed by
Minh Nguyễn
parent
44a4f7bca2
commit
0a23d4fe39
@@ -1,14 +1,22 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <Mapbox/Mapbox.h>
|
||||
|
||||
extern NSString * const MGLMapboxAccessTokenDefaultsKey;
|
||||
|
||||
@class MapDocument;
|
||||
|
||||
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
||||
|
||||
@property (weak) IBOutlet NSWindow *preferencesWindow;
|
||||
|
||||
@property (copy) NSURL *pendingURL;
|
||||
// Normally, an application should respect the “Close windows when quitting an
|
||||
// application” setting in the General pane of System Preferences. But the map
|
||||
// would only be restored to its last opened location if the user quits the
|
||||
// application using Quit and Keep Windows. An application that displays only a
|
||||
// map should restore the last viewed map, like Maps.app does. These properties
|
||||
// temporarily hold state for the next map window to be opened.
|
||||
|
||||
@property (assign) double pendingZoomLevel;
|
||||
@property (copy) MGLMapCamera *pendingCamera;
|
||||
@property (copy) NSURL *pendingStyleURL;
|
||||
@property (assign) MGLMapDebugMaskOptions pendingDebugMask;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
|
||||
#import "MapDocument.h"
|
||||
|
||||
#import <Mapbox/Mapbox.h>
|
||||
|
||||
NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken";
|
||||
NSString * const MGLLastMapCameraDefaultsKey = @"MGLLastMapCamera";
|
||||
NSString * const MGLLastMapStyleURLDefaultsKey = @"MGLLastMapStyleURL";
|
||||
NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
|
||||
|
||||
@interface AppDelegate ()
|
||||
|
||||
@@ -36,6 +37,20 @@ NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken";
|
||||
andSelector:@selector(handleGetURLEvent:withReplyEvent:)
|
||||
forEventClass:kInternetEventClass
|
||||
andEventID:kAEGetURL];
|
||||
|
||||
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"NSQuitAlwaysKeepsWindows"]) {
|
||||
NSData *cameraData = [[NSUserDefaults standardUserDefaults] objectForKey:MGLLastMapCameraDefaultsKey];
|
||||
if (cameraData) {
|
||||
NSKeyedUnarchiver *coder = [[NSKeyedUnarchiver alloc] initForReadingWithData:cameraData];
|
||||
self.pendingZoomLevel = -1;
|
||||
self.pendingCamera = [[MGLMapCamera alloc] initWithCoder:coder];
|
||||
}
|
||||
NSString *styleURLString = [[NSUserDefaults standardUserDefaults] objectForKey:MGLLastMapStyleURLDefaultsKey];
|
||||
if (styleURLString) {
|
||||
self.pendingStyleURL = [NSURL URLWithString:styleURLString];
|
||||
}
|
||||
self.pendingDebugMask = [[NSUserDefaults standardUserDefaults] integerForKey:MGLLastMapDebugMaskDefaultsKey];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
||||
@@ -50,10 +65,59 @@ NSString * const MGLMapboxAccessTokenDefaultsKey = @"MGLMapboxAccessToken";
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification *)notification {
|
||||
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"NSQuitAlwaysKeepsWindows"]) {
|
||||
NSDocument *currentDocument = [NSDocumentController sharedDocumentController].currentDocument;
|
||||
if ([currentDocument isKindOfClass:[MapDocument class]]) {
|
||||
MGLMapView *mapView = [(MapDocument *)currentDocument mapView];
|
||||
NSMutableData *cameraData = [NSMutableData data];
|
||||
NSKeyedArchiver *coder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:cameraData];
|
||||
[mapView.camera encodeWithCoder:coder];
|
||||
[coder finishEncoding];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:cameraData forKey:MGLLastMapCameraDefaultsKey];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:mapView.styleURL.absoluteString forKey:MGLLastMapStyleURLDefaultsKey];
|
||||
[[NSUserDefaults standardUserDefaults] setInteger:mapView.debugMask forKey:MGLLastMapDebugMaskDefaultsKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Services
|
||||
|
||||
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent {
|
||||
self.pendingURL = [NSURL URLWithString:[event paramDescriptorForKeyword:keyDirectObject].stringValue];
|
||||
// mapboxgl://?center=29.95,-90.066667&zoom=14&bearing=45&pitch=30
|
||||
NSURL *url = [NSURL URLWithString:[event paramDescriptorForKeyword:keyDirectObject].stringValue];
|
||||
NS_MUTABLE_DICTIONARY_OF(NSString *, NSString *) *params = [[NSMutableDictionary alloc] init];
|
||||
for (NSString *param in [url.query componentsSeparatedByString:@"&"]) {
|
||||
NSArray *parts = [param componentsSeparatedByString:@"="];
|
||||
if (parts.count >= 2) {
|
||||
params[parts[0]] = [parts[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
}
|
||||
}
|
||||
|
||||
MGLMapCamera *camera = [MGLMapCamera camera];
|
||||
NSString *zoomLevelString = params[@"zoom"];
|
||||
self.pendingZoomLevel = zoomLevelString.length ? zoomLevelString.doubleValue : -1;
|
||||
|
||||
NSString *directionString = params[@"bearing"];
|
||||
if (directionString.length) {
|
||||
camera.heading = directionString.doubleValue;
|
||||
}
|
||||
|
||||
NSString *centerString = params[@"center"];
|
||||
if (centerString) {
|
||||
NSArray *coordinateValues = [centerString componentsSeparatedByString:@","];
|
||||
if (coordinateValues.count == 2) {
|
||||
camera.centerCoordinate = CLLocationCoordinate2DMake([coordinateValues[0] doubleValue],
|
||||
[coordinateValues[1] doubleValue]);
|
||||
}
|
||||
}
|
||||
|
||||
NSString *pitchString = params[@"pitch"];
|
||||
if (pitchString.length) {
|
||||
camera.pitch = pitchString.doubleValue;
|
||||
}
|
||||
|
||||
self.pendingCamera = camera;
|
||||
[[NSDocumentController sharedDocumentController] openUntitledDocumentAndDisplay:YES error:NULL];
|
||||
}
|
||||
|
||||
|
||||
@@ -65,12 +65,7 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
|
||||
NSPressGestureRecognizer *pressGestureRecognizer = [[NSPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlePressGesture:)];
|
||||
[self.mapView addGestureRecognizer:pressGestureRecognizer];
|
||||
|
||||
if (_inheritedStyleURL) {
|
||||
self.mapView.styleURL = _inheritedStyleURL;
|
||||
}
|
||||
AppDelegate *appDelegate = (AppDelegate *)NSApp.delegate;
|
||||
[self populateFromURL:appDelegate.pendingURL];
|
||||
appDelegate.pendingURL = nil;
|
||||
[self applyPendingState];
|
||||
}
|
||||
|
||||
- (NSString *)displayName {
|
||||
@@ -120,47 +115,6 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
|
||||
self.mapView.zoomLevel, centerCoordinate.latitude, centerCoordinate.longitude, self.mapView.direction]];
|
||||
}
|
||||
|
||||
- (void)populateFromURL:(NSURL *)url {
|
||||
if (![url.scheme isEqualToString:@"mapboxgl"]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// mapboxgl://?center=29.95,-90.066667&zoom=14&bearing=45&pitch=30
|
||||
NS_MUTABLE_DICTIONARY_OF(NSString *, NSString *) *params = [[NSMutableDictionary alloc] init];
|
||||
for (NSString *param in [url.query componentsSeparatedByString:@"&"]) {
|
||||
NSArray *parts = [param componentsSeparatedByString:@"="];
|
||||
if (parts.count >= 2) {
|
||||
params[parts[0]] = [parts[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
}
|
||||
}
|
||||
|
||||
NSString *zoomLevelString = params[@"zoom"];
|
||||
if (zoomLevelString.length) {
|
||||
_mapView.zoomLevel = zoomLevelString.doubleValue;
|
||||
}
|
||||
|
||||
NSString *directionString = params[@"bearing"];
|
||||
if (directionString.length) {
|
||||
_mapView.direction = directionString.doubleValue;
|
||||
}
|
||||
|
||||
NSString *centerString = params[@"center"];
|
||||
if (centerString) {
|
||||
NSArray *coordinateValues = [centerString componentsSeparatedByString:@","];
|
||||
if (coordinateValues.count == 2) {
|
||||
_mapView.centerCoordinate = CLLocationCoordinate2DMake([coordinateValues[0] doubleValue],
|
||||
[coordinateValues[1] doubleValue]);
|
||||
}
|
||||
}
|
||||
|
||||
NSString *pitchString = params[@"pitch"];
|
||||
if (pitchString.length) {
|
||||
MGLMapCamera *camera = _mapView.camera;
|
||||
camera.pitch = pitchString.doubleValue;
|
||||
_mapView.camera = camera;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark View methods
|
||||
|
||||
- (IBAction)setStyle:(id)sender {
|
||||
@@ -237,6 +191,30 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
|
||||
[self.mapView reloadStyle:sender];
|
||||
}
|
||||
|
||||
- (void)applyPendingState {
|
||||
if (_inheritedStyleURL) {
|
||||
self.mapView.styleURL = _inheritedStyleURL;
|
||||
_inheritedStyleURL = nil;
|
||||
}
|
||||
|
||||
AppDelegate *appDelegate = (AppDelegate *)NSApp.delegate;
|
||||
if (appDelegate.pendingStyleURL) {
|
||||
self.mapView.styleURL = appDelegate.pendingStyleURL;
|
||||
}
|
||||
if (appDelegate.pendingCamera) {
|
||||
if (appDelegate.pendingZoomLevel >= 0) {
|
||||
self.mapView.zoomLevel = appDelegate.pendingZoomLevel;
|
||||
appDelegate.pendingCamera.altitude = self.mapView.camera.altitude;
|
||||
}
|
||||
self.mapView.camera = appDelegate.pendingCamera;
|
||||
appDelegate.pendingZoomLevel = -1;
|
||||
appDelegate.pendingCamera = nil;
|
||||
}
|
||||
if (appDelegate.pendingDebugMask) {
|
||||
self.mapView.debugMask = appDelegate.pendingDebugMask;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Debug methods
|
||||
|
||||
- (IBAction)toggleTileBoundaries:(id)sender {
|
||||
|
||||
Reference in New Issue
Block a user