Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AppController.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#import "SGHotKey.h"

@class SGHotKey;
@class FlycutClipping;

@interface AppController : NSResponder <NSMenuDelegate, NSApplicationDelegate, FlycutStoreDelegate, FlycutOperatorDelegate, BezelWindowDelegate> {
BezelWindow *bezel;
Expand Down Expand Up @@ -91,6 +92,7 @@
// Basic functionality
-(void) pollPB:(NSTimer *)timer;
-(void) addClipToPasteboard:(NSString*)pbFullText;
-(void) addImageClipToPasteboard:(FlycutClipping *)clipping;
-(void) setPBBlockCount:(NSNumber *)newPBBlockCount;
-(void) hideApp;
-(void) fakeCommandV;
Expand Down
329 changes: 263 additions & 66 deletions AppController.m

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions Flycut.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@
E5334CA52DBF0A1D00AAEAEE /* FlycutClipping.m in Sources */ = {isa = PBXBuildFile; fileRef = E5334CA02DBF0A1D00AAEAEE /* FlycutClipping.m */; };
E5334CA62DBF0A1D00AAEAEE /* FlycutStore.h in Headers */ = {isa = PBXBuildFile; fileRef = E5334CA12DBF0A1D00AAEAEE /* FlycutStore.h */; };
E5334CA72DBF0A1D00AAEAEE /* FlycutClipping.h in Headers */ = {isa = PBXBuildFile; fileRef = E5334C9F2DBF0A1D00AAEAEE /* FlycutClipping.h */; };
F1000001AAAA000100000001 /* FlycutImageStore.m in Sources */ = {isa = PBXBuildFile; fileRef = F1000001AAAA000100000003 /* FlycutImageStore.m */; };
F1000001AAAA000100000002 /* FlycutImageStore.h in Headers */ = {isa = PBXBuildFile; fileRef = F1000001AAAA000100000004 /* FlycutImageStore.h */; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
Expand Down Expand Up @@ -172,6 +174,8 @@
E5334CA02DBF0A1D00AAEAEE /* FlycutClipping.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FlycutClipping.m; sourceTree = "<group>"; };
E5334CA12DBF0A1D00AAEAEE /* FlycutStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FlycutStore.h; sourceTree = "<group>"; };
E5334CA22DBF0A1D00AAEAEE /* FlycutStore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FlycutStore.m; sourceTree = "<group>"; };
F1000001AAAA000100000003 /* FlycutImageStore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FlycutImageStore.m; sourceTree = "<group>"; };
F1000001AAAA000100000004 /* FlycutImageStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FlycutImageStore.h; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -376,6 +380,8 @@
E5334CA02DBF0A1D00AAEAEE /* FlycutClipping.m */,
E5334CA12DBF0A1D00AAEAEE /* FlycutStore.h */,
E5334CA22DBF0A1D00AAEAEE /* FlycutStore.m */,
F1000001AAAA000100000004 /* FlycutImageStore.h */,
F1000001AAAA000100000003 /* FlycutImageStore.m */,
);
path = FlycutEngine;
sourceTree = "<group>";
Expand All @@ -399,6 +405,7 @@
7761C8AC139BDF12000FB3AB /* SRKeyCodeTransformer.h in Headers */,
E5334CA62DBF0A1D00AAEAEE /* FlycutStore.h in Headers */,
E5334CA72DBF0A1D00AAEAEE /* FlycutClipping.h in Headers */,
F1000001AAAA000100000002 /* FlycutImageStore.h in Headers */,
7761C8AE139BDF12000FB3AB /* SRRecorderCell.h in Headers */,
7761C8B0139BDF12000FB3AB /* SRRecorderControl.h in Headers */,
7761C8B2139BDF12000FB3AB /* SRValidator.h in Headers */,
Expand Down Expand Up @@ -516,6 +523,7 @@
77A4F3B0139BD72300F39666 /* SGHotKeyCenter.m in Sources */,
E5334CA42DBF0A1D00AAEAEE /* FlycutStore.m in Sources */,
E5334CA52DBF0A1D00AAEAEE /* FlycutClipping.m in Sources */,
F1000001AAAA000100000001 /* FlycutImageStore.m in Sources */,
77A4F3B2139BD72300F39666 /* SGKeyCodeTranslator.m in Sources */,
77A4F3B4139BD72300F39666 /* SGKeyCombo.m in Sources */,
7761C891139BDEAF000FB3AB /* BezelWindow.m in Sources */,
Expand Down
17 changes: 8 additions & 9 deletions FlycutEngine/FlycutClipping.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,20 @@
#import <Foundation/Foundation.h>

@interface FlycutClipping : NSObject {
// What must a clipping hold?
// The text
NSString * clipContents;
// The text type
NSString * clipType;
// The display length
int clipDisplayLength;
// The display string
NSString * clipDisplayString;
// Does it have a name?
BOOL clipHasName;
// The app name it came from
NSString * appLocalizedName;
// The the bunle URL of the app it came from
NSString * appBundleURL;
// The time
NSInteger clipTimestamp;
NSString * imageHash;
NSSize imageSize;
}

-(id) initWithContents:(NSString *)contents withType:(NSString *)type withDisplayLength:(int)displayLength withAppLocalizedName:(NSString *)localizedName withAppBundleURL:(NSString *)bundleURL withTimestamp:(NSInteger)timestamp;
-(id) initWithImageHash:(NSString *)hash withImageSize:(NSSize)size withImageType:(NSString *)imageType withDisplayLength:(int)displayLength withAppLocalizedName:(NSString *)localizedName withAppBundleURL:(NSString *)bundleURL withTimestamp:(NSInteger)timestamp;
/* -(id) initWithCoder:(NSCoder *)coder;
-(void) decodeWithCoder:(NSCoder *)coder; */
-(NSString *) description;
Expand All @@ -53,6 +47,11 @@
-(NSString *) appBundleURL;
-(NSInteger) timestamp;
-(BOOL) hasName;
-(BOOL) isImageClipping;
-(NSString *) imageHash;
-(NSSize) imageSize;
-(void) setImageHash:(NSString *)hash;
-(void) setImageSize:(NSSize)size;

// Additional functions
-(void) resetDisplayString;
Expand Down
81 changes: 74 additions & 7 deletions FlycutEngine/FlycutClipping.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@


#import "FlycutClipping.h"
#import <AppKit/AppKit.h>

@implementation FlycutClipping

Expand All @@ -31,14 +32,35 @@ -(id) initWithContents:(NSString *)contents withType:(NSString *)type withDispla
clipContents = [[[NSString alloc] init] retain];
clipDisplayString = [[[NSString alloc] init] retain];
clipType = [[[NSString alloc] init] retain];
imageHash = nil;
imageSize = NSZeroSize;

[self setContents:contents setDisplayLength:displayLength];
[self setType:type];
[self setAppLocalizedName:localizedName];
[self setAppBundleURL:bundleURL];
[self setTimestamp:timestamp];
[self setHasName:false];


return self;
}

-(id) initWithImageHash:(NSString *)hash withImageSize:(NSSize)size withImageType:(NSString *)imageType withDisplayLength:(int)displayLength withAppLocalizedName:(NSString *)localizedName withAppBundleURL:(NSString*)bundleURL withTimestamp:(NSInteger)timestamp
{
[super init];
clipContents = [@"" retain];
clipDisplayString = [[[NSString alloc] init] retain];
clipType = [(imageType != nil ? imageType : NSPasteboardTypeTIFF) retain];
clipDisplayLength = displayLength > 0 ? displayLength : 40;

[self setImageHash:hash];
imageSize = size;
[self setAppLocalizedName:localizedName];
[self setAppBundleURL:bundleURL];
[self setTimestamp:timestamp];
[self setHasName:false];
[self resetDisplayString];

return self;
}

Expand Down Expand Up @@ -136,19 +158,32 @@ -(void) setHasName:(BOOL)newHasName

-(void) resetDisplayString
{
[clipDisplayString release];

if (imageHash != nil) {
NSString *label = [clipType isEqualToString:@"com.compuserve.gif"] ? @"GIF" : @"Image";
NSString *newDisplayString;
if (imageSize.width > 0 && imageSize.height > 0) {
newDisplayString = [NSString stringWithFormat:@"[%@ %dx%d]",
label, (int)imageSize.width, (int)imageSize.height];
} else {
newDisplayString = [NSString stringWithFormat:@"[%@]", label];
}
[newDisplayString retain];
clipDisplayString = newDisplayString;
return;
}

NSString *newDisplayString, *firstLineOfClipping, *trimmedString;
NSUInteger start, lineEnd, contentsEnd;
NSRange startRange = NSMakeRange(0,0);
NSRange contentsRange;
// We're resetting the display string, so release the old one.
[clipDisplayString release];
// We want to restrict the display string to the clipping contents through the first line break.
trimmedString = [clipContents stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[trimmedString getLineStart:&start end:&lineEnd contentsEnd:&contentsEnd forRange:startRange];
contentsRange = NSMakeRange(0, contentsEnd);
firstLineOfClipping = [trimmedString substringWithRange:contentsRange];
if ( [firstLineOfClipping length] > clipDisplayLength ) {
newDisplayString = [[NSString stringWithString:[firstLineOfClipping substringToIndex:clipDisplayLength]] stringByAppendingString:@"…"];
newDisplayString = [[NSString stringWithString:[firstLineOfClipping substringToIndex:clipDisplayLength]] stringByAppendingString:@"…"];
} else {
newDisplayString = [NSString stringWithString:firstLineOfClipping];
}
Expand Down Expand Up @@ -216,14 +251,45 @@ -(BOOL) hasName
return clipHasName;
}

-(BOOL) isImageClipping
{
return imageHash != nil;
}

-(NSString *) imageHash
{
return imageHash;
}

-(NSSize) imageSize
{
return imageSize;
}

-(void) setImageHash:(NSString *)hash
{
id old = imageHash;
[hash retain];
imageHash = hash;
[old release];
}

-(void) setImageSize:(NSSize)size
{
imageSize = size;
}

- (BOOL)isEqual:(id)other {
if (other == self)
return YES;
if (!other || ![other isKindOfClass:[self class]])
return NO;
FlycutClipping * otherClip = (FlycutClipping *)other;
return (/*[self.type isEqualToString:otherClip.type] &&*/ // Type is under-utilized a this time and will mismatch on cross-device (macOS <-> iOS) usage. This should be revisited once we have support for more than just raw text clippings.
[self.contents isEqualToString:otherClip.contents]);
if ([self isImageClipping] && [otherClip isImageClipping])
return [self.imageHash isEqualToString:otherClip.imageHash];
if ([self isImageClipping] != [otherClip isImageClipping])
return NO;
return [self.contents isEqualToString:otherClip.contents];
}


Expand All @@ -234,6 +300,7 @@ -(void) dealloc
[clipType release];
[appLocalizedName release];
[appBundleURL release];
[imageHash release];
clipDisplayLength = 0;
[clipDisplayString release];
clipHasName = 0;
Expand Down
31 changes: 31 additions & 0 deletions FlycutEngine/FlycutImageStore.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// FlycutImageStore.h
// Flycut
//
// File-based image storage for clipboard image clippings.
//

#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>

@interface FlycutImageStore : NSObject {
NSString *imagesDirectoryPath;
}

+(FlycutImageStore *)sharedStore;

// Maps a pasteboard UTI (e.g. com.compuserve.gif) to the on-disk file extension.
+(NSString *)fileExtensionForType:(NSString *)uti;

-(NSString *)hashForData:(NSData *)data;
-(BOOL)saveImageData:(NSData *)data forHash:(NSString *)hash;
-(BOOL)saveImageData:(NSData *)data forHash:(NSString *)hash extension:(NSString *)ext;
-(NSData *)imageDataForHash:(NSString *)hash;
// Absolute path to the stored image file for a hash (whatever extension), or nil.
-(NSString *)imageFilePathForHash:(NSString *)hash;
-(void)deleteImageForHash:(NSString *)hash;
-(BOOL)hasImageForHash:(NSString *)hash;
-(NSString *)imagesDirectoryPath;
-(NSArray *)allStoredHashes;

@end
Loading