/* Copyright (C) 2002-2003, Jeffrey D. Argast. The authors make NO WARRANTY or representation, either express or implied, with respect to this software, its quality, accuracy, merchantability, or fitness for a particular purpose. This software is provided "AS IS", and you, its user, assume the entire risk as to its quality and accuracy. Permission is hereby granted to use, copy, modify, and distribute this software or portions thereof for any purpose, without fee, subject to these conditions: (1) If any part of the source code is distributed, then this statement must be included, with this copyright and no-warranty notice unaltered. (2) Permission for use of this software is granted only if the user accepts full responsibility for any undesirable consequences; the authors accept NO LIABILITY for damages of any kind. */ #import "PerforceDirectory.h" #import "PerforceActionDirsAndFstat.h" #import "PerforceActionDirs.h" #import "PerforceActionFstat.h" #import "PerforceActionSync.h" #import "PerforceActionEdit.h" #import "PerforceActionRevert.h" #import "PerforceActionDelete.h" #import "IconController.h" #import "IconDefs.h" #import "AppUtils.h" #import "MessageDefs.h" static NSString* kNibExt = @"nib"; static NSString* kPBExt = @"pbproj"; @implementation PerforceDirectory + (PerforceDirectory *) directoryWithPath: (NSString *) fullPath { return [[[PerforceDirectory alloc] initWithPath: fullPath] autorelease]; } - (id) initWithPath: (NSString *) fullPath { if ( self = [super init] ) { fDepotPath = [fullPath retain]; fName = ExtractLastPathComponent (fDepotPath); [fName retain]; fDirChildren = nil; fFileChildren = nil; fShouldBuildChildren = YES; fExpandAfterBuilding = NO; fBuildingDirs = NO; fExpandPaths = [[NSMutableArray alloc] init]; fTotalNumChildren = 0; fNumFiles = 0; fNumDirs = 0; IconController* iconController = [IconController defaultIconController]; NSString* dirExtension = [fName pathExtension]; if ( dirExtension ) { if ( [dirExtension isEqualToString:kNibExt] ) { fIcon = [[iconController getIcon:kDirNibIcon] retain]; } else if ( [dirExtension isEqualToString:kPBExt] ) { fIcon = [[iconController getIcon:kDirPBIcon] retain]; } else { fIcon = [[iconController getIcon:kDirIcon] retain]; } } else { fIcon = [[iconController getIcon:kDirIcon] retain]; } } return self; } - (void) dealloc { [fDirChildren release]; [fFileChildren release]; [fName release]; [fDepotPath release]; [fExpandPaths release]; [fIcon release]; [super dealloc]; } - (void) releaseChildren { fShouldBuildChildren = YES; int n; for ( n = 0; n < fNumDirs; n++ ) { PerforceDirectory* childDir = [fDirChildren objectAtIndex:n]; [childDir releaseChildren]; } } - (void) resultFromDirs: (PerforceActionDirs*) action { NSArray* newDirs = [action getDirs]; // first off, if we have no dirs, then just copy if ( !fDirChildren ) { fDirChildren = [[NSMutableArray alloc] initWithArray:newDirs]; } else { // avoid changing the dir pointer so that the outline view still thinks it // is valid thereby updating it without collapsing it. // we assume that perforce dirs will always return the dirs in the same order // we'll march down the list of dirs and any new ones will be added before // the existing one. At the end of the incoming list if there are some // in the existing list not yet found, then we remove them -- should we? // isn't that a never should happen error case? int numExisting = [fDirChildren count]; int numNew = [newDirs count]; int existingIndex = numExisting - 1; int newIndex = numNew - 1; // This is a valid case: Hiding deleted files on, delete all files in a directory, // submit. numNew is less than numExisting in that case // NSAssert (numNew >= numExisting, @"Perforce dirs returned fewer directories than last time"); // we go backwards because we are inserting elements into fDirChildren and we don't // want to skip the inserts while ( (existingIndex >= 0) && (newIndex >= 0) ) { PerforceDirectory* existingDir = [fDirChildren objectAtIndex:existingIndex]; PerforceDirectory* newDir = [newDirs objectAtIndex:newIndex]; if ( [existingDir->fDepotPath isEqualTo:newDir->fDepotPath] ) { existingIndex--; newIndex--; } else { // according to the documentation of NSMutableArray insertObject:atIndex: // an index equal to the number of elements in the array is valid // and appends the item to the list [fDirChildren insertObject:newDir atIndex:(existingIndex + 1)]; newIndex--; } } int insertIndex = existingIndex + 1; while ( newIndex >= 0 ) { PerforceDirectory* newDir = [newDirs objectAtIndex:newIndex]; [fDirChildren insertObject:newDir atIndex:insertIndex]; newIndex--; } if ( insertIndex > 0 ) { int removeStart = 0; int removeLen = insertIndex; [fDirChildren removeObjectsInRange:NSMakeRange (removeStart, removeLen)]; } } fNumDirs = [fDirChildren count]; fTotalNumChildren = fNumFiles + fNumDirs; fBuildingDirs = NO; if ( fExpandAfterBuilding ) { int numPaths = [fExpandPaths count]; int n; for ( n = 0; n < numPaths; n++ ) { [self expandPath:[fExpandPaths objectAtIndex:n]]; } [fExpandPaths removeAllObjects]; } fExpandAfterBuilding = NO; SendNotificationWithObject (kDepotControllerChildChanged, self); } - (void) resultFromFstat: (PerforceActionFstat*) action { [fFileChildren release]; fFileChildren = [[action getFiles] retain]; fNumFiles = [fFileChildren count]; fTotalNumChildren = fNumFiles + fNumDirs; SendNotificationWithObject (kDepotControllerChildChanged, self); } - (void) buildChildren { NSMutableString* dirPath = [NSMutableString stringWithString:fDepotPath]; [dirPath appendString:@"/*"]; [PerforceAction abortAllOwnersActions:self]; [PerforceActionDirs defaultRunFor:self selector:@selector(resultFromDirs:) withPath:dirPath]; [PerforceActionFstat defaultRunFor:self selector:@selector(resultFromFstat:) withPath:dirPath]; fBuildingDirs = YES; fShouldBuildChildren = NO; } - (NSString*) getName { return fName; } - (int) getNumberOfChildren { if ( fShouldBuildChildren ) { [self buildChildren]; } return fTotalNumChildren; } - (BOOL) hasChildren { // Depots/Directories always have children return YES; } - (id) getChildAtIndex: (int) index { if ( fShouldBuildChildren ) { [self buildChildren]; } if ( index < fNumDirs ) { return [fDirChildren objectAtIndex:index]; } if ( index < fTotalNumChildren ) { return [fFileChildren objectAtIndex:(index - fNumDirs)]; } return nil; } - (id) getCellText { return fName; } - (id) getCellImage { return fIcon; } - (NSString*) buildPath: (NSString*) extraPath { return [NSString stringWithFormat: @"%@%@", fDepotPath, extraPath]; } // // Perforce Protocol // // // data // // // Enablement // - (BOOL) canSyncToHead { return YES; } - (BOOL) canSyncToNone { return YES; } - (BOOL) canEdit { return YES; } - (BOOL) canDelete { return YES; } - (BOOL) canRevert { return YES; } - (BOOL) canDiff { return NO; } - (BOOL) canGetRevisions { return NO; } - (BOOL) canViewInEditor { return NO; } // // Actions // - (void) showRevisionHistory { } - (void) diff { // do nothing } - (void) viewInEditor { // do nothing; } - (NSString*) getPasteboardData { NSMutableString* dragPath = [NSMutableString stringWithString:fDepotPath]; [dragPath appendString:@"/..."]; return dragPath; } - (void) pathChanged:(NSString*)depotPath theFile:(PerforceFile**)theFile { int myLen = [fDepotPath length]; int otherLen = [depotPath length]; if ( myLen < otherLen ) { NSComparisonResult compareResult = [depotPath compare:fDepotPath options:0 range:NSMakeRange (0, myLen)]; if ( compareResult == NSOrderedSame ) { // are the next 4 chars /... ? if ( (otherLen - myLen) == 4 ) { compareResult = [depotPath compare:@"/..." options:0 range:NSMakeRange (myLen, 4)]; if ( compareResult == NSOrderedSame ) { [self releaseChildren]; return; } } if ( fFileChildren ) { int numChildren = [fFileChildren count]; int n; for ( n = 0; (n < numChildren) && (*theFile == nil); n++ ) { id<DepotViewProtocol> child = [fFileChildren objectAtIndex:n]; [child pathChanged:depotPath theFile:theFile]; } } if ( fDirChildren ) { int numChildren = [fDirChildren count]; int n; for ( n = 0; (n < numChildren) && (*theFile == nil); n++ ) { id<DepotViewProtocol> child = [fDirChildren objectAtIndex:n]; [child pathChanged:depotPath theFile:theFile]; } } } } } - (NSString*) getDepotPath { return fDepotPath; } - (NSString*) getPerforceActionPath { return [self buildPath:@"/..."]; } - (void) expandPath:(NSString*)depotPath { int myLen = [fDepotPath length]; int otherLen = [depotPath length]; if ( myLen <= otherLen ) { NSComparisonResult compareResult = [depotPath compare:fDepotPath options:0 range:NSMakeRange (0, myLen)]; if ( compareResult == NSOrderedSame ) { if ( fShouldBuildChildren ) { fExpandAfterBuilding = YES; [fExpandPaths addObject:depotPath]; [self buildChildren]; } else if ( fBuildingDirs ) { fExpandAfterBuilding = YES; [fExpandPaths addObject:depotPath]; } else { // Send notification before calling expand on children so // that the messages are received in the correct order // by the depot controller SendNotificationWithObject (kDepotControllerExpandChild, self); if ( fDirChildren ) { int numChildren = [fDirChildren count]; int n; for ( n = 0; n < numChildren; n++ ) { id<DepotViewProtocol> child = [fDirChildren objectAtIndex:n]; [child expandPath:depotPath]; } } } } } } @end
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 3391 | Paul Ferguson | More memory leak fixes, other code cleanup | ||
#1 | 3210 | Paul Ferguson | Initial branch | ||
//guest/jeff_argast/P4Cocoa/source/Perforce/PerforceDirectory.m | |||||
#5 | 3147 | Jeff Argast | Testing std in blockage | ||
#4 | 3134 | Jeff Argast |
Added copy/paste support in the depot view Added expand path to depot view Added bookmarks |
||
#3 | 3113 | Jeff Argast |
Reduced the times the depot view completely collapses. Now it won't collapse on refresh views or submit, but still collapses when the defaults change. |
||
#2 | 3111 | Jeff Argast |
Made multiple selection smarter by operating on the entire selection as an atomic operation with the server. Also partially fixed the read only window to not wrap at the window boundary. I did the same for the editable window, but now the problem appears to be that p4 change -o is breaking its output at some character location before the string gets into the editor (at least I think that is the problem). |
||
#1 | 2732 | Jeff Argast | Initial submission of P4Cocoa |