Main Page | Alphabetical List | Class List | Directories | File List | Class Members | Related Pages

DownAndOutController.m

00001 //
00002 //  DownAndOutController.m
00003 //  DownAndOutª
00004 //
00005 //  Created by Fritz Anderson on Mon Aug 18 2003.
00006 //  Copyright (c) 2003 Trustees of the University of Chicago. All rights reserved.
00007 //  This program is free software; you can redistribute it and/or modify
00008 //  it under the terms of the GNU General Public License as published by
00009 //  the Free Software Foundation; either version 2 of the License, or
00010 //  (at your option) any later version.
00011 //  
00012 //  This program is distributed in the hope that it will be useful,
00013 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 //  GNU General Public License for more details.
00016 //  
00017 //  You should have received a copy of the GNU General Public License
00018 //  along with this program; if not, write to the Free Software
00019 //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020 //
00021 
00022 #define USE_DAPREFERENCES   1
00023 
00024 #import "DownAndOutController.h"
00025 #import "DownAndOutView.h"
00026 #import "DAApplication.h"
00027 
00028 #if USE_DAPREFERENCES
00029 #include "DAPreferences.h"
00030 
00031 static DAPreferences *          sPreferences = nil;
00032 #endif
00033 
00035 #define DEFAULT_LOGOUT      300
00036 
00037 #define DEFAULT_SHOULD_MOVE YES
00038 
00039 #define DEFAULT_MESSAGE     @"%n will log out automatically in %t"
00040 
00041 #define DEFAULT_RADIUS      30
00042 
00043 @implementation DownAndOutController
00044 
00045 static DownAndOutController *   sMainController = nil;
00046 static NSArray *                sTags = nil;
00047 
00050 + (void) initialize
00051 {
00052     if (self == [DownAndOutController class]) {
00053         NSDictionary *          stdDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
00054             [NSNumber numberWithInt: DEFAULT_LOGOUT], @"secondsBeforeLogout",
00055             [NSNumber numberWithBool: DEFAULT_SHOULD_MOVE], @"shouldMove",
00056             [NSNumber numberWithBool: NO], @"usesImage",
00057             [NSNumber numberWithInt: DEFAULT_RADIUS], @"clockRadius",
00058             DEFAULT_MESSAGE, @"messageText",
00059             nil];
00060 #if USE_DAPREFERENCES
00061         sPreferences = [[DAPreferences alloc] initWithDefaults: stdDefaults];
00062 #else
00063         ScreenSaverDefaults *   defaults = [ScreenSaverDefaults defaultsForModuleWithName: MODULE_NAME];
00064         [defaults registerDefaults: stdDefaults];
00065 #endif
00066 
00067         sTags = [[NSArray alloc] initWithObjects:
00068             @"%s", @"%t", @"%n", @"%u", nil
00069             ];      
00070     }
00071 }
00072 
00073 - (id) initAsPreview: (BOOL) inIsPreview forView: (DownAndOutView *) aView
00074 {
00075 #if USE_DAPREFERENCES
00076     DAPreferences *         defaults = sPreferences;
00077 #else
00078     ScreenSaverDefaults *   defaults = [ScreenSaverDefaults defaultsForModuleWithName: MODULE_NAME];
00079 #endif
00080     
00081     view = aView;
00082     
00083     if (!inIsPreview && !sMainController)
00084         sMainController = self;
00085 
00086     secondsBeforeLogout = [defaults integerForKey: @"secondsBeforeLogout"];
00087     shouldMove = [defaults boolForKey: @"shouldMove"];
00088     
00089     if ([defaults boolForKey: @"usesImage"]) {
00090         NSData *    imageData = [defaults dataForKey: @"addedImage"];
00091         
00092         addedImage = (NSImage *) [NSUnarchiver unarchiveObjectWithData: imageData];
00093         [addedImage retain];
00094     }
00095     else
00096         addedImage = nil;
00097     
00098     messageText = [[defaults stringForKey: @"messageText"] retain];
00099     
00100     [view setClockRadius: [defaults integerForKey: @"clockRadius"]];  //  This is important to initializing the view.
00101         
00102     return self;
00103 }
00104 
00105 - (void) dispose
00106 {
00107     [messageText release];
00108     [addedImage release];
00109 }
00110 
00111 - (NSPanel *) panel
00112 {
00113     return panel;
00114 }
00115 
00118 - (void) colorMessageField
00119 {
00120     NSTextStorage *     storage = [messageField textStorage];
00121     NSString *          content = [storage string];
00122     NSRange             contentRange = NSMakeRange(0, [content length]);
00123     
00124     [storage removeAttribute: NSForegroundColorAttributeName
00125                        range: contentRange];
00126     
00127     NSEnumerator *      iter = [sTags objectEnumerator];
00128     NSString *          curr;
00129     
00130     while (curr = [iter nextObject]) {
00131         NSRange         found = { 0, 0 };
00132         do {
00133             found = [content rangeOfString: curr
00134                                    options: NSLiteralSearch 
00135                                      range: NSMakeRange(NSMaxRange(found),
00136                                         contentRange.length - NSMaxRange(found))];
00137             if (found.location != NSNotFound) {
00138                 [storage addAttribute: NSForegroundColorAttributeName
00139                                 value: [NSColor blueColor] 
00140                                 range: found];
00141             }
00142         } while (NSLocationInRange(found.location, contentRange));
00143     }
00144 }
00145 
00148 - (void) awakeFromNib
00149 {
00150 #if USE_DAPREFERENCES
00151     DAPreferences *         defaults = sPreferences;
00152 #else
00153     ScreenSaverDefaults *   defaults = [ScreenSaverDefaults defaultsForModuleWithName: MODULE_NAME];
00154 #endif
00155 
00156     [self setSecondsBeforeLogout: secondsBeforeLogout];
00157     if (shouldMove)
00158         [movementMatrix selectCellAtRow: 0 column: 0];
00159     else
00160         [movementMatrix selectCellAtRow: 1 column: 0];
00161     [imageWell setImage: addedImage];
00162     [imageClear setEnabled: (addedImage != nil)];
00163         
00164     [[messageField textStorage]
00165         replaceCharactersInRange: NSMakeRange(0, [[messageField textStorage] length])
00166         withString: messageText];
00167     [self colorMessageField];
00168 
00169     [sizeSlider setFloatValue: [defaults integerForKey: @"clockRadius"]];
00170 }
00171 
00175 - (void) textDidChange: (NSNotification *) notice
00176 {
00177     if ([notice object] == messageField)
00178         [self colorMessageField];
00179 }
00180 
00181 - (IBAction) moveSelected: (id) sender
00182 {
00183     
00184 }
00185 
00186 - (BOOL) shouldMove { return shouldMove; }
00187 
00188 - (IBAction) endButton: (id) sender
00189 {
00190     if (sender == okButton) {
00191         secondsBeforeLogout = [timeStepper intValue];
00192 #if USE_DAPREFERENCES
00193         DAPreferences *         defaults = sPreferences;
00194 #else
00195         ScreenSaverDefaults *   defaults = [ScreenSaverDefaults defaultsForModuleWithName: MODULE_NAME];
00196 #endif
00197         [defaults setInteger: secondsBeforeLogout forKey: @"secondsBeforeLogout"];
00198         
00199         int                     row = [movementMatrix selectedRow];
00200         shouldMove = (row == 0);
00201         [defaults setBool: shouldMove forKey: @"shouldMove"];
00202         
00203         [self setAddedImage: [imageWell image]];
00204         if (addedImage) {
00205             [defaults setBool: YES forKey: @"usesImage"];
00206             NSData *    imageData = [NSArchiver archivedDataWithRootObject: addedImage];
00207             [defaults setObject: imageData forKey: @"addedImage"];              
00208         }
00209         else {
00210             [defaults setBool: NO forKey: @"usesImage"];
00211             [defaults removeObjectForKey: @"addedImage"];
00212         }
00213         
00214         messageText = [[[messageField textStorage] string] copy];
00215         [defaults setObject: messageText forKey: @"messageText"];
00216 
00217         float       value = [sizeSlider floatValue];
00218         [view setClockRadius: value];
00219         [defaults setInteger: (int) value forKey: @"clockRadius"];
00220 
00221 #if USE_DAPREFERENCES
00222         [defaults flushToFile];
00223 #endif
00224     }
00225     
00226     [[NSApplication sharedApplication] endSheet: panel];
00227 }
00228 
00229 - (IBAction) sliderAction: (id) sender
00230 {
00231 }
00232 
00233 - (NSString *) messageText { return messageText; }
00234 
00235 - (NSString *) messageTextForSeconds: (int) seconds
00236 {
00237     NSMutableString *   retval = [NSMutableString stringWithString: messageText];
00238     
00239     NSString *          userID = (NSString *) CSCopyUserName(YES);
00240     [retval replaceOccurrencesOfString: @"%u" withString: userID
00241             options: NSLiteralSearch range: NSMakeRange(0, [retval length])];
00242     
00243     NSString *          userName = (NSString *) CSCopyUserName(NO);
00244     if (userName && [userName length]) {
00245         [retval replaceOccurrencesOfString: @"%n" withString: userName
00246             options: NSLiteralSearch range: NSMakeRange(0, [retval length])];
00247     }
00248     else {
00249         [retval replaceOccurrencesOfString: @"%n" withString: userID
00250             options: NSLiteralSearch range: NSMakeRange(0, [retval length])];
00251     }
00252     [userName release];
00253     [userID release];
00254     
00255     NSString *          secondsInt = [NSString stringWithFormat: @"%d", seconds];
00256     [retval replaceOccurrencesOfString: @"%s" withString: secondsInt
00257             options: NSLiteralSearch range: NSMakeRange(0, [retval length])];
00258 
00259     NSString *          secondsMss = [NSString stringWithFormat: @"%d:%02d", seconds/60, seconds%60];
00260     [retval replaceOccurrencesOfString: @"%t" withString: secondsMss
00261             options: NSLiteralSearch range: NSMakeRange(0, [retval length])];
00262     
00263     return retval;
00264 }
00265 
00266 - (void) setMessageText: (NSString *) newText
00267 {
00268     if (newText != messageText) {
00269         [messageText release];
00270         messageText = [newText retain];
00271 
00272         [[messageField textStorage]
00273                 replaceCharactersInRange: NSMakeRange(0, [[messageField textStorage] length])
00274                               withString: newText];
00275         [self colorMessageField];
00276     }
00277 }
00278 
00283 - (void) setTimeTextMinutes: (int) mins seconds: (int) secs
00284 {
00285     NSString *      str = [NSString stringWithFormat: @"%d:%02d", mins, secs];
00286     [timeField setStringValue: str];
00287 }
00288 
00289 - (void) setSecondsBeforeLogout: (int) seconds
00290 {
00291     if (seconds < 10)
00292         seconds = 10;
00293     
00294     [self setTimeTextMinutes: (seconds / 60) seconds: (seconds % 60)];
00295     [timeStepper setIntValue: seconds];
00296 }
00297 
00298 - (int) secondsBeforeLogout
00299 {
00300     return secondsBeforeLogout;
00301 }
00302 
00303 - (IBAction) stepper: (id) sender
00304 {
00305     int     value = [sender intValue];
00306     [self setSecondsBeforeLogout: value];
00307 }
00308 
00309 - (IBAction) timeText: (id) sender
00310 {
00311     NSString *      str = [sender stringValue];
00312     int             minutes = 0;
00313     int             seconds = 0;
00314     
00315     int             i, iLimit = [str length];
00316     int             state = 0;
00317     
00318     for (i = 0; i < iLimit && state < 9; i++) {
00319         unichar         ch = [str characterAtIndex: i];
00320         switch (state) {
00321             case 0:
00322                 if (ch >= '0' && ch <= '9') {
00323                     seconds *= 10;
00324                     seconds += (ch - '0');
00325                 }
00326                 else if (ch == ':' || ch == ' ' || ch == '.') {
00327                     minutes = 60 * seconds;
00328                     seconds = 0;
00329                     state = 1;
00330                 }
00331                 else {
00332                     state = 9;
00333                 }
00334                 break;
00335             case 1:
00336                 if (ch >= '0' && ch <= '9') {
00337                     seconds *= 10;
00338                     seconds += (ch - '0');
00339                 }
00340                 else {
00341                     state = 9;
00342                     return;
00343                 }
00344                 break;
00345         }
00346     }
00347     
00348     [self setSecondsBeforeLogout: seconds + minutes];
00349 }
00350 
00356 - (NSMutableArray *) closableUIApplications
00357 {
00358     NSArray *           exempt = [NSArray arrayWithObjects: @"Finder", nil];
00359     NSMutableArray *    retval = [DAApplication launchedApplications];
00360     int                 i;
00361     
00362     //  Remove exempt applications from the list of running UI apps
00363     for (i = [retval count] - 1; i >= 0; i--) {
00364         DAApplication *     curr = [retval objectAtIndex: i];
00365         if ([exempt containsObject: [curr name]]) {
00366             [retval removeObject: curr];
00367         }
00368     }
00369     
00370     return retval;
00371 }
00372 
00373 - (void) quitApplications
00374 {
00375     if (self != sMainController)
00376         return;
00377     
00378     NSMutableArray *    apps = [self closableUIApplications];
00379     [apps makeObjectsPerformSelector: @selector(quitWithoutSaving)];
00380 }
00381 
00382 - (void) killApplications
00383 {
00384     if (self != sMainController)
00385         return;
00386     
00387     NSMutableArray *    apps = [self closableUIApplications];
00388     [apps makeObjectsPerformSelector: @selector(killObj:) withObject: [NSNumber numberWithInt: 9]];
00389 }
00390 
00391 - (NSString *) nameOfThisApplication
00392 {
00393     return [[[NSWorkspace sharedWorkspace] activeApplication] objectForKey: @"NSApplicationName"];
00394 }
00395 
00396 - (void) logOut
00397 {
00398     if (self != sMainController)
00399         return;
00400     
00401     NSAppleScript *     script = [[NSAppleScript alloc] initWithSource:
00402         @"ignoring application responses\r"
00403         @"tell application \"loginwindow\" to Çevent aevtrlgoÈ\r"
00404         @"end ignoring"];
00405     //  logo is the event that asks permission to log out;
00406     //  rlgo doesn't ask.
00407     NSAppleEventDescriptor *    result;
00408     NSDictionary *              errorDict;
00409     
00410     result = [script executeAndReturnError: &errorDict];
00411     if (! result)
00412         NSLog(@"ErrorDict = %@", errorDict);    
00413 }
00414 
00415 - (void) makeTouchFile
00416 {
00417     NSString *          userID = (NSString *) CSCopyUserName(YES);
00418     NSString *          touchPath = [NSString stringWithFormat: @"/tmp/%@.DownAndOut", userID];
00419     NSMutableString *   content = [NSMutableString string];
00420     NSEnumerator *      iter = [[DAApplication quitApplicationNames] objectEnumerator];
00421     NSString *          curr;
00422     
00423     while (curr = [iter nextObject]) {
00424         if (![[DAApplication killedApplicationNames] containsObject: curr])
00425             [content appendFormat: @"Quit:\t%@\n", curr];
00426     }
00427     
00428     iter = [[DAApplication killedApplicationNames] objectEnumerator];
00429     while (curr = [iter nextObject])
00430         [content appendFormat: @"Killed:\t%@\n", curr];
00431     
00432     [content writeToFile: touchPath atomically: NO];
00433 }
00434 
00435 - (IBAction) restoreDefaults: (id) sender
00436 {
00437     [self setSecondsBeforeLogout: DEFAULT_LOGOUT];
00438     if (DEFAULT_SHOULD_MOVE)
00439         [movementMatrix selectCellAtRow: 0 column: 0];
00440     else
00441         [movementMatrix selectCellAtRow: 1 column: 0];
00442     [imageWell setImage: nil];
00443     [imageClear setEnabled: NO];
00444     
00445     [[messageField textStorage]
00446         replaceCharactersInRange: NSMakeRange(0, [[messageField textStorage] length])
00447                       withString: DEFAULT_MESSAGE];
00448     [self colorMessageField];
00449 }
00450 
00451 - (NSImage *) addedImage { return addedImage; }
00452 
00453 - (void) setAddedImage: (NSImage *) anImage
00454 {
00455     if (anImage != addedImage) {
00456         [addedImage release];
00457         addedImage = [anImage retain];
00458         
00459         [imageWell setImage: anImage];
00460         [imageClear setEnabled: (addedImage != nil)];
00461     }
00462 }
00463 
00464 - (IBAction) imageAction: (id) sender
00465 {
00466     if (sender == imageClear) {
00467         [imageWell setImage: nil];
00468     }
00469     else if (sender == imageSet) {
00470         NSOpenPanel *   openPanel = [NSOpenPanel openPanel];
00471         
00472         [openPanel setCanChooseDirectories: NO];
00473         [openPanel setAllowsMultipleSelection: NO];
00474         
00475         int             answer = [openPanel runModalForTypes: [NSImage imageFileTypes]];
00476         
00477         if (answer == NSOKButton) {
00478             NSImage *   newImage = [[NSImage alloc] initWithContentsOfFile: [openPanel filename]];
00479             if (newImage)
00480                 [imageWell setImage: newImage];
00481             [newImage release];
00482         }
00483     }
00484     else if (sender == imageWell) {
00485         //  [self setAddedImage: [imageWell image]];
00486     }
00487     
00488     [imageClear setEnabled: ([imageWell image] != nil)];
00489 }
00490 
00491 @end

Generated on Wed Jan 25 12:04:27 2006 for DownAndOut by  doxygen 1.4.4