/* UtilityFunctions.h Utility static functions for the FileManager class of ProjectManager. Copyright (C) 2005 Saso Kiselkov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #import #import #import #import #import #import #import #import #import #import #import #import "FileManager.h" /** * This function pops up an alert panel describing an NSError object. The * description of an error is taken from it's NSLocalizedDescriptionKey * userInfo entry. * * @param error The error which to describe. * @param aTitle The title of the alert panel. * @param aDescription An additional description of the error. If specified, * this argument is printed out in the alert panel's main text area, * followed by a colon and a description of the NSError object. If it * is `nil', only the error's description is printed in the panel. * @param firstButton The title of the first button. If nothing is specified, * this defaults to "OK". * @param secondButton The title of the second button. If nothing is * specified, this button is ommited. * @param thirdButton The title of the third button. If nothing is specified, * this button is ommited. * * @return The code of the clicked button to dismiss the panel, as returned * by NSRunAlertPanel. */ static int DescribeError (NSError * error, NSString * aTitle, NSString * aDescription, NSString * firstButton, NSString * secondButton, NSString * thirdButton, ...) { NSString * description; NSString * prefix, * errorDescription; if (aDescription == nil) { prefix = @""; } else { va_list arglist; va_start (arglist, thirdButton); prefix = [NSString stringWithFormat: aDescription arguments: arglist]; va_end (arglist); prefix = [prefix stringByAppendingString: _(@": ")]; } errorDescription = [[error userInfo] objectForKey: NSLocalizedDescriptionKey]; description = [NSString stringWithFormat: @"%@%@", prefix, errorDescription]; return NSRunAlertPanel (aTitle, description, firstButton, secondButton, thirdButton); } /** * This function is a shorthand for creating NSError objects and setting * error object pointers in the FileManager class code. The NSError * object's error domain is always set ProjectFilesErrorDomain. * * @param ptr A pointer to an area which is to be filled with the NSError * object. In case the passed pointer is NULL, this function immediately * returns and doesn't create any NSError object. * @param code The code of the error. * @param reasonFormat A format string specifying the reason of the error. * This will be put into the error's userInfo dictionary under the * NSLocalizedDescriptionKey. The remaining variable arguments are * arguments for the format string. */ static void SetFileError (NSError ** ptr, int code, NSString * reasonFormat, ...) { if (ptr != NULL) { NSString * reason; NSDictionary * userInfo; va_list arglist; va_start (arglist, reasonFormat); reason = [[[NSString alloc] initWithFormat: reasonFormat arguments: arglist] autorelease]; va_end (arglist); userInfo = [NSDictionary dictionaryWithObject: reason forKey: NSLocalizedDescriptionKey]; *ptr = [NSError errorWithDomain: ProjectFilesErrorDomain code: code userInfo: userInfo]; } } /** * Posts a ProjectFilesDidChangeNotification to the default notification * center. The notification's user info will be structured like this: * { * Project = ""; * Category = ""; * } * * @param sender The sender FileManager of the notification. * @param category The category which will be declared in the user info * under the `Category' key. Passing `nil' will result in the * `Category' key not being present in the user info dictionary. */ static void PostFilesChangedNotification (FileManager * sender, NSString * category) { NSDictionary * userInfo; NSString * projectPath; static NSNotificationCenter * nc = nil; if (nc == nil) { nc = [NSNotificationCenter defaultCenter]; } projectPath = [[sender document] fileName]; if (category != nil) { userInfo = [NSDictionary dictionaryWithObjectsAndKeys: projectPath, @"Project", category, @"Category", nil]; } else { userInfo = [NSDictionary dictionaryWithObject: projectPath forKey: @"Project"]; } [nc postNotificationName: ProjectFilesDidChangeNotification object: sender userInfo: userInfo]; } /** * Sets the text field `tf' to editable or non-editable, based on `flag'. * If the text field is set to editable, it's also made to draw it's * background and it's target is set to `target'. Otherwise, it's made * to not display it's background and it's target is reset. */ static inline void SetTextFieldEnabled (NSTextField * tf, BOOL flag) { if ([tf isEnabled] != flag) { [tf setEnabled: flag]; [tf setEditable: flag]; [tf setSelectable: flag]; [tf setDrawsBackground: flag]; } } /** * Constructs a human-readable description of the data size `size'. * E.g. if the value is greater than 1024, then the prefix 'kB' is * appended to indicate kilobytes and the number is represented as * a fraction of this unit. * * @return The resulting string. */ static inline NSString * MakeSizeStringFromValue (unsigned long long size) { if (size < 1024) { return [NSString stringWithFormat: _(@"%i bytes"), size]; } else if (size < 1024 * 1024) { return [NSString stringWithFormat: _(@"%.2f kB"), (double) size / 1024]; } else if (size < 1024 * 1024 * 1024) { return [NSString stringWithFormat: _(@"%.2f MB"), (double) size / (1024 * 1024)]; } else { return [NSString stringWithFormat: _(@"%.2f GB"), (double) size / (1024 * 1024 * 1024)]; } } /** * This function translates `linkTarget', which was the target of a * link originally located at `oldLocation', to correctly point to * it's target from `newLocation'. * * @return The translocated link target. */ static inline NSString * TranslocateLinkTarget (NSString * linkTarget, NSString * oldLocation, NSString * newLocation) { // absolute paths do not need to be translocated if ([linkTarget isAbsolutePath]) { return linkTarget; } else { return [newLocation stringByConstructingRelativePathTo: [oldLocation stringByConcatenatingWithPath: linkTarget]]; } } /** * Removes the directory (and any superdirectories of it) at `aPath' * which are empty. */ static BOOL PurgeUnneededDirectories (NSString * aPath, NSError ** error) { NSFileManager * fm = [NSFileManager defaultManager]; for (; [[fm directoryContentsAtPath: aPath] count] == 0; aPath = [aPath stringByDeletingLastPathComponent]) { if (![fm removeFileAtPath: aPath handler: nil]) { SetFileError (error, ProjectFilesDeletionError, _(@"Couldn't delete directory at path %@."), aPath); return NO; } } return YES; }