diff --git a/Frameworks/DocumentWindow/src/DocumentController.mm b/Frameworks/DocumentWindow/src/DocumentController.mm index 39758e2c..bed7a26e 100644 --- a/Frameworks/DocumentWindow/src/DocumentController.mm +++ b/Frameworks/DocumentWindow/src/DocumentController.mm @@ -837,7 +837,7 @@ NSString* const kUserDefaultsFileBrowserPlacementKey = @"fileBrowserPlacement"; // = Document Action Methods = // =========================== -- (void)savePanelDidEnd:(OakSavePanel*)sheet path:(NSString*)aPath contextInfo:(void*)info +- (void)savePanelDidEnd:(OakSavePanel*)sheet path:(NSString*)aPath encoding:(std::string const&)encoding newlines:(std::string const&)newlines useBOM:(BOOL)useBOM { if(!aPath) return; @@ -849,6 +849,10 @@ NSString* const kUserDefaultsFileBrowserPlacementKey = @"fileBrowserPlacement"; ASSERT_LT(0, paths.size()); [self selectedDocument]->set_path(paths[0]); // FIXME check if document already exists (overwrite) + [self selectedDocument]->set_disk_encoding(encoding); + [self selectedDocument]->set_disk_newlines(newlines); + [self selectedDocument]->set_disk_bom(useBOM); + [DocumentSaveHelper trySaveDocument:self.selectedDocument forWindow:self.window defaultDirectory:nil andCallback:NULL]; if(paths.size() > 1) @@ -858,6 +862,9 @@ NSString* const kUserDefaultsFileBrowserPlacementKey = @"fileBrowserPlacement"; { documents.push_back(document::create(paths[i])); documents.back()->open(); // so that we find this when going to counterpart + documents.back()->set_disk_encoding(encoding); + documents.back()->set_disk_newlines(newlines); + documents.back()->set_disk_bom(useBOM); } [self addDocuments:documents andSelect:kSelectDocumentNone closeOther:NO pruneTabBar:NO]; @@ -870,18 +877,20 @@ NSString* const kUserDefaultsFileBrowserPlacementKey = @"fileBrowserPlacement"; - (IBAction)saveDocument:(id)sender { D(DBF_DocumentController, bug("%s\n", [self selectedDocument]->path().c_str());); - if([self selectedDocument]->path() != NULL_STR) - [DocumentSaveHelper trySaveDocument:self.selectedDocument forWindow:self.window defaultDirectory:nil andCallback:NULL]; - else [OakSavePanel showWithPath:DefaultSaveNameForDocument([self selectedDocument]) directory:self.untitledSavePath fowWindow:self.window delegate:self contextInfo:NULL]; + document::document_ptr doc = [self selectedDocument]; + if(doc->path() != NULL_STR) + [DocumentSaveHelper trySaveDocument:doc forWindow:self.window defaultDirectory:nil andCallback:NULL]; + else [OakSavePanel showWithPath:DefaultSaveNameForDocument(doc) directory:self.untitledSavePath fowWindow:self.window delegate:self encoding:doc->disk_encoding() newlines:doc->disk_newlines() useBOM:doc->disk_bom()]; } - (IBAction)saveDocumentAs:(id)sender { D(DBF_DocumentController, bug("%s\n", [self selectedDocument]->path().c_str());); - std::string const documentPath = [self selectedDocument]->path(); + document::document_ptr doc = [self selectedDocument]; + std::string const documentPath = doc->path(); NSString* documentFolder = [NSString stringWithCxxString:path::parent(documentPath)]; NSString* documentName = [NSString stringWithCxxString:path::name(documentPath)]; - [OakSavePanel showWithPath:(documentName ?: DefaultSaveNameForDocument([self selectedDocument])) directory:(documentFolder ?: self.untitledSavePath) fowWindow:self.window delegate:self contextInfo:NULL]; + [OakSavePanel showWithPath:(documentName ?: DefaultSaveNameForDocument(doc)) directory:(documentFolder ?: self.untitledSavePath) fowWindow:self.window delegate:self encoding:doc->disk_encoding() newlines:doc->disk_newlines() useBOM:doc->disk_bom()]; } - (IBAction)saveAllDocuments:(id)sender diff --git a/Frameworks/DocumentWindow/src/DocumentSaveHelper.mm b/Frameworks/DocumentWindow/src/DocumentSaveHelper.mm index 0dc36b8b..945d1318 100644 --- a/Frameworks/DocumentWindow/src/DocumentSaveHelper.mm +++ b/Frameworks/DocumentWindow/src/DocumentSaveHelper.mm @@ -44,7 +44,7 @@ namespace D(DBF_DocumentController_SaveHelper, bug("\n");); init(context); - [OakSavePanel showWithPath:DefaultSaveNameForDocument(_document) directory:_self.saveFolder fowWindow:_window delegate:_self contextInfo:NULL]; + [OakSavePanel showWithPath:DefaultSaveNameForDocument(_document) directory:_self.saveFolder fowWindow:_window delegate:_self encoding:_document->disk_encoding() newlines:_document->disk_newlines() useBOM:_document->disk_bom()]; } void select_make_writable (std::string const& path, io::bytes_ptr content, file::save_context_ptr context) @@ -197,12 +197,15 @@ namespace // = Sheet Callbacks = // =================== -- (void)savePanelDidEnd:(OakSavePanel*)sheet path:(NSString*)aPath contextInfo:(void*)info +- (void)savePanelDidEnd:(OakSavePanel*)sheet path:(NSString*)aPath encoding:(std::string const&)encoding newlines:(std::string const&)newlines useBOM:(BOOL)useBOM { D(DBF_DocumentController_SaveHelper, bug("%s\n", to_s(aPath).c_str());); if(aPath) { documents.back()->set_path(to_s(aPath)); + documents.back()->set_disk_encoding(encoding); + documents.back()->set_disk_newlines(newlines); + documents.back()->set_disk_bom(useBOM); context->set_path(to_s(aPath)); } else diff --git a/Frameworks/OakAppKit/resources/English.lproj/EncodingSaveOptions.xib b/Frameworks/OakAppKit/resources/English.lproj/EncodingSaveOptions.xib new file mode 100644 index 00000000..1063898e --- /dev/null +++ b/Frameworks/OakAppKit/resources/English.lproj/EncodingSaveOptions.xib @@ -0,0 +1,583 @@ + + + + 1070 + 12A269 + 2549 + 1187 + 624.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 2549 + + + NSButton + NSButtonCell + NSCustomObject + NSCustomView + NSMenu + NSMenuItem + NSPopUpButton + NSPopUpButtonCell + NSTextField + NSTextFieldCell + NSUserDefaultsController + + + com.apple.InterfaceBuilder.CocoaPlugin + + + PluginDependencyRecalculationVersion + + + + + OakEncodingSaveOptionsViewController + + + FirstResponder + + + NSApplication + + + + 301 + + + + 268 + {{17, 77}, {89, 17}} + + + + _NS:1535 + YES + + 68157504 + 272630784 + Line endings: + + LucidaGrande + 13 + 1044 + + _NS:1535 + + + 6 + System + controlColor + + 3 + MC42NjY2NjY2NjY3AA + + + + 6 + System + controlTextColor + + 3 + MAA + + + + NO + + + + 268 + {{40, 46}, {66, 17}} + + + + _NS:1535 + YES + + 68157504 + 272630784 + Encoding: + + _NS:1535 + + + + + NO + + + + 268 + {{109, 18}, {153, 18}} + + + + _NS:9 + YES + + -2080374784 + 268435456 + Add byte order mark + + _NS:9 + + 1211912448 + 2 + + NSImage + NSSwitch + + + NSSwitch + + + + 200 + 25 + + NO + + + + 268 + {{108, 72}, {174, 26}} + + + + _NS:9 + YES + + -2076180416 + 2048 + + _NS:9 + + 109199360 + 129 + + + 400 + 75 + + + LF (recommended) + + 1048576 + 2147483647 + 1 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + _popUpItemAction: + + + YES + + OtherViews + + + + + CR (Classic Mac) + + 1048576 + 2147483647 + + + _popUpItemAction: + 1 + + + + + CRLF (MS-DOS) + + 1048576 + 2147483647 + + + _popUpItemAction: + 2 + + + + + + 1 + YES + YES + 2 + + NO + + + + 268 + {{108, 41}, {174, 26}} + + + + _NS:9 + YES + + -2076180416 + 2048 + + _NS:9 + + 109199360 + 129 + + + 400 + 75 + + + encoding + + 1048576 + 2147483647 + 1 + + + _popUpItemAction: + + + YES + + OtherViews + + + + + + 1 + YES + YES + 2 + + NO + + + {299, 116} + + + + NSView + + + YES + + + + + + + view + + + + 228 + + + + encodingPopUpButton + + + + 238 + + + + selectedTag: lineEndings + + + + + + selectedTag: lineEndings + selectedTag + lineEndings + + NSValueTransformerName + OakLineEndingsTransformer + + 2 + + + 247 + + + + value: useByteOrderMark + + + + + + value: useByteOrderMark + value + useByteOrderMark + 2 + + + 240 + + + + enabled: canUseByteOrderMark + + + + + + enabled: canUseByteOrderMark + enabled + canUseByteOrderMark + 2 + + + 242 + + + + + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 1 + + + + + + + + + + + + 33 + + + + + + + + 34 + + + + + 2 + + + + + + + + 3 + + + + + + + + 4 + + + + + + + + 5 + + + + + 11 + + + + + + + + 13 + + + + + + + + 14 + + + + + + + + + + 17 + + + + + 16 + + + + + 15 + + + + + 25 + + + + + + + + 26 + + + + + 29 + + + + + + + + 30 + + + + + 243 + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + Line Endings Pop Up Button + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + OakEncodingPopUpButton + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + 247 + + + + + OakEncodingPopUpButton + NSPopUpButton + + IBProjectSource + ./Classes/OakEncodingPopUpButton.h + + + + OakEncodingSaveOptionsViewController + NSViewController + + encodingPopUpButton + OakEncodingPopUpButton + + + encodingPopUpButton + + encodingPopUpButton + OakEncodingPopUpButton + + + + IBProjectSource + ./Classes/OakEncodingSaveOptionsViewController.h + + + + + 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES + 3 + + {11, 11} + {10, 3} + {15, 15} + + + diff --git a/Frameworks/OakAppKit/src/OakSavePanel.h b/Frameworks/OakAppKit/src/OakSavePanel.h index f1c20c1e..02073d13 100644 --- a/Frameworks/OakAppKit/src/OakSavePanel.h +++ b/Frameworks/OakAppKit/src/OakSavePanel.h @@ -1,11 +1,12 @@ +@class OakEncodingSaveOptionsViewController; + @interface OakSavePanel : NSObject { - id delegate; - void* contextInfo; + OakEncodingSaveOptionsViewController* optionsViewController; } -+ (void)showWithPath:(NSString*)aPathSuggestion directory:(NSString*)aDirectorySuggestion fowWindow:(NSWindow*)aWindow delegate:(id)aDelegate contextInfo:(void*)info; ++ (void)showWithPath:(NSString*)aPathSuggestion directory:(NSString*)aDirectorySuggestion fowWindow:(NSWindow*)aWindow delegate:(id)aDelegate encoding:(std::string const&)encoding newlines:(std::string const&)newlines useBOM:(BOOL)useBOM; @end @interface NSObject (OakSavePanelDelegate) -- (void)savePanelDidEnd:(OakSavePanel*)sheet path:(NSString*)aPath contextInfo:(void*)info; +- (void)savePanelDidEnd:(OakSavePanel*)sheet path:(NSString*)aPath encoding:(std::string const&)encoding newlines:(std::string const&)newlines useBOM:(BOOL)useBOM; @end diff --git a/Frameworks/OakAppKit/src/OakSavePanel.mm b/Frameworks/OakAppKit/src/OakSavePanel.mm index 703797c8..84b8cc5d 100644 --- a/Frameworks/OakAppKit/src/OakSavePanel.mm +++ b/Frameworks/OakAppKit/src/OakSavePanel.mm @@ -1,13 +1,90 @@ -#import "NSSavePanel Additions.h" #import "OakSavePanel.h" +#import "OakEncodingPopUpButton.h" +#import "NSSavePanel Additions.h" +#import +#import +#import + +@interface OakEncodingSaveOptionsViewController : NSViewController +{ + IBOutlet OakEncodingPopUpButton* encodingPopUpButton; + + NSString* encoding; + NSString* lineEndings; + BOOL useByteOrderMark; +} +@property (nonatomic, retain) NSString* lineEndings; +@property (nonatomic, retain) NSString* encoding; +@property (nonatomic, assign) BOOL useByteOrderMark; +@property (nonatomic, readonly) BOOL canUseByteOrderMark; +@end + +@implementation OakEncodingSaveOptionsViewController +@synthesize encoding, lineEndings, useByteOrderMark; + ++ (NSSet*)keyPathsForValuesAffectingCanUseByteOrderMark { return [NSSet setWithObject:@"encoding"]; } + ++ (void)initialize +{ + [OakStringListTransformer createTransformerWithName:@"OakLineEndingsTransformer" andObjectsArray:@[ @"\n", @"\r", @"\r\n" ]]; + [OakStringListTransformer createTransformerWithName:@"OakLineEndingsListTransformer" andObjectsArray:@[ @"\n", @"\r", @"\r\n" ]]; +} + +- (id)init +{ + if(self = [super initWithNibName:@"EncodingSaveOptions" bundle:[NSBundle bundleForClass:[self class]]]) + { + self.encoding = @"UTF-8"; + self.lineEndings = @"\n"; + } + return self; +} + +- (void)dealloc +{ + [self unbind:@"encoding"]; + [super dealloc]; +} + +- (void)loadView +{ + [super loadView]; + encodingPopUpButton.encoding = encoding; + [self bind:@"encoding" toObject:encodingPopUpButton withKeyPath:@"encoding" options:nil]; +} + +- (BOOL)canUseByteOrderMark +{ + return [self.encoding hasPrefix:@"UTF-"]; +} + +- (void)setEncoding:(NSString*)newEncoding +{ + if(encoding != newEncoding && ![encoding isEqualToString:newEncoding]) + { + [encoding autorelease]; + encoding = [newEncoding retain]; + + self.useByteOrderMark = [self canUseByteOrderMark] && ![encoding isEqualToString:@"UTF-8"]; + } +} +@end @implementation OakSavePanel -- (id)initWithPath:(NSString*)aPathSuggestion directory:(NSString*)aDirectorySuggestion fowWindow:(NSWindow*)aWindow delegate:(id)aDelegate contextInfo:(void*)info +- (id)initWithPath:(NSString*)aPathSuggestion directory:(NSString*)aDirectorySuggestion fowWindow:(NSWindow*)aWindow delegate:(id)aDelegate encoding:(std::string const&)encoding newlines:(std::string const&)newlines useBOM:(BOOL)useBOM { if((self = [super init])) { - delegate = aDelegate; - contextInfo = info; + optionsViewController = [OakEncodingSaveOptionsViewController new]; + if(!optionsViewController) + { + [self release]; + return nil; + } + + optionsViewController.encoding = [NSString stringWithCxxString:encoding] ?: @"UTF-8"; + optionsViewController.lineEndings = [NSString stringWithCxxString:newlines] ?: @"\n"; + optionsViewController.useByteOrderMark = useBOM; [[aWindow attachedSheet] orderOut:self]; // incase there already is a sheet showing (like “Do you want to save?”) @@ -16,9 +93,10 @@ if(aDirectorySuggestion) [savePanel setDirectoryURL:[NSURL fileURLWithPath:aDirectorySuggestion]]; [savePanel setNameFieldStringValue:[aPathSuggestion lastPathComponent]]; + [savePanel setAccessoryView:optionsViewController.view]; [savePanel beginSheetModalForWindow:aWindow completionHandler:^(NSInteger result) { NSString* path = result == NSOKButton ? [[savePanel.URL filePathURL] path] : nil; - [delegate savePanelDidEnd:self path:path contextInfo:contextInfo]; + [aDelegate savePanelDidEnd:self path:path encoding:to_s(optionsViewController.encoding) newlines:to_s(optionsViewController.lineEndings) useBOM:optionsViewController.useByteOrderMark]; [self release]; }]; [savePanel deselectExtension]; @@ -26,9 +104,14 @@ return self; } -+ (void)showWithPath:(NSString*)aPathSuggestion directory:(NSString*)aDirectorySuggestion fowWindow:(NSWindow*)aWindow delegate:(id)aDelegate contextInfo:(void*)info +- (void)dealloc { - [[OakSavePanel alloc] initWithPath:aPathSuggestion directory:aDirectorySuggestion fowWindow:aWindow delegate:aDelegate contextInfo:info]; + [optionsViewController release]; + [super dealloc]; } ++ (void)showWithPath:(NSString*)aPathSuggestion directory:(NSString*)aDirectorySuggestion fowWindow:(NSWindow*)aWindow delegate:(id)aDelegate encoding:(std::string const&)encoding newlines:(std::string const&)newlines useBOM:(BOOL)useBOM +{ + [[OakSavePanel alloc] initWithPath:aPathSuggestion directory:aDirectorySuggestion fowWindow:aWindow delegate:aDelegate encoding:encoding newlines:newlines useBOM:useBOM]; +} @end