Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

executable file 294 lines (239 sloc) 10.933 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
#import "EncodingsManager.h"
#import "NoteObject.h"
#import "NotationFileManager.h"
#import "NSData_transformations.h"
#import "NSString_NV.h"

@implementation EncodingsManager

static const NSStringEncoding AllowedEncodings[] = {
/* Western */
NSISOLatin1StringEncoding, // ISO Latin 1
(NSStringEncoding) 0x80000203, // ISO Latin 3
(NSStringEncoding) 0x8000020F, // ISO Latin 9
NSMacOSRomanStringEncoding, // Mac
NSWindowsCP1252StringEncoding, // Windows
/* Baltic */
(NSStringEncoding) -1,
(NSStringEncoding) 0x8000020D, // ISO Latin 7
(NSStringEncoding) 0x80000507, // Windows
/* Central European */
(NSStringEncoding) -1,
NSISOLatin2StringEncoding, // ISO Latin 2
(NSStringEncoding) 0x80000204, // ISO Latin 4
(NSStringEncoding) 0x8000001D, // Mac
NSWindowsCP1250StringEncoding, // Windows
/* Cyrillic */
(NSStringEncoding) -1,
(NSStringEncoding) 0x80000A02, // KOI8-R
(NSStringEncoding) 0x80000205, // ISO Latin 5
(NSStringEncoding) 0x80000007, // Mac
NSWindowsCP1251StringEncoding, // Windows
/* Japanese */
(NSStringEncoding) -1, // Divider
(NSStringEncoding) 0x80000A01, // ShiftJIS
NSISO2022JPStringEncoding, // ISO-2022-JP
NSJapaneseEUCStringEncoding, // EUC
(NSStringEncoding) 0x80000001, // Mac
NSShiftJISStringEncoding, // Windows
/* Simplified Chinese */
(NSStringEncoding) -1, // Divider
(NSStringEncoding) 0x80000632, // GB 18030
(NSStringEncoding) 0x80000631, // GBK
(NSStringEncoding) 0x80000930, // EUC
(NSStringEncoding) 0x80000019, // Mac
(NSStringEncoding) 0x80000421, // Windows
/* Traditional Chinese */
(NSStringEncoding) -1, // Divider
(NSStringEncoding) 0x80000A03, // Big5
(NSStringEncoding) 0x80000A06, // Big5 HKSCS
(NSStringEncoding) 0x80000931, // EUC
(NSStringEncoding) 0x80000002, // Mac
(NSStringEncoding) 0x80000423, // Windows
/* Korean */
(NSStringEncoding) -1, // Divider
(NSStringEncoding) 0x80000940, // EUC
(NSStringEncoding) 0x80000003, // Mac
(NSStringEncoding) 0x80000422, // Windows
/* Hebrew */
(NSStringEncoding) -1, // Divider
(NSStringEncoding) 0x80000208, // ISO-8859-8
(NSStringEncoding) 0x80000005, // Mac
(NSStringEncoding) 0x80000505, // Windows
/* End */ 0 };


+ (EncodingsManager *)sharedManager {
static EncodingsManager *man = nil;
if (!man)
man = [[EncodingsManager alloc] init];
return man;
}

- (BOOL)checkUnicode {

if (NSUnicodeStringEncoding == currentEncoding || NSUTF8StringEncoding == currentEncoding) {

NSString * alertTitleString = NSLocalizedString(@"quotemark%@quotemark is a Unicode file and not directly interpretable using plain text encodings.",
@"alert title when converting from unicode");
if (NSRunAlertPanel([NSString stringWithFormat:alertTitleString, filenameOfNote(note)],
NSLocalizedString(@"If you wish to convert it, you must open and re-save the file in an external editor.", "alert description when converting from unicode"),
NSLocalizedString(@"OK", nil), NSLocalizedString(@"Open in TextEdit", @"title of button for opening the current note in text edit"), NULL) != NSAlertDefaultReturn) {

NSString *textEditPath = [[NSWorkspace sharedWorkspace] absolutePathForAppBundleWithIdentifier:@"com.apple.TextEdit"];
if (textEditPath) {
NSString *resolvedPath = [note noteFilePath];
if (!resolvedPath) {
NSRunAlertPanel(NSLocalizedString(@"Could not locate the note file.", nil), NSLocalizedString(@"Does it still exist?", nil),
NSLocalizedString(@"I'll Go See", @"... if it exists"), NULL, NULL);
} else {
[[NSWorkspace sharedWorkspace] openFile:resolvedPath withApplication:textEditPath];
}
} else {
NSRunAlertPanel(NSLocalizedString(@"Could not find the application TextEdit.", nil), NSLocalizedString(@"You may need to re-run the Mac OS X installer.",nil), NSLocalizedString(@"OK", nil), NULL, NULL);
}
}

return YES;
}

return NO;
}

- (void)showPanelForNote:(NoteObject*)aNote {
currentEncoding = fileEncodingOfNote(aNote);

[note release];
note = [aNote retain];

bzero(&fsRef, sizeof(FSRef));

[noteData release];
if (!(noteData = [[[note delegate] dataFromFileInNotesDirectory:&fsRef forFilename:filenameOfNote(note)] retain])) {
NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"Error: unable to read the contents of the file quotemark%@.quotemark",nil), filenameOfNote(aNote)],
NSLocalizedString(@"The file may no longer exist or has incorrect permissions.",nil), NSLocalizedString(@"OK",nil), NULL, NULL);
return;
}

if (![self checkUnicode]) {

if (!window) {
if (![NSBundle loadNibNamed:@"EncodingsManager" owner:self]) {
NSLog(@"Failed to load EncodingsManager.nib");
NSBeep();
return;
}
}

[helpStringField setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Notational Velocity should assume the file quotemark%@quotemark was saved with the encoding:",nil), filenameOfNote(note)]];
[encodingsPopUpButton setMenu:[self textConversionsMenu]];

//setup panel for given note
if ([self tryToUpdateTextForEncoding:currentEncoding]) {
[NSApp beginSheet:window modalForWindow:[[NSApp delegate] window] modalDelegate:self
didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:NULL];
} else {
//this shouldn't happen
}
}
}

- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo {
[note release];
note = nil;
}


- (NSMenu*)textConversionsMenu {
NSMenu *menu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
NSMenuItem *menuItem = nil;
unsigned int i = 0;

for (i = 0; AllowedEncodings[i]; i++) {
NSStringEncoding thisEncoding = AllowedEncodings[i];

if (thisEncoding == (NSStringEncoding) -1) {
[menu addItem:[NSMenuItem separatorItem]];
continue;
}

menuItem = [[[NSMenuItem alloc] initWithTitle:[NSString localizedNameOfStringEncoding:thisEncoding]
action:@selector(setFileEncodingFromMenu:) keyEquivalent:@""] autorelease];
if (currentEncoding == thisEncoding)
[menuItem setState:NSOnState];

NSString *noteString = (NSString*)CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, (CFDataRef)noteData,
CFStringConvertNSStringEncodingToEncoding(thisEncoding));
//make sure that the conversion works both ways
[menuItem setEnabled:(noteString != nil && [noteString canBeConvertedToEncoding:thisEncoding])];
[noteString release];

[menuItem setTag:(int)thisEncoding];
[menuItem setTarget:self];
[menu addItem:menuItem];
}

[menu setAutoenablesItems:NO];

return menu;
}


- (void)setFileEncodingFromMenu:(id)sender {
if ([sender isKindOfClass:[NSMenuItem class]]) {

NSStringEncoding newEncoding = (unsigned)[sender tag];

//preview conversion in text view
if (![self tryToUpdateTextForEncoding:newEncoding]) {

//set it back to the current encoding--this one doesn't work
int encodingIndex = [encodingsPopUpButton indexOfItemWithTag:(int)currentEncoding];
if (encodingIndex > -1)
[encodingsPopUpButton selectItemAtIndex:encodingIndex];
else
NSLog(@"(setting it back) encoding %u not found", currentEncoding);
}

//if ([[[self contentString] string] canBeConvertedToEncoding:encoding]) {


//}
} else {
NSLog(@"Unknown class sent msg to change encoding: %@", [sender description]);
}
}

- (BOOL)tryToUpdateTextForEncoding:(NSStringEncoding)encoding {

NSString *stringFromData = (NSString*)CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, (CFDataRef)noteData, CFStringConvertNSStringEncodingToEncoding(encoding));

if (stringFromData) {
NSAttributedString *attributedStringFromData = [[NSAttributedString alloc] initWithString:stringFromData];
NSTextStorage *storage = [textView textStorage];
[storage setAttributedString:attributedStringFromData];

[stringFromData release];
[attributedStringFromData release];

currentEncoding = encoding;

int encodingIndex = [encodingsPopUpButton indexOfItemWithTag:(int)currentEncoding];
if (encodingIndex > -1)
[encodingsPopUpButton selectItemAtIndex:encodingIndex];
else
NSLog(@"encoding %u not found", currentEncoding);

return YES;
} else {
NSRunAlertPanel([NSString stringWithFormat:@"%@ is not a valid encoding for this text file.",
[NSString localizedNameOfStringEncoding:encoding]], @"Please try another encoding.", @"OK", NULL, NULL);
}


return NO;
}

- (IBAction)cancelAction:(id)sender {
[NSApp endSheet:window returnCode:0];
[window close];
}

- (IBAction)chooseEncoding:(id)sender {
}

- (BOOL)shouldUpdateNoteFromDisk {
FSCatalogInfo info;
OSStatus err = noErr;
if ((err = [[note delegate] fileInNotesDirectory:&fsRef isOwnedByUs:NULL hasCatalogInfo:&info]) != noErr) {
NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"Error: the modification date of the file quotemark%@quotemark could not be determined because %@",nil),
filenameOfNote(note), [NSString reasonStringFromCarbonFSError:err]], NSLocalizedString(@"The file may no longer exist or has incorrect permissions.",nil),
NSLocalizedString(@"OK",nil), NULL, NULL);
return NO;
}

UTCDateTime fileModifiedDate = fileModifiedDateOfNote(note);
CFAbsoluteTime timeOnDisk, lastTime;
    if ((err = (UCConvertUTCDateTimeToCFAbsoluteTime(&fileModifiedDate, &lastTime) == noErr)) &&
(err = (UCConvertUTCDateTimeToCFAbsoluteTime(&info.contentModDate, &timeOnDisk) == noErr))) {

if (lastTime > timeOnDisk) {
int result = NSRunCriticalAlertPanel([NSString stringWithFormat:NSLocalizedString(@"The note quotemark%@quotemark is newer than its file on disk.",nil), titleOfNote(note)],
NSLocalizedString(@"If you update this note with re-interpreted data from the file, you may overwrite your changes.",nil),
NSLocalizedString(@"Don't Update", @"don't update the note from its file on disk"),
NSLocalizedString(@"Overwrite Note", @"...from file on disk"), NULL);
if (result == NSAlertDefaultReturn) {
NSLog(@"not updating");
return NO;
} else {
NSLog(@"user wants to update");
}
}
    } else {
NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"Error: the modification date of the file quotemark%@quotemark could not be compared because %@",nil),
filenameOfNote(note), [NSString reasonStringFromCarbonFSError:err]], NSLocalizedString(@"This may be due to an error in the program or operating system.",nil),
NSLocalizedString(@"OK",nil), NULL, NULL);
return NO;
    }

return YES;
}

- (IBAction)okAction:(id)sender {

//check whether file mod. date of note is older than mod. date on disk
if ([self shouldUpdateNoteFromDisk]) {
[note setFileEncodingAndReinterpret:currentEncoding];
[[NSApp delegate] contentsUpdatedForNote:note];
}

[NSApp endSheet:window returnCode:1];
[window close];
}

@end
Something went wrong with that request. Please try again.