Skip to content
Newer
Older
100755 295 lines (240 sloc) 11.1 KB
c5cfe65 @ttscoff Slightly better way to handle adding scroll reset script.
ttscoff authored Jan 14, 2011
1 /*Copyright (c) 2010, Zachary Schneirov. All rights reserved.
2 Redistribution and use in source and binary forms, with or without modification, are permitted
3 provided that the following conditions are met:
4 - Redistributions of source code must retain the above copyright notice, this list of conditions
5 and the following disclaimer.
6 - Redistributions in binary form must reproduce the above copyright notice, this list of
7 conditions and the following disclaimer in the documentation and/or other materials provided with
8 the distribution.
9 - Neither the name of Notational Velocity nor the names of its contributors may be used to endorse
10 or promote products derived from this software without specific prior written permission. */
11
12
13 #import "EncodingsManager.h"
14 #import "NoteObject.h"
15 #import "NotationFileManager.h"
16 #import "NSData_transformations.h"
17 #import "NSString_NV.h"
18
19 @implementation EncodingsManager
20
21 static const NSStringEncoding AllowedEncodings[] = {
22 /* Western */
23 NSISOLatin1StringEncoding, // ISO Latin 1
24 (NSStringEncoding) 0x80000203, // ISO Latin 3
25 (NSStringEncoding) 0x8000020F, // ISO Latin 9
26 NSMacOSRomanStringEncoding, // Mac
27 NSWindowsCP1252StringEncoding, // Windows
28 /* Baltic */
29 (NSStringEncoding) -1,
30 (NSStringEncoding) 0x8000020D, // ISO Latin 7
31 (NSStringEncoding) 0x80000507, // Windows
32 /* Central European */
33 (NSStringEncoding) -1,
34 NSISOLatin2StringEncoding, // ISO Latin 2
35 (NSStringEncoding) 0x80000204, // ISO Latin 4
36 (NSStringEncoding) 0x8000001D, // Mac
37 NSWindowsCP1250StringEncoding, // Windows
38 /* Cyrillic */
39 (NSStringEncoding) -1,
40 (NSStringEncoding) 0x80000A02, // KOI8-R
41 (NSStringEncoding) 0x80000205, // ISO Latin 5
42 (NSStringEncoding) 0x80000007, // Mac
43 NSWindowsCP1251StringEncoding, // Windows
44 /* Japanese */
45 (NSStringEncoding) -1, // Divider
46 (NSStringEncoding) 0x80000A01, // ShiftJIS
47 NSISO2022JPStringEncoding, // ISO-2022-JP
48 NSJapaneseEUCStringEncoding, // EUC
49 (NSStringEncoding) 0x80000001, // Mac
50 NSShiftJISStringEncoding, // Windows
51 /* Simplified Chinese */
52 (NSStringEncoding) -1, // Divider
53 (NSStringEncoding) 0x80000632, // GB 18030
54 (NSStringEncoding) 0x80000631, // GBK
55 (NSStringEncoding) 0x80000930, // EUC
56 (NSStringEncoding) 0x80000019, // Mac
57 (NSStringEncoding) 0x80000421, // Windows
58 /* Traditional Chinese */
59 (NSStringEncoding) -1, // Divider
60 (NSStringEncoding) 0x80000A03, // Big5
61 (NSStringEncoding) 0x80000A06, // Big5 HKSCS
62 (NSStringEncoding) 0x80000931, // EUC
63 (NSStringEncoding) 0x80000002, // Mac
64 (NSStringEncoding) 0x80000423, // Windows
65 /* Korean */
66 (NSStringEncoding) -1, // Divider
67 (NSStringEncoding) 0x80000940, // EUC
68 (NSStringEncoding) 0x80000003, // Mac
69 (NSStringEncoding) 0x80000422, // Windows
70 /* Hebrew */
71 (NSStringEncoding) -1, // Divider
72 (NSStringEncoding) 0x80000208, // ISO-8859-8
73 (NSStringEncoding) 0x80000005, // Mac
74 (NSStringEncoding) 0x80000505, // Windows
75 /* End */ 0 };
76
77
78 + (EncodingsManager *)sharedManager {
79 static EncodingsManager *man = nil;
80 if (!man)
81 man = [[EncodingsManager alloc] init];
82 return man;
83 }
84
85 - (BOOL)checkUnicode {
86
87 if (NSUnicodeStringEncoding == currentEncoding || NSUTF8StringEncoding == currentEncoding) {
88
89 NSString * alertTitleString = NSLocalizedString(@"quotemark%@quotemark is a Unicode file and not directly interpretable using plain text encodings.",
90 @"alert title when converting from unicode");
91 if (NSRunAlertPanel([NSString stringWithFormat:alertTitleString, filenameOfNote(note)],
92 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"),
93 NSLocalizedString(@"OK", nil), NSLocalizedString(@"Open in TextEdit", @"title of button for opening the current note in text edit"), NULL) != NSAlertDefaultReturn) {
94
95 NSString *textEditPath = [[NSWorkspace sharedWorkspace] absolutePathForAppBundleWithIdentifier:@"com.apple.TextEdit"];
96 if (textEditPath) {
97 NSString *resolvedPath = [note noteFilePath];
98 if (!resolvedPath) {
99 NSRunAlertPanel(NSLocalizedString(@"Could not locate the note file.", nil), NSLocalizedString(@"Does it still exist?", nil),
100 NSLocalizedString(@"I'll Go See", @"... if it exists"), NULL, NULL);
101 } else {
102 [[NSWorkspace sharedWorkspace] openFile:resolvedPath withApplication:textEditPath];
103 }
104 } else {
105 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);
106 }
107 }
108
109 return YES;
110 }
111
112 return NO;
113 }
114
115 - (void)showPanelForNote:(NoteObject*)aNote {
116 currentEncoding = fileEncodingOfNote(aNote);
117
118 [note release];
119 note = [aNote retain];
120
121 bzero(&fsRef, sizeof(FSRef));
122
123 [noteData release];
124 if (!(noteData = [[[note delegate] dataFromFileInNotesDirectory:&fsRef forFilename:filenameOfNote(note)] retain])) {
125 NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"Error: unable to read the contents of the file quotemark%@.quotemark",nil), filenameOfNote(aNote)],
126 NSLocalizedString(@"The file may no longer exist or has incorrect permissions.",nil), NSLocalizedString(@"OK",nil), NULL, NULL);
127 return;
128 }
129
130 if (![self checkUnicode]) {
131
132 if (!window) {
133 if (![NSBundle loadNibNamed:@"EncodingsManager" owner:self]) {
134 NSLog(@"Failed to load EncodingsManager.nib");
135 NSBeep();
136 return;
137 }
138 }
139
140 [helpStringField setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Notational Velocity should assume the file quotemark%@quotemark was saved with the encoding:",nil), filenameOfNote(note)]];
141 [encodingsPopUpButton setMenu:[self textConversionsMenu]];
142
143 //setup panel for given note
144 if ([self tryToUpdateTextForEncoding:currentEncoding]) {
145 [NSApp beginSheet:window modalForWindow:[[NSApp delegate] window] modalDelegate:self
146 didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:NULL];
147 } else {
148 //this shouldn't happen
149 }
150 }
151 }
152
153 - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo {
154 [note release];
155 note = nil;
156 }
157
158
159 - (NSMenu*)textConversionsMenu {
160 NSMenu *menu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
161 NSMenuItem *menuItem = nil;
162 unsigned int i = 0;
163
164 for (i = 0; AllowedEncodings[i]; i++) {
165 NSStringEncoding thisEncoding = AllowedEncodings[i];
166
167 if (thisEncoding == (NSStringEncoding) -1) {
168 [menu addItem:[NSMenuItem separatorItem]];
169 continue;
170 }
171
172 menuItem = [[[NSMenuItem alloc] initWithTitle:[NSString localizedNameOfStringEncoding:thisEncoding]
173 action:@selector(setFileEncodingFromMenu:) keyEquivalent:@""] autorelease];
174 if (currentEncoding == thisEncoding)
175 [menuItem setState:NSOnState];
176
177 NSString *noteString = (NSString*)CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, (CFDataRef)noteData,
178 CFStringConvertNSStringEncodingToEncoding(thisEncoding));
179 //make sure that the conversion works both ways
180 [menuItem setEnabled:(noteString != nil && [noteString canBeConvertedToEncoding:thisEncoding])];
181 [noteString release];
182
183 [menuItem setTag:(int)thisEncoding];
184 [menuItem setTarget:self];
185 [menu addItem:menuItem];
186 }
187
188 [menu setAutoenablesItems:NO];
189
190 return menu;
191 }
192
193
194 - (void)setFileEncodingFromMenu:(id)sender {
195 if ([sender isKindOfClass:[NSMenuItem class]]) {
196
197 NSStringEncoding newEncoding = (unsigned)[sender tag];
198
199 //preview conversion in text view
200 if (![self tryToUpdateTextForEncoding:newEncoding]) {
201
202 //set it back to the current encoding--this one doesn't work
b637fb7 @ttscoff Jumping fork ahead to nvALT2 HEAD
ttscoff authored May 19, 2011
203 [encodingsPopUpButton selectItemWithTag:(int)currentEncoding];
204 }
c5cfe65 @ttscoff Slightly better way to handle adding scroll reset script.
ttscoff authored Jan 15, 2011
205 } else {
206 NSLog(@"Unknown class sent msg to change encoding: %@", [sender description]);
207 }
208 }
209
210 - (BOOL)tryToUpdateTextForEncoding:(NSStringEncoding)encoding {
211
212 NSString *stringFromData = (NSString*)CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, (CFDataRef)noteData, CFStringConvertNSStringEncodingToEncoding(encoding));
213
214 if (stringFromData) {
215 NSAttributedString *attributedStringFromData = [[NSAttributedString alloc] initWithString:stringFromData];
216 NSTextStorage *storage = [textView textStorage];
217 [storage setAttributedString:attributedStringFromData];
218
219 [stringFromData release];
220 [attributedStringFromData release];
221
222 currentEncoding = encoding;
223
b637fb7 @ttscoff Jumping fork ahead to nvALT2 HEAD
ttscoff authored May 20, 2011
224 [encodingsPopUpButton selectItemWithTag:(int)currentEncoding];
c5cfe65 @ttscoff Slightly better way to handle adding scroll reset script.
ttscoff authored Jan 15, 2011
225
226 return YES;
227 } else {
228 NSRunAlertPanel([NSString stringWithFormat:@"%@ is not a valid encoding for this text file.",
b637fb7 @ttscoff Jumping fork ahead to nvALT2 HEAD
ttscoff authored May 20, 2011
229 [NSString localizedNameOfStringEncoding:encoding]], NSLocalizedString(@"Please try another encoding.", @"prompt for choosing an incompatible text encoding"),
230 NSLocalizedString(@"OK",nil), NULL, NULL);
c5cfe65 @ttscoff Slightly better way to handle adding scroll reset script.
ttscoff authored Jan 15, 2011
231 }
232
233
234 return NO;
235 }
236
237 - (IBAction)cancelAction:(id)sender {
238 [NSApp endSheet:window returnCode:0];
239 [window close];
240 }
241
242 - (IBAction)chooseEncoding:(id)sender {
243 }
244
245 - (BOOL)shouldUpdateNoteFromDisk {
246 FSCatalogInfo info;
247 OSStatus err = noErr;
248 if ((err = [[note delegate] fileInNotesDirectory:&fsRef isOwnedByUs:NULL hasCatalogInfo:&info]) != noErr) {
249 NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"Error: the modification date of the file quotemark%@quotemark could not be determined because %@",nil),
250 filenameOfNote(note), [NSString reasonStringFromCarbonFSError:err]], NSLocalizedString(@"The file may no longer exist or has incorrect permissions.",nil),
251 NSLocalizedString(@"OK",nil), NULL, NULL);
252 return NO;
253 }
254
255 UTCDateTime fileModifiedDate = fileModifiedDateOfNote(note);
256 CFAbsoluteTime timeOnDisk, lastTime;
257 if ((err = (UCConvertUTCDateTimeToCFAbsoluteTime(&fileModifiedDate, &lastTime) == noErr)) &&
258 (err = (UCConvertUTCDateTimeToCFAbsoluteTime(&info.contentModDate, &timeOnDisk) == noErr))) {
259
260 if (lastTime > timeOnDisk) {
261 int result = NSRunCriticalAlertPanel([NSString stringWithFormat:NSLocalizedString(@"The note quotemark%@quotemark is newer than its file on disk.",nil), titleOfNote(note)],
262 NSLocalizedString(@"If you update this note with re-interpreted data from the file, you may overwrite your changes.",nil),
263 NSLocalizedString(@"Don't Update", @"don't update the note from its file on disk"),
264 NSLocalizedString(@"Overwrite Note", @"...from file on disk"), NULL);
265 if (result == NSAlertDefaultReturn) {
266 NSLog(@"not updating");
267 return NO;
268 } else {
269 NSLog(@"user wants to update");
270 }
271 }
272 } else {
273 NSRunAlertPanel([NSString stringWithFormat:NSLocalizedString(@"Error: the modification date of the file quotemark%@quotemark could not be compared because %@",nil),
274 filenameOfNote(note), [NSString reasonStringFromCarbonFSError:err]], NSLocalizedString(@"This may be due to an error in the program or operating system.",nil),
275 NSLocalizedString(@"OK",nil), NULL, NULL);
276 return NO;
277 }
278
279 return YES;
280 }
281
282 - (IBAction)okAction:(id)sender {
283
284 //check whether file mod. date of note is older than mod. date on disk
285 if ([self shouldUpdateNoteFromDisk]) {
286 [note setFileEncodingAndReinterpret:currentEncoding];
287 [[NSApp delegate] contentsUpdatedForNote:note];
288 }
289
290 [NSApp endSheet:window returnCode:1];
291 [window close];
292 }
293
294 @end
Something went wrong with that request. Please try again.