Camino only: Bug 322093 - Bookmark Import rewrite with progress window and performance improvements (performs majority of import in background thread). Patch by David Haas r=hwaara sr=pink

This commit is contained in:
stridey%gmail.com 2006-09-11 20:14:54 +00:00
Родитель da9955a079
Коммит b8e7d3a0d3
4 изменённых файлов: 176 добавлений и 91 удалений

Просмотреть файл

@ -43,6 +43,9 @@
IBOutlet NSPopUpButton* mBrowserListButton; IBOutlet NSPopUpButton* mBrowserListButton;
IBOutlet NSButton* mCancelButton; IBOutlet NSButton* mCancelButton;
IBOutlet NSButton* mImportButton; IBOutlet NSButton* mImportButton;
IBOutlet NSProgressIndicator* mImportProgressBar;
IBOutlet NSView* mImportView;
IBOutlet NSView* mProgressView;
} }
-(void) buildAvailableFileList; -(void) buildAvailableFileList;
@ -51,5 +54,6 @@
-(IBAction) loadOpenPanel:(id)aSender; -(IBAction) loadOpenPanel:(id)aSender;
-(IBAction) nullAction:(id)aSender; -(IBAction) nullAction:(id)aSender;
-(void) alertSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo; -(void) alertSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
-(void) finishThreadedImport:(BOOL)success fromFile:(NSString *)aFile;
@end @end

Просмотреть файл

@ -47,11 +47,14 @@
-(void) tryAddImportFromBrowser: (NSString *) aBrowserName withBookmarkPath: (NSString *) aPath; -(void) tryAddImportFromBrowser: (NSString *) aBrowserName withBookmarkPath: (NSString *) aPath;
-(void) tryOmniWeb5Import; -(void) tryOmniWeb5Import;
-(void) buildButtonForBrowser:(NSString *) aBrowserName withObject:(id)anObject; -(void) buildButtonForBrowser:(NSString *) aBrowserName withPathArray:(NSArray *)anArray;
-(NSString *) getSaltedBookmarkPathForProfile: (NSString *) aPath; -(NSString *) getSaltedBookmarkPathForProfile: (NSString *) aPath;
-(void) beginImportFrom:(NSString *) aPath intoFolder:(BookmarkFolder *) aFolder; -(void) beginImportFrom:(NSArray *)aPath withTitles:(NSArray *)anArray;
-(void) beginOmniWeb5ImportFrom:(NSArray *)anArray intoFolder:(BookmarkFolder *)aFolder; -(void) beginOmniWeb5ImportFrom:(NSArray *)anArray;
-(void) finishImport:(BOOL)success fromFile:(NSString *)aFile intoFolder:(BookmarkFolder*)aFolder; -(void) finishImport:(BOOL)success fromFiles:(NSArray *)anArray;
-(void) finishThreadedImport:(BOOL)success fromFiles:(NSArray *)anArray;
-(void) showProgressView;
-(void) showImportView;
@end @end
@ -61,8 +64,8 @@
-(void) windowDidLoad -(void) windowDidLoad
{ {
[self showImportView];
[self buildAvailableFileList]; [self buildAvailableFileList];
[[self window] center];
} }
// Check for common webbrower bookmark files and, if they exist, add import buttons. // Check for common webbrower bookmark files and, if they exist, add import buttons.
@ -107,7 +110,7 @@
NSFileManager *fm = [NSFileManager defaultManager]; NSFileManager *fm = [NSFileManager defaultManager];
NSString *fullPathString = [aPath stringByStandardizingPath]; NSString *fullPathString = [aPath stringByStandardizingPath];
if ([fm fileExistsAtPath:fullPathString]) { if ([fm fileExistsAtPath:fullPathString]) {
[self buildButtonForBrowser:aBrowserName withObject:fullPathString]; [self buildButtonForBrowser:aBrowserName withPathArray:[NSArray arrayWithObject:fullPathString]];
} }
} }
@ -131,7 +134,7 @@
} }
if ([haveFiles count] > 0) if ([haveFiles count] > 0)
{ {
[self buildButtonForBrowser:@"OmniWeb 5" withObject:haveFiles]; [self buildButtonForBrowser:@"OmniWeb 5" withPathArray:haveFiles];
} }
} }
@ -153,13 +156,13 @@
return nil; return nil;
} }
-(void) buildButtonForBrowser:(NSString *) aBrowserName withObject:(id)aThingy -(void) buildButtonForBrowser:(NSString *) aBrowserName withPathArray:(NSArray *)anArray
{ {
[mBrowserListButton insertItemWithTitle:aBrowserName atIndex:0]; [mBrowserListButton insertItemWithTitle:aBrowserName atIndex:0];
NSMenuItem *browserItem = [mBrowserListButton itemAtIndex:0]; NSMenuItem *browserItem = [mBrowserListButton itemAtIndex:0];
[browserItem setTarget:self]; [browserItem setTarget:self];
[browserItem setAction:@selector(nullAction:)]; [browserItem setAction:@selector(nullAction:)];
[browserItem setRepresentedObject:aThingy]; [browserItem setRepresentedObject:anArray];
} }
// keeps browsers turned on // keeps browsers turned on
@ -175,22 +178,18 @@
-(IBAction) import:(id)aSender -(IBAction) import:(id)aSender
{ {
// XXX show a spinner, disable the button, postpone to next event loop (to give UI time to update)
NSMenuItem *selectedItem = [mBrowserListButton selectedItem]; NSMenuItem *selectedItem = [mBrowserListButton selectedItem];
BookmarkFolder *importFolder = [[[BookmarkManager sharedBookmarkManager] rootBookmarks] addBookmarkFolder];
NSString *titleString; NSString *titleString;
if ([[selectedItem title] isEqualToString:@"Internet Explorer"]) if ([[selectedItem title] isEqualToString:@"Internet Explorer"])
titleString = [[NSString alloc] initWithString:NSLocalizedString(@"Imported IE Favorites", @"")]; titleString = [NSString stringWithString:NSLocalizedString(@"Imported IE Favorites", @"")];
else else
titleString = [[NSString alloc] initWithFormat:NSLocalizedString(@"Imported %@ Bookmarks", @""), [selectedItem title]]; titleString = [NSString stringWithFormat:NSLocalizedString(@"Imported %@ Bookmarks", @""), [selectedItem title]];
[importFolder setTitle:titleString];
[titleString release];
// Stupid OmniWeb 5 gets its own import function // Stupid OmniWeb 5 gets its own import function
if ( [[selectedItem title] isEqualToString:@"OmniWeb 5"] ) { if ( [[selectedItem title] isEqualToString:@"OmniWeb 5"] ) {
[self beginOmniWeb5ImportFrom:[selectedItem representedObject] intoFolder:importFolder]; [self beginOmniWeb5ImportFrom:[selectedItem representedObject]];
} }
else { else {
[self beginImportFrom:[selectedItem representedObject] intoFolder:importFolder]; [self beginImportFrom:[selectedItem representedObject] withTitles:[NSArray arrayWithObject:titleString]];
} }
} }
@ -207,75 +206,56 @@
types: array]; types: array];
if (result == NSOKButton) { if (result == NSOKButton) {
NSString *pathToFile = [[openPanel filenames] objectAtIndex:0]; NSString *pathToFile = [[openPanel filenames] objectAtIndex:0];
BookmarkFolder *importFolder = [[[BookmarkManager sharedBookmarkManager] rootBookmarks] addBookmarkFolder]; [self beginImportFrom:[NSArray arrayWithObject:pathToFile]
[importFolder setTitle:NSLocalizedString(@"Imported Bookmarks",@"Imported Bookmarks")]; withTitles:[NSArray arrayWithObject:NSLocalizedString(@"Imported Bookmarks",@"Imported Bookmarks")]];
[self beginImportFrom:pathToFile intoFolder:importFolder];
} }
} }
-(void) beginOmniWeb5ImportFrom:(NSArray *)anArray intoFolder:(BookmarkFolder *) aFolder -(void) beginOmniWeb5ImportFrom:(NSArray *)anArray
{ {
[mCancelButton setEnabled:NO];
[mImportButton setEnabled:NO];
NSEnumerator *enumerator = [anArray objectEnumerator]; NSEnumerator *enumerator = [anArray objectEnumerator];
NSMutableArray *titleArray= [NSMutableArray array];
NSString* curFilename = nil; NSString* curFilename = nil;
NSString *curPath = nil;
BOOL success = TRUE; while ( curPath = [enumerator nextObject] )
NSString *curPath;
while ( success && (curPath = [enumerator nextObject] ) )
{ {
curFilename = [curPath lastPathComponent]; curFilename = [curPath lastPathComponent];
// What folder we import into depends on what OmniWeb file we're importing. // What folder we import into depends on what OmniWeb file we're importing.
if ([curFilename isEqualToString:@"Bookmarks.html"] ) if ([curFilename isEqualToString:@"Bookmarks.html"] )
{ {
success = [[BookmarkManager sharedBookmarkManager] importBookmarks:curPath intoFolder:aFolder]; [titleArray addObject:NSLocalizedString(@"Imported OmniWeb 5 Bookmarks", @"Imported OmniWeb 5 Bookmarks")];
} }
else if ([curFilename isEqualToString:@"Favorites.html"] ) else if ([curFilename isEqualToString:@"Favorites.html"] )
{ {
BookmarkFolder *favoriteFolder = [aFolder addBookmarkFolder]; [titleArray addObject:NSLocalizedString(@"OmniWeb Favorites", @"OmniWeb Favorites")];
[favoriteFolder setTitle:NSLocalizedString(@"OmniWeb Favorites", @"OmniWeb Favorites")];
success = [[BookmarkManager sharedBookmarkManager] importBookmarks:curPath intoFolder:favoriteFolder];
} }
else if ([curFilename isEqualToString:@"Published.html"]) else if ([curFilename isEqualToString:@"Published.html"])
{ {
BookmarkFolder *publishedFolder = [aFolder addBookmarkFolder]; [titleArray addObject:NSLocalizedString(@"OmniWeb Published", @"OmniWeb Published")];
[publishedFolder setTitle:NSLocalizedString(@"OmniWeb Published", @"OmniWeb Published")];
success = [[BookmarkManager sharedBookmarkManager] importBookmarks:curPath intoFolder:publishedFolder];
} }
} }
[self beginImportFrom:anArray withTitles:titleArray];
[mCancelButton setEnabled:YES];
[mImportButton setEnabled:YES];
// Non-rigorous reporting of errors
[self finishImport:success fromFile:curFilename intoFolder:aFolder];
} }
-(void) beginImportFrom:(NSString *) aPath intoFolder:(BookmarkFolder *) aFolder -(void) beginImportFrom:(NSArray *) aPathArray withTitles:(NSArray *)aTitleArray
{ {
[mCancelButton setEnabled:NO]; [self showProgressView];
[mImportButton setEnabled:NO]; NSDictionary *aDict = [NSDictionary dictionaryWithObjectsAndKeys: aPathArray, kBookmarkImportPathIndentifier,
aTitleArray, kBookmarkImportNewFolderNameIdentifier, nil];
BOOL success = [[BookmarkManager sharedBookmarkManager] importBookmarks:aPath intoFolder:aFolder]; [NSThread detachNewThreadSelector:@selector(importBookmarksThreadEntry:)
toTarget:[BookmarkManager sharedBookmarkManager]
[mCancelButton setEnabled:YES]; withObject:aDict];
[mImportButton setEnabled:YES];
[self finishImport:success fromFile:[aPath lastPathComponent] intoFolder:aFolder];
} }
-(void) finishImport:(BOOL)success fromFile:(NSString *)aFile intoFolder:(BookmarkFolder*)aFolder -(void) finishThreadedImport:(BOOL)success fromFile:(NSString *)aFile
{ {
//show them the imported bookmarks if import succeeded
if (success) if (success)
{ {
[[self window] orderOut:self];
BrowserWindowController* windowController = [(MainController *)[NSApp delegate] openBrowserWindowWithURL:@"about:bookmarks" andReferrer:nil behind:nil allowPopups:NO]; BrowserWindowController* windowController = [(MainController *)[NSApp delegate] openBrowserWindowWithURL:@"about:bookmarks" andReferrer:nil behind:nil allowPopups:NO];
BookmarkViewController* bmController = [windowController bookmarkViewController]; BookmarkViewController* bmController = [windowController bookmarkViewController];
[bmController setItemToRevealOnLoad:aFolder]; BookmarkFolder *rootFolder = [[BookmarkManager sharedBookmarkManager] rootBookmarks];
BookmarkFolder *newFolder = [rootFolder objectAtIndex:([rootFolder count] - 1)];
[bmController setItemToRevealOnLoad:newFolder];
} }
else else
{ {
@ -291,6 +271,8 @@
[NSString stringWithFormat:NSLocalizedString(@"ImportFailureMessage", @"The file '%@' is not a supported bookmark file type."), aFile] [NSString stringWithFormat:NSLocalizedString(@"ImportFailureMessage", @"The file '%@' is not a supported bookmark file type."), aFile]
); );
} }
[[self window] orderOut:self];
[self showImportView];
} }
-(void) alertSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo -(void) alertSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
@ -298,4 +280,23 @@
[[self window] orderOut:self]; [[self window] orderOut:self];
} }
-(void) showProgressView
{
NSSize viewSize = [mProgressView frame].size;
[[self window] setContentView:mProgressView];
[[self window] setContentSize:viewSize];
[[self window] center];
[mImportProgressBar setUsesThreadedAnimation:YES];
[mImportProgressBar startAnimation:self];
}
-(void) showImportView
{
[mImportProgressBar stopAnimation:self];
NSSize viewSize = [mImportView frame].size;
[[self window] setContentView:mImportView];
[[self window] setContentSize:viewSize];
[[self window] center];
}
@end @end

Просмотреть файл

@ -47,10 +47,12 @@
@class KindaSmartFolderManager; @class KindaSmartFolderManager;
extern NSString* const kBookmarkManagerStartedNotification; extern NSString* const kBookmarkManagerStartedNotification;
extern NSString* const kBookmarksToolbarFolderIdentifier; extern NSString* const kBookmarksToolbarFolderIdentifier;
extern NSString* const kBookmarksMenuFolderIdentifier; extern NSString* const kBookmarksMenuFolderIdentifier;
extern NSString* const kBookmarkImportPathIndentifier;
extern NSString* const kBookmarkImportNewFolderNameIdentifier;
const int kBookmarksContextMenuArrangeSeparatorTag = 100; const int kBookmarksContextMenuArrangeSeparatorTag = 100;
@ -142,7 +144,7 @@ const int kBookmarksContextMenuArrangeSeparatorTag = 100;
// Importing bookmarks // Importing bookmarks
- (void)startImportBookmarks; - (void)startImportBookmarks;
- (BOOL)importBookmarks:(NSString *)pathToFile intoFolder:(BookmarkFolder *)aFolder; - (void)importBookmarksThreadEntry:(NSDictionary *)aDict;
// Writing bookmark files // Writing bookmark files
- (void)writeHTMLFile:(NSString *)pathToFile; - (void)writeHTMLFile:(NSString *)pathToFile;

Просмотреть файл

@ -67,13 +67,20 @@
NSString* const kBookmarkManagerStartedNotification = @"BookmarkManagerStartedNotification"; NSString* const kBookmarkManagerStartedNotification = @"BookmarkManagerStartedNotification";
// root bookmark folder identifiers (must be unique!) // root bookmark folder identifiers (must be unique!)
NSString* const kBookmarksToolbarFolderIdentifier = @"BookmarksToolbarFolder"; NSString* const kBookmarksToolbarFolderIdentifier = @"BookmarksToolbarFolder";
NSString* const kBookmarksMenuFolderIdentifier = @"BookmarksMenuFolder"; NSString* const kBookmarksMenuFolderIdentifier = @"BookmarksMenuFolder";
static NSString* const kTop10BookmarksFolderIdentifier = @"Top10BookmarksFolder"; static NSString* const kTop10BookmarksFolderIdentifier = @"Top10BookmarksFolder";
static NSString* const kRendezvousFolderIdentifier = @"RendezvousFolder"; // aka Bonjour static NSString* const kRendezvousFolderIdentifier = @"RendezvousFolder"; // aka Bonjour
static NSString* const kAddressBookFolderIdentifier = @"AddressBookFolder"; static NSString* const kAddressBookFolderIdentifier = @"AddressBookFolder";
static NSString* const kHistoryFolderIdentifier = @"HistoryFolder"; static NSString* const kHistoryFolderIdentifier = @"HistoryFolder";
NSString* const kBookmarkImportPathIndentifier = @"path";
NSString* const kBookmarkImportNewFolderNameIdentifier = @"title";
static NSString* const kBookmarkImportStatusIndentifier = @"flag";
static NSString* const kBookmarkImportNewFolderIdentifier = @"folder";
static NSString* const kBookmarkImportNewFolderIndexIdentifier = @"index";
// these are suggested indices; we only use them to order the root folders, not to access them. // these are suggested indices; we only use them to order the root folders, not to access them.
enum { enum {
@ -111,6 +118,7 @@ enum {
- (BOOL)importHTMLFile:(NSString *)pathToFile intoFolder:(BookmarkFolder *)aFolder; - (BOOL)importHTMLFile:(NSString *)pathToFile intoFolder:(BookmarkFolder *)aFolder;
- (BOOL)importCaminoXMLFile:(NSString *)pathToFile intoFolder:(BookmarkFolder *)aFolder settingToolbarFolder:(BOOL)setToolbarFolder; - (BOOL)importCaminoXMLFile:(NSString *)pathToFile intoFolder:(BookmarkFolder *)aFolder settingToolbarFolder:(BOOL)setToolbarFolder;
- (BOOL)importPropertyListFile:(NSString *)pathToFile intoFolder:(BookmarkFolder *)aFolder; - (BOOL)importPropertyListFile:(NSString *)pathToFile intoFolder:(BookmarkFolder *)aFolder;
- (void)importBookmarksThreadReturn:(NSDictionary *)aDict;
- (BOOL)readOperaFile:(NSString *)pathToFile intoFolder:(BookmarkFolder *)aFolder; - (BOOL)readOperaFile:(NSString *)pathToFile intoFolder:(BookmarkFolder *)aFolder;
@ -601,9 +609,14 @@ static BookmarkManager* gBookmarkManager = nil;
return [mRootBookmarks itemWithUUID:uuid]; return [mRootBookmarks itemWithUUID:uuid];
} }
// only the main thread can get the undo manager.
// imports (on a background thread) get nothing, which is ok.
// this keeps things nice and thread safe
-(NSUndoManager *) undoManager -(NSUndoManager *) undoManager
{ {
return mUndoManager; if ([NSThread inMainThread])
return mUndoManager;
return nil;
} }
- (void)setPathToBookmarkFile:(NSString *)aString - (void)setPathToBookmarkFile:(NSString *)aString
@ -1466,39 +1479,104 @@ static BookmarkManager* gBookmarkManager = nil;
[mImportDlgController showWindow:nil]; [mImportDlgController showWindow:nil];
} }
- (BOOL)importBookmarks:(NSString *)pathToFile intoFolder:(BookmarkFolder *)aFolder - (void)importBookmarksThreadEntry:(NSDictionary *)aDict
{ {
// I feel dirty doing it this way. But we'll check file extension NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
// to figure out how to handle this. BOOL success = TRUE;
NSUndoManager *undoManager = [self undoManager]; int currentFile = 0;
[undoManager beginUndoGrouping]; NSArray *pathArray = [aDict objectForKey:kBookmarkImportPathIndentifier];
BOOL success = NO; NSArray *titleArray = [aDict objectForKey:kBookmarkImportNewFolderNameIdentifier];
NSString *extension =[pathToFile pathExtension]; NSString *pathToFile;
if ([extension isEqualToString:@""]) // we'll go out on a limb here NSString *aTitle;
success = [self readOperaFile:pathToFile intoFolder:aFolder]; BookmarkFolder *topImportFolder = [[BookmarkFolder alloc] init];
else if ([extension isEqualToString:@"html"] || [extension isEqualToString:@"htm"]) BookmarkFolder *importFolder = topImportFolder;
success = [self importHTMLFile:pathToFile intoFolder:aFolder];
else if ([extension isEqualToString:@"xml"]) NSEnumerator *pathEnumerator = [pathArray objectEnumerator];
success = [self importCaminoXMLFile:pathToFile intoFolder:aFolder settingToolbarFolder:NO]; NSEnumerator *titleEnumerator = [titleArray objectEnumerator];
else if ([extension isEqualToString:@"plist"] || !success)
success = [self importPropertyListFile:pathToFile intoFolder:aFolder]; [self startSuppressingChangeNotifications];
// we don't know the extension, or we failed to load. we'll take another
// crack at it trying everything we know. while (success && (pathToFile = [pathEnumerator nextObject]) )
if (!success) { {
success = [self readOperaFile:pathToFile intoFolder:aFolder]; if (!importFolder)
{
importFolder = [[BookmarkFolder alloc] init];
}
NSString *extension =[pathToFile pathExtension];
if ([extension isEqualToString:@""]) // we'll go out on a limb here
success = [self readOperaFile:pathToFile intoFolder:importFolder];
else if ([extension isEqualToString:@"html"] || [extension isEqualToString:@"htm"])
success = [self importHTMLFile:pathToFile intoFolder:importFolder];
else if ([extension isEqualToString:@"xml"])
success = [self importCaminoXMLFile:pathToFile intoFolder:importFolder settingToolbarFolder:NO];
else if ([extension isEqualToString:@"plist"] || !success)
success = [self importPropertyListFile:pathToFile intoFolder:importFolder];
// we don't know the extension, or we failed to load. we'll take another
// crack at it trying everything we know.
if (!success) { if (!success) {
success = [self importHTMLFile:pathToFile intoFolder:aFolder]; success = [self readOperaFile:pathToFile intoFolder:importFolder];
if (!success) { if (!success) {
success = [self importCaminoXMLFile:pathToFile intoFolder:aFolder settingToolbarFolder:NO]; success = [self importHTMLFile:pathToFile intoFolder:importFolder];
if (!success) {
success = [self importCaminoXMLFile:pathToFile intoFolder:importFolder settingToolbarFolder:NO];
}
} }
} }
aTitle = [titleEnumerator nextObject];
if (!aTitle)
aTitle = NSLocalizedString(@"Imported Bookmarks",@"Imported Bookmarks");
[importFolder setTitle:aTitle];
if (importFolder != topImportFolder)
{
[topImportFolder appendChild:importFolder];
[importFolder release];
}
importFolder = nil;
currentFile++;
} }
[[undoManager prepareWithInvocationTarget:[self rootBookmarks]] deleteChild:aFolder];
[undoManager endUndoGrouping]; [self stopSuppressingChangeNotifications];
[undoManager setActionName:NSLocalizedString(@"Import Bookmarks", @"")];
return success; NSDictionary *returnDict = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:success],kBookmarkImportStatusIndentifier,
[NSNumber numberWithInt:currentFile], kBookmarkImportNewFolderIndexIdentifier,
pathArray, kBookmarkImportPathIndentifier,
topImportFolder, kBookmarkImportNewFolderIdentifier,
nil];
[self performSelectorOnMainThread:@selector(importBookmarksThreadReturn:)
withObject:returnDict
waitUntilDone:YES];
// release the top-level import folder we allocated - somebody else retains it by now if still needed.
[topImportFolder release];
[pool release];
} }
-(void)importBookmarksThreadReturn:(NSDictionary *)aDict
{
BOOL success = [[aDict objectForKey:kBookmarkImportStatusIndentifier] boolValue];
NSArray *fileArray = [aDict objectForKey:kBookmarkImportPathIndentifier];
int currentIndex = [[aDict objectForKey:kBookmarkImportNewFolderIndexIdentifier] intValue];
BookmarkFolder *rootFolder = [self rootBookmarks];
BookmarkFolder *importFolder = [aDict objectForKey:kBookmarkImportNewFolderIdentifier];
if (success || ((currentIndex - [fileArray count]) > 0) )
{
NSUndoManager *undoManager = [self undoManager];
[rootFolder appendChild:importFolder];
[undoManager setActionName:NSLocalizedString(@"Import Bookmarks", @"")];
}
[mImportDlgController finishThreadedImport:success
fromFile:[[fileArray objectAtIndex:(--currentIndex)] lastPathComponent] ];
}
// spits out text file as NSString with "proper" encoding based on pretty shitty detection // spits out text file as NSString with "proper" encoding based on pretty shitty detection
- (NSString *)decodedTextFile:(NSString *)pathToFile - (NSString *)decodedTextFile:(NSString *)pathToFile
{ {