Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

When using Move to.../Copy to... set the 3rd pane object to the parent directory of the file to be moved/copied #665

Merged
merged 6 commits into from

3 participants

@pjrobertson
Owner

Does exactly what it says on the tin.

Short of a better place to start, I think the 'current' folder is typically quite near where you want to move things to. I found myself doing this a lot lately, so thought I'd implement it.

It's certainly better than a completely random folder

@skurfer

Could we just replace these three lines with

NSMutableArray *fileObjects = [[[QSLibrarian sharedInstance] arrayForType:QSFilePathType] mutableCopy];

and then use that for the rest of the method?

yes, that would make more sense :)

@skurfer

I know you didn’t add this, but what’s with checking that there’s no extension? You think maybe it’s trying to filter out bundles?

Seems flimsy to me. What if a plain directory has an extension? The only way I can see to check properly is using NSBundle’s bundleWithPath: (since it returns nil for things that aren’t bundles), but that could be an expensive operation. Maybe it could be done up-front in fileObjectWithPath: and then you could simply test for it here?

I’m aware that I might be over-thinking this. :-)

Probably worth being more robust, maybe this is the way to go:

If you need to further determine if path is a package, use the isFilePackageAtPath: method of NSWorkspace.

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSWorkspace_Class/Reference/Reference.html#//apple_ref/occ/instm/NSWorkspace/isFilePackageAtPath:

@skurfer
Owner

By the way, I love this change. I always saw the weirdest folders pop up in the third pane.

@skurfer
Owner

If I try to move something out of ~/Downloads, the parent folder in the third pane has a semi-transparent generic folder icon. I think this is because you’re creating the object from scratch every time. Something like this seems to fix it (and probably runs faster for things already in the catalog).

NSString *currentFolderPath = [[[[dObject splitObjects] lastObject] singleFilePath] stringByDeletingLastPathComponent];
QSObject *currentFolderObject = [QSObject objectWithIdentifier:currentFolderPath];
if (!currentFolderObject) {
    // if it wasn't in the catalog, create it from scratch
    currentFolderObject = [QSObject fileObjectWithPath:currentFolderPath];
}

Also, did you notice if you set a breakpoint in this method, it gets run twice? Completely unrelated to this pull request, but it sounds like a good opportunity for a speed-up somewhere.

@pjrobertson
Owner

:) I like how you're improving on this!

I'll make the changes when I get home. (OK, I'm now home and making the changes. Completely forgot about this - work was too fun! :P)

Also, did you notice if you set a breakpoint in this method, it gets run twice? Completely unrelated to this pull request, but it sounds like a good opportunity for a speed-up somewhere.

I've seen that in hundreds and hundred of places with Quicksilver. If we can stop it, then Quicksilver will definitely be much, much faster!

@pjrobertson pjrobertson Tidy up the Copy/Move To... iObjects
This commit:

* Obtains the list of objects more cleanly (using mutableCopy)
* Ensures a new file object for the folder isn't created if it already exists
* Performs a more robust check for bundles (using NSWorkspace's `isFilePackageAtPath`)
* Creates one instance of NSFileManager as opposed to thousands (for each run of the for loop)

Thanks to @skurfer for tips
33eeca2
@pjrobertson
Owner

Take a look and see what you think :)

P.S. - you may have just omitted it in your line note, but a mutableCopy retains the object so we need to release it when we're done :)

@skurfer
Owner

I've seen that in hundreds and hundred of places with Quicksilver. If we can stop it, then Quicksilver will definitely be much, much faster!

Yeah, but usually something runs 3 times (once per pane, I assume) or some multiple of 3. Probably pretty tricky to find and fix those. But this is twice, which makes me think it’s probably just a silly mistake somewhere.

As for how the folder object gets created, I looked at fileObjectWithPath: and it’s already doing a check for existing objects so in theory, my fix should be redundant, but in practice, it seemed to fix the issue with the icon.

@pjrobertson
Owner

my fix should be redundant, but in practice, it seemed to fix the issue with the icon.

Yeah looking at fileObjectWithPath: it looks completely redundant. I'll look into it.
I haven't noticed the 'running twice' problem you're talking about, but I'll look into it

@pjrobertson
Owner

FWIW: I still saw the 'semi' transparent problem with your fix, but it was pretty random. Removing your (redundant) check makes no difference for me.

And... the 'running twice' business is: The method is run however many times you type a letter.

e.g. if you type 'm' for 'Move To...' the method is run once.
If you type 'moveto' the method is run 6 times! Good catch, now to fix... :o

pjrobertson added some commits
@pjrobertson pjrobertson Don't check if the object's already been created.
This is already done in `fileObjectWithPath
d2bc207
@pjrobertson pjrobertson Only send a "SearchObjectChanged" notif is the object really changed de9dc40
@pjrobertson pjrobertson Correctly define the getter/setter methods for searchArray
searchArray is an NSMutableArray, yet these methods refer to NSArrays.
Code has been checked for all occurrences of `setSearchArray` and they all set an NSMutableArray
4099157
@skurfer
Owner

If you type 'moveto' the method is run 6 times! Good catch, now to fix

Ah, this could be a result of having the “Wait before searching” preferences set to 0.0. I’ll bet if I up that, the method will only have to run once.

@pjrobertson
Owner

OK you have many, many commits to look at now! I thought this was going to be an easy one...

So the fix for the 'running twice' part was to check the actual objects as opposed to the ranked objects (which obviously aren't the same as you alter your search)

The commits also:

  • Reverts the check to see if the file object exists, as fileObjectWithPath: does this
  • Properly defined some setter/getters that were giving a warning. From what I can see, they're always NSMutableArrays
  • Moved the 'disabling catalog' part to run for debug builds only. This will mean we'd have to remove the section on 'Catalog' here. I think we'd gain more from users not reporting problems than we would from users not being able to debug a crash. Who's going to go through altering their .plists from 'YES' to 'NO' anyway?!
@pjrobertson
Owner

OK you have many, many commits to look at now! I thought this was going to be an easy one...

So the fix for the 'running twice' part was to check the actual objects as opposed to the ranked objects (which obviously aren't the same as you alter your search)

The commits also:

  • Reverts the check to see if the file object exists, as fileObjectWithPath: does this
  • Properly defined some setter/getters that were giving a warning. From what I can see, they're always NSMutableArrays
  • Moved the 'disabling catalog' part to run for debug builds only. This will mean we'd have to remove the section on 'Catalog' here. I think we'd gain more from users not reporting problems than we would from users not being able to debug a crash. Who's going to go through altering their .plists from 'YES' to 'NO' anyway?!
@skurfer
Owner

Increasing the time before searching did fix the double call, but your fix is still necessary because as I type, the action isn’t changing and so there should be no need to re-validate. Good catch.

Properly defined some setter/getters that were giving a warning.

Maybe this is pre-mature optimization, but it doesn’t need to be mutable, right? There doesn’t seem to be an immutableCopy method though. :-)

@lovequicksilver

Great! I got 'Scripts archive iPhoto' in pane 3. On relaunch it became 'Public', and now it's 'Example materials and photos'…

@pjrobertson
Owner

Maybe this is pre-mature optimization, but it doesn’t need to be mutable, right? There doesn’t seem to be an immutableCopy method though. :-)

I guess not, but is it worth us changing it? I think it may be a bit premature considering the optimisation gains would be minimal, but the consequences if anything every does try to alter the array would be catastrophic.

@skurfer
Owner

I guess not, but is it worth us changing it?

Nah, leave it.

@pjrobertson
Owner

Is there anything more that needs to be done on this?

I know the changes here grew to a bit more than just the move to.../copy to... action, so I guess it might take a bit more time to test.

@skurfer
Owner

Is there anything more that needs to be done on this?

No, I’ll probably merge this and a couple of your others this afternoon.

@pjrobertson
Owner
@skurfer skurfer merged commit 780f465 into quicksilver:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 26, 2012
  1. @pjrobertson

    When using Move to.../Copy to... set the 3rd pane object to the paren…

    pjrobertson authored
    …t directory of the file to be moved/copied
Commits on Jan 27, 2012
  1. @pjrobertson

    Tidy up the Copy/Move To... iObjects

    pjrobertson authored
    This commit:
    
    * Obtains the list of objects more cleanly (using mutableCopy)
    * Ensures a new file object for the folder isn't created if it already exists
    * Performs a more robust check for bundles (using NSWorkspace's `isFilePackageAtPath`)
    * Creates one instance of NSFileManager as opposed to thousands (for each run of the for loop)
    
    Thanks to @skurfer for tips
  2. @pjrobertson

    Don't check if the object's already been created.

    pjrobertson authored
    This is already done in `fileObjectWithPath
  3. @pjrobertson
  4. @pjrobertson

    Correctly define the getter/setter methods for searchArray

    pjrobertson authored
    searchArray is an NSMutableArray, yet these methods refer to NSArrays.
    Code has been checked for all occurrences of `setSearchArray` and they all set an NSMutableArray
  5. @pjrobertson
This page is out of date. Refresh to see the latest.
View
4 Quicksilver/Code-QuickStepCore/QSLibrarian.m
@@ -80,12 +80,16 @@ - (id)init {
[NSMutableArray array] , kItemChildren,
[NSNumber numberWithBool:YES] , kItemEnabled, nil];
+#ifdef DEBUG
if ((int) getenv("QSDisableCatalog") || GetCurrentKeyModifiers() & shiftKey) {
NSLog(@"Disabling Catalog");
} else {
+#endif
[self setCatalog:[QSCatalogEntry entryWithDictionary:
[NSMutableDictionary dictionaryWithObjectsAndKeys:@"QSCATALOGROOT", kItemName, @"QSGroupObjectSource", kItemSource, [NSMutableArray arrayWithObjects:modulesEntry, nil] , kItemChildren, [NSNumber numberWithBool:YES] , kItemEnabled, nil]]];
+#ifdef DEBUG
}
+#endif
// Register for Notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(writeCatalog:) name:QSCatalogEntryChanged object:nil];
View
4 Quicksilver/Code-QuickStepInterface/QSSearchObjectView.h
@@ -83,8 +83,8 @@ typedef enum QSSearchMode {
- (NSMutableArray *)sourceArray;
- (void)setSourceArray:(NSMutableArray *)newSourceArray;
-- (NSArray *)searchArray;
-- (void)setSearchArray:(NSArray *)newSearchArray;
+- (NSMutableArray *)searchArray;
+- (void)setSearchArray:(NSMutableArray *)newSearchArray;
- (NSMutableArray *)resultArray;
- (void)setResultArray:(NSMutableArray *)newResultArray;
View
15 Quicksilver/Code-QuickStepInterface/QSSearchObjectView.m
@@ -293,8 +293,8 @@ - (void)setResultArray:(NSMutableArray *)newResultArray {
[(id)[self controller] searchView:self changedResults:newResultArray];
}
-- (NSArray *)searchArray { return searchArray; }
-- (void)setSearchArray:(NSArray *)newSearchArray {
+- (NSMutableArray *)searchArray { return searchArray; }
+- (void)setSearchArray:(NSMutableArray *)newSearchArray {
if (searchArray != newSearchArray) {
[searchArray release];
searchArray = [newSearchArray retain];
@@ -580,7 +580,16 @@ - (IBAction)updateResultView:(id)sender {
#pragma mark -
#pragma mark Object Value
- (void)selectObjectValue:(QSObject *)newObject {
- if (newObject != [self objectValue]) {
+ QSObject *currentObject = [self objectValue];
+ QSObject *tempNewObject;
+ QSObject *tempCurrentObject;
+ if ([newObject isKindOfClass:[QSRankedObject class]]) {
+ tempNewObject = [(QSRankedObject *)newObject object];
+ }
+ if ([currentObject isKindOfClass:[QSRankedObject class]]) {
+ tempCurrentObject = [(QSRankedObject *)currentObject object];
+ }
+ if ((tempNewObject ? tempNewObject : newObject) != (tempCurrentObject ? tempCurrentObject : currentObject)) {
[self updateHistory];
[super setObjectValue:newObject];
[[NSNotificationCenter defaultCenter] postNotificationName:@"SearchObjectChanged" object:self];
View
16 Quicksilver/PlugIns-Main/QSCorePlugIn/Code/QSActionProvider_EmbeddedProviders.m
@@ -343,15 +343,25 @@ - (NSArray *)validIndirectObjectsForAction:(NSString *)action directObject:(QSOb
return [NSArray arrayWithObject:[QSObject textProxyObjectWithDefaultValue:@"untitled folder"]];
} else if ([action isEqualToString:kFileMoveToAction] || [action isEqualToString:kFileCopyToAction]) {
// We only want folders for the move to / copy to actions (can't move to anything else)
- NSArray *fileObjects = [[QSLibrarian sharedInstance] arrayForType:QSFilePathType];
+ NSMutableArray *fileObjects = [[[QSLibrarian sharedInstance] arrayForType:QSFilePathType] mutableCopy];
BOOL isDirectory;
+ NSString *currentFolderPath = [[[[dObject splitObjects] lastObject] singleFilePath] stringByDeletingLastPathComponent];
+ // if it wasn't in the catalog, create it from scratch
+ QSObject *currentFolderObject = [QSObject fileObjectWithPath:currentFolderPath];
+ [fileObjects removeObject:currentFolderObject];
+ [fileObjects insertObject:currentFolderObject atIndex:0];
+ NSWorkspace *ws = [[NSWorkspace sharedWorkspace] retain];
+ NSFileManager *fm = [[NSFileManager alloc] init];
for(QSObject *thisObject in fileObjects) {
NSString *path = [thisObject singleFilePath];
- if ([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory]) {
- if (isDirectory && ![[path pathExtension] length])
+ if ([fm fileExistsAtPath:path isDirectory:&isDirectory]) {
+ if (isDirectory && ![ws isFilePackageAtPath:path])
[validIndirects addObject:thisObject];
}
}
+ [fileObjects release];
+ [ws release];
+ [fm release];
return validIndirects;
}
return nil;
Something went wrong with that request. Please try again.