Camino only - Bug 407544: Clean up event handling in the download manager. r/sr=mento

git-svn-id: svn://10.0.0.236/trunk@242872 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
stuart.morgan%alumni.case.edu
2008-01-10 23:53:22 +00:00
parent 9c6afd0d83
commit cda6262149
6 changed files with 97 additions and 174 deletions

View File

@@ -69,8 +69,7 @@
#import "CHDownloadProgressDisplay.h"
#import "FileChangeWatcher.h"
@class ProgressViewController;
#import "ProgressViewController.h"; // For DownloadSelectionBehavior enum
//
// interface ProgressDlgController
@@ -107,6 +106,9 @@
-(IBAction)pause:(id)sender;
-(IBAction)resume:(id)sender;
-(void)updateSelectionOfDownload:(ProgressViewController*)selectedDownload
withBehavior:(DownloadSelectionBehavior)behavior;
-(int)numDownloadsInProgress;
-(void)clearAllDownloads;
-(void)didStartDownload:(ProgressViewController*)progressDisplay;

View File

@@ -59,7 +59,7 @@ static NSString* const kProgressWindowFrameSaveName = @"ProgressWindow";
-(void)rebuildViews;
-(NSArray*)selectedProgressViewControllers;
-(ProgressViewController*)progressViewControllerAtIndex:(unsigned)inIndex;
-(void)deselectDLInstancesInArray:(NSArray*)instances;
-(void)deselectDownloads:(NSArray*)downloads;
-(void)scrollIntoView:(ProgressViewController*)controller;
-(void)killDownloadTimer;
-(void)setupDownloadTimer;
@@ -122,16 +122,6 @@ static id gSharedProgressController = nil;
[mStackView setDataSource:self];
mSelectionPivotIndex = -1;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(DLInstanceSelected:)
name:kDownloadInstanceSelectedNotificationName
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(DLInstanceOpened:)
name:kDownloadInstanceOpenedNotificationName
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cancel:)
name:kDownloadInstanceCancelledNotificationName
object:nil];
}
return self;
}
@@ -152,7 +142,6 @@ static id gSharedProgressController = nil;
-(void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
if (self == gSharedProgressController) {
gSharedProgressController = nil;
}
@@ -177,7 +166,10 @@ static id gSharedProgressController = nil;
// open all selected instances
-(IBAction)open:(id)sender
{
[[self selectedProgressViewControllers] makeObjectsPerformSelector:@selector(open:) withObject:sender];
if ([self shouldAllowOpenAction])
[[self selectedProgressViewControllers] makeObjectsPerformSelector:@selector(open:) withObject:sender];
else
NSBeep();
}
//
@@ -299,83 +291,49 @@ static id gSharedProgressController = nil;
[self saveProgressViewControllers];
}
//
// -DLInstanceOpened:
//
// Called when one of the ProgressView's should be opened (dbl clicked, for example). Open all of the
// selected instances with the Finder.
//
-(void)DLInstanceOpened:(NSNotification*)notification
-(void)updateSelectionOfDownload:(ProgressViewController*)selectedDownload
withBehavior:(DownloadSelectionBehavior)behavior
{
if ([self fileExistsForSelectedItems])
[self open:self];
}
int indexOfSelectedDownload = (int)[mProgressViewControllers indexOfObject:selectedDownload];
// calculate what buttons should be enabled/disabled because the user changed the selection state
-(void)DLInstanceSelected:(NSNotification*)notification
{
// make sure the notification object is the kind we want
ProgressView* selectedView = ((ProgressView*)[notification object]);
if (![selectedView isKindOfClass:[ProgressView class]])
return;
NSArray* currentlySelectedDownloads = [self selectedProgressViewControllers];
ProgressViewController* selectedViewController = [selectedView controller];
NSArray* selectedArray = [self selectedProgressViewControllers];
int indexOfSelectedController = (int)[mProgressViewControllers indexOfObject:selectedViewController];
// check for key modifiers and select more instances if appropriate
// if its shift key, extend the selection one way or another
// if its command key, just let the selection happen wherever it is (don't mess with it here)
// if its not either clear all selections except the one that just happened
switch ([selectedView lastModifier])
{
case kNoKey:
// deselect everything
[self deselectDLInstancesInArray:selectedArray];
[selectedViewController setSelected:YES];
mSelectionPivotIndex = indexOfSelectedController;
switch (behavior) {
case DownloadSelectExclusively:
[self deselectDownloads:currentlySelectedDownloads];
[selectedDownload setSelected:YES];
mSelectionPivotIndex = indexOfSelectedDownload;
break;
case kCommandKey:
if (![selectedViewController isSelected])
{
// if this was at the pivot index set the pivot index to -1
if (indexOfSelectedController == mSelectionPivotIndex)
mSelectionPivotIndex = -1;
case DownloadSelectByExtending:
if (mSelectionPivotIndex == -1 || [currentlySelectedDownloads count] == 0) {
mSelectionPivotIndex = indexOfSelectedDownload;
}
else
{
if ([selectedArray count] == 1)
mSelectionPivotIndex = indexOfSelectedController;
}
break;
case kShiftKey:
if (mSelectionPivotIndex == -1)
mSelectionPivotIndex = indexOfSelectedController;
else
{
if ([selectedArray count] == 1)
mSelectionPivotIndex = indexOfSelectedController;
else
{
// deselect everything
[self deselectDLInstancesInArray:selectedArray];
if (indexOfSelectedController <= mSelectionPivotIndex)
{
for (int i = indexOfSelectedController; i <= mSelectionPivotIndex; i++)
[(ProgressViewController*)[mProgressViewControllers objectAtIndex:i] setSelected:YES];
}
else if (indexOfSelectedController > mSelectionPivotIndex)
{
for (int i = mSelectionPivotIndex; i <= indexOfSelectedController; i++)
[(ProgressViewController*)[mProgressViewControllers objectAtIndex:i] setSelected:YES];
}
else {
[self deselectDownloads:currentlySelectedDownloads];
if (indexOfSelectedDownload <= mSelectionPivotIndex) {
for (int i = indexOfSelectedDownload; i <= mSelectionPivotIndex; i++)
[(ProgressViewController*)[mProgressViewControllers objectAtIndex:i] setSelected:YES];
}
else if (indexOfSelectedDownload > mSelectionPivotIndex) {
for (int i = mSelectionPivotIndex; i <= indexOfSelectedDownload; i++)
[(ProgressViewController*)[mProgressViewControllers objectAtIndex:i] setSelected:YES];
}
}
break;
case DownloadSelectByInverting:
if ([selectedDownload isSelected]) {
// if this was at the pivot index set the pivot index to -1
if (indexOfSelectedDownload == mSelectionPivotIndex)
mSelectionPivotIndex = -1;
}
else {
if ([currentlySelectedDownloads count] == 0)
mSelectionPivotIndex = indexOfSelectedDownload;
}
[selectedDownload setSelected:(![selectedDownload isSelected])];
break;
}
}
@@ -407,7 +365,7 @@ static id gSharedProgressController = nil;
}
// deselect everything if the shift key isn't a modifier
if (!shiftKeyDown)
[self deselectDLInstancesInArray:[self selectedProgressViewControllers]];
[self deselectDownloads:[self selectedProgressViewControllers]];
if (i == (int)[mProgressViewControllers count]) // if nothing was selected select the first item
instanceToSelect = 0;
@@ -439,7 +397,7 @@ static id gSharedProgressController = nil;
// deselect everything if the shift key isn't a modifier
if (!shiftKeyDown)
[self deselectDLInstancesInArray:[self selectedProgressViewControllers]];
[self deselectDownloads:[self selectedProgressViewControllers]];
if (i < 0) // if nothing was selected select the first item
instanceToSelect = ([mProgressViewControllers count] - 1);
@@ -489,24 +447,22 @@ static id gSharedProgressController = nil;
}
}
-(void)deselectDLInstancesInArray:(NSArray*)instances
-(void)deselectDownloads:(NSArray*)downloads
{
unsigned count = [instances count];
unsigned count = [downloads count];
for (unsigned i = 0; i < count; i++) {
[(ProgressViewController*)[instances objectAtIndex:i] setSelected:NO];
[(ProgressViewController*)[downloads objectAtIndex:i] setSelected:NO];
}
}
// return a mutable array with instance in order top-down
// Returns the currently-selected download view controllers.
-(NSArray*)selectedProgressViewControllers
{
NSMutableArray *selectedArray = [[NSMutableArray alloc] init];
unsigned selectedCount = [mProgressViewControllers count];
for (unsigned i = 0; i < selectedCount; i++) {
if ([[mProgressViewControllers objectAtIndex:i] isSelected]) {
// insert at zero so they're in order to-down
if ([[mProgressViewControllers objectAtIndex:i] isSelected])
[selectedArray addObject:[mProgressViewControllers objectAtIndex:i]];
}
}
[selectedArray autorelease];
return selectedArray;
@@ -557,7 +513,7 @@ static id gSharedProgressController = nil;
[self setupDownloadTimer];
// downloads should be individually selected when initiated
[self deselectDLInstancesInArray:[self selectedProgressViewControllers]];
[self deselectDownloads:[self selectedProgressViewControllers]];
[(ProgressViewController*)progressDisplay setSelected:YES];
// make sure new download is visible

View File

@@ -41,10 +41,6 @@
@class ProgressViewController;
extern NSString* const kDownloadInstanceSelectedNotificationName;
extern NSString* const kDownloadInstanceOpenedNotificationName;
extern NSString* const kDownloadInstanceCancelledNotificationName;
//
// interface ProgressView
//
@@ -59,13 +55,8 @@ extern NSString* const kDownloadInstanceCancelledNotificationName;
IBOutlet NSImageView* mFileIconView;
ProgressViewController* mProgressController; // WEAK reference
NSEvent* mFileIconMouseDownEvent; // STRONG reference
int mLastModifier;
}
// returns the most recent modifier key used during the last
// click on this view
-(int)lastModifier;
// get/set our owning controller, to which we maintain a weak link
-(void)setController:(ProgressViewController*)controller;
-(ProgressViewController*)controller;

View File

@@ -41,29 +41,8 @@
#import "ProgressViewController.h"
NSString* const kDownloadInstanceSelectedNotificationName = @"DownloadInstanceSelected";
NSString* const kDownloadInstanceOpenedNotificationName = @"DownloadInstanceOpened";
NSString* const kDownloadInstanceCancelledNotificationName = @"DownloadInstanceCancelled";
@interface ProgressView(Private)
-(BOOL)isSelected;
-(void)setSelected:(BOOL)inSelected;
@end
@implementation ProgressView
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
mLastModifier = kNoKey;
mProgressController = nil;
}
return self;
}
- (void)dealloc
{
[mFileIconMouseDownEvent release];
@@ -72,7 +51,7 @@ NSString* const kDownloadInstanceCancelledNotificationName = @"DownloadInstanceC
-(void)drawRect:(NSRect)rect
{
if ([self isSelected]) {
if ([mProgressController isSelected]) {
[[NSColor selectedTextBackgroundColor] set];
}
else {
@@ -84,33 +63,25 @@ NSString* const kDownloadInstanceCancelledNotificationName = @"DownloadInstanceC
-(void)mouseDown:(NSEvent*)theEvent
{
unsigned int mods = [theEvent modifierFlags];
mLastModifier = kNoKey;
BOOL shouldSelect = YES;
// set mLastModifier to any relevant modifier key
if (!((mods & NSShiftKeyMask) && (mods & NSCommandKeyMask))) {
if (mods & NSShiftKeyMask) {
mLastModifier = kShiftKey;
}
else if (mods & NSCommandKeyMask) {
if ([self isSelected])
shouldSelect = NO;
mLastModifier = kCommandKey;
}
}
[self setSelected:shouldSelect];
[[NSNotificationCenter defaultCenter] postNotificationName:kDownloadInstanceSelectedNotificationName
object:self];
DownloadSelectionBehavior selectionBehavior;
// Favor command behavior over shift, like most table views do
if (mods & NSCommandKeyMask)
selectionBehavior = DownloadSelectByInverting;
else if (mods & NSShiftKeyMask)
selectionBehavior = DownloadSelectByExtending;
else
selectionBehavior = DownloadSelectExclusively;
[mProgressController updateSelectionWithBehavior:selectionBehavior];
[mFileIconMouseDownEvent release];
mFileIconMouseDownEvent = nil;
if ([theEvent type] == NSLeftMouseDown) {
// See if it's a double-click; if so, send a notification off to the
// controller which will handle it accordingly. Doing it after processing
// the modifiers allows someone to shift-dblClick and open all selected
// items in the list in one action.
// the selection change allows someone to shift-double-click and open all
// selected items in the list in one action.
if ([theEvent clickCount] == 2) {
[[NSNotificationCenter defaultCenter] postNotificationName:kDownloadInstanceOpenedNotificationName
object:self];
[mProgressController openSelectedDownloads];
}
// If not, and the download isn't active, see if it's a click on the icon.
else if (![mProgressController isActive]) {
@@ -183,32 +154,8 @@ NSString* const kDownloadInstanceCancelledNotificationName = @"DownloadInstanceC
[mProgressController remove:self];
}
-(int)lastModifier
{
return mLastModifier;
}
- (BOOL)isSelected
{
// make sure the controller is not nil before checking if it is selected
if (!mProgressController)
return NO;
return [mProgressController isSelected];
}
-(void)setSelected:(BOOL)inSelected
{
// make sure the controller is not nil before setting its selected state
if (!mProgressController)
return;
[mProgressController setSelected:inSelected];
}
-(void)setController:(ProgressViewController*)controller
{
// Don't retain since this view will only exist if its controller does
mProgressController = controller;
}
@@ -220,11 +167,9 @@ NSString* const kDownloadInstanceCancelledNotificationName = @"DownloadInstanceC
-(NSMenu*)menuForEvent:(NSEvent*)theEvent
{
// if the item is unselected, select it and deselect everything else before displaying the contextual menu
if (![self isSelected]) {
mLastModifier = kNoKey; // control is only special because it means its contextual menu time
[self setSelected:YES];
[self display]; // change selection immediately
[[NSNotificationCenter defaultCenter] postNotificationName:kDownloadInstanceSelectedNotificationName object:self];
if (![mProgressController isSelected]) {
[mProgressController updateSelectionWithBehavior:DownloadSelectExclusively];
[self display]; // change visual selection immediately
}
return [[self controller] contextualMenu];
}
@@ -236,7 +181,7 @@ NSString* const kDownloadInstanceCancelledNotificationName = @"DownloadInstanceC
([theEvent modifierFlags] & NSCommandKeyMask) != 0) &&
[[theEvent characters] isEqualToString:@"."])
{
[[NSNotificationCenter defaultCenter] postNotificationName:kDownloadInstanceCancelledNotificationName object:self];
[mProgressController cancelSelectedDownloads];
return YES;
}

View File

@@ -56,6 +56,11 @@ enum {
kShiftKey = 1,
kCommandKey = 2
};
typedef enum {
DownloadSelectExclusively,
DownloadSelectByInverting,
DownloadSelectByExtending
} DownloadSelectionBehavior;
// Define these auto remove download pref values here
// becase both ProgressViewController and ProgressDlgController
@@ -129,10 +134,17 @@ const int kRemoveUponSuccessfulDownloadPrefValue = 2;
-(BOOL)hasSucceeded;
// Directly sets the selection of this item (should not be called by the view).
-(void)setSelected:(BOOL)inSelected;
-(NSDictionary*)downloadInfoDictionary;
-(NSMenu*)contextualMenu;
// Handlers for actions that are triggered by user action on a view but aren't
// specific to the view.
-(void)updateSelectionWithBehavior:(DownloadSelectionBehavior)behavior;
-(void)openSelectedDownloads;
-(void)cancelSelectedDownloads;
@end

View File

@@ -694,6 +694,23 @@ enum {
#pragma mark -
-(void)updateSelectionWithBehavior:(DownloadSelectionBehavior)behavior
{
[mProgressWindowController updateSelectionOfDownload:self withBehavior:behavior];
}
-(void)openSelectedDownloads
{
[mProgressWindowController open:self];
}
-(void)cancelSelectedDownloads
{
[mProgressWindowController cancel:self];
}
#pragma mark -
-(void)onStartDownload:(BOOL)isFileSave
{
mIsFileSave = isFileSave;