From ac45921cb4998f9138e77391d8e6a44f92a15f47 Mon Sep 17 00:00:00 2001 From: Mitchell Livingston Date: Thu, 9 Jan 2014 16:23:54 +0000 Subject: [PATCH] #5576 Share Button (to iMessage, email, etc) for torrent file --- Transmission.xcodeproj/project.pbxproj | 6 ++ macosx/Controller.h | 4 +- macosx/Controller.m | 89 ++++++++++++++++++++++---- macosx/ShareToolbarItem.h | 15 +++++ macosx/ShareToolbarItem.m | 65 +++++++++++++++++++ 5 files changed, 164 insertions(+), 15 deletions(-) create mode 100644 macosx/ShareToolbarItem.h create mode 100644 macosx/ShareToolbarItem.m diff --git a/Transmission.xcodeproj/project.pbxproj b/Transmission.xcodeproj/project.pbxproj index 144707475..54180adc7 100644 --- a/Transmission.xcodeproj/project.pbxproj +++ b/Transmission.xcodeproj/project.pbxproj @@ -126,6 +126,7 @@ A221DCC8104B3660008A642D /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A221DCC7104B3660008A642D /* Quartz.framework */; }; A222E9870E6B21D9009FB003 /* BlocklistDownloaderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A222E9860E6B21D9009FB003 /* BlocklistDownloaderViewController.m */; }; A222EA7B0E6C32C4009FB003 /* BlocklistScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = A222EA7A0E6C32C4009FB003 /* BlocklistScheduler.m */; }; + A225A4C0187E369C00CDE823 /* ShareToolbarItem.m in Sources */ = {isa = PBXBuildFile; fileRef = A225A4BF187E369C00CDE823 /* ShareToolbarItem.m */; }; A2265F420B5EF5F40093DDA5 /* FileNameCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A2265F400B5EF5F40093DDA5 /* FileNameCell.m */; }; A226FDAC0D0CDF20005A7F71 /* libnatpmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C7A118D0D0B2EB800B5701F /* libnatpmp.a */; }; A2290D1E14421CC100B95A09 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = A27653A714369C5C009D3CCF /* libcrypto.dylib */; }; @@ -744,6 +745,8 @@ A223AA800D220CEB00840069 /* nl */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = nl; path = macosx/nl.lproj/Localizable.strings; sourceTree = ""; }; A223AA810D220CEB00840069 /* nl */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = nl; path = macosx/nl.lproj/MainMenu.xib; sourceTree = ""; }; A223AA830D220CEB00840069 /* nl */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = nl; path = macosx/nl.lproj/PrefsWindow.xib; sourceTree = ""; }; + A225A4BE187E369C00CDE823 /* ShareToolbarItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ShareToolbarItem.h; path = macosx/ShareToolbarItem.h; sourceTree = ""; }; + A225A4BF187E369C00CDE823 /* ShareToolbarItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ShareToolbarItem.m; path = macosx/ShareToolbarItem.m; sourceTree = ""; }; A2265F3F0B5EF5F40093DDA5 /* FileNameCell.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = FileNameCell.h; path = macosx/FileNameCell.h; sourceTree = ""; }; A2265F400B5EF5F40093DDA5 /* FileNameCell.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = FileNameCell.m; path = macosx/FileNameCell.m; sourceTree = ""; }; A2290D2D1442B23200B95A09 /* libcurl.4.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcurl.4.dylib; path = "third-party/curl/lib/libcurl.4.dylib"; sourceTree = ""; }; @@ -1393,6 +1396,8 @@ A2ED7D8E0CEF431B00970975 /* FilterButton.m */, A2C89D5F0CFCBF57004CC2BC /* ButtonToolbarItem.m */, A28E1DDF0CFFD8EC00E16385 /* ButtonToolbarItem.h */, + A225A4BE187E369C00CDE823 /* ShareToolbarItem.h */, + A225A4BF187E369C00CDE823 /* ShareToolbarItem.m */, A21979890D07B78400438EA7 /* GroupToolbarItem.h */, A219798A0D07B78400438EA7 /* GroupToolbarItem.m */, A20BFFB50D091CC700CE5D2B /* ToolbarSegmentedCell.h */, @@ -2719,6 +2724,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + A225A4C0187E369C00CDE823 /* ShareToolbarItem.m in Sources */, A2D77453154CC72B00A62B93 /* WebSeedTableView.m in Sources */, 8D11072D0486CEB800E47090 /* main.m in Sources */, 4DF0C5AB0899190500DD8943 /* Controller.m in Sources */, diff --git a/macosx/Controller.h b/macosx/Controller.h index e6b6807c3..e1d768215 100644 --- a/macosx/Controller.h +++ b/macosx/Controller.h @@ -50,7 +50,7 @@ typedef enum ADD_CREATED } addType; -@interface Controller : NSObject +@interface Controller : NSObject { tr_session * fLib; @@ -180,6 +180,8 @@ typedef enum - (void) verifySelectedTorrents: (id) sender; - (void) verifyTorrents: (NSArray *) torrents; +- (NSArray *)selectedTorrents; + @property (retain, readonly) PrefsController * prefsController; - (void) showPreferenceWindow: (id) sender; diff --git a/macosx/Controller.m b/macosx/Controller.m index 0b2bd2cda..1251d0305 100644 --- a/macosx/Controller.m +++ b/macosx/Controller.m @@ -44,6 +44,7 @@ #import "GlobalOptionsPopoverViewController.h" #import "ButtonToolbarItem.h" #import "GroupToolbarItem.h" +#import "ShareToolbarItem.h" #import "ToolbarSegmentedCell.h" #import "BlocklistDownloader.h" #import "StatusBarController.h" @@ -78,6 +79,7 @@ #define TOOLBAR_PAUSE_RESUME_SELECTED @"Toolbar Pause / Resume Selected" #define TOOLBAR_FILTER @"Toolbar Toggle Filter" #define TOOLBAR_QUICKLOOK @"Toolbar QuickLook" +#define TOOLBAR_SHARE @"Toolbar Share" typedef enum { @@ -1783,6 +1785,11 @@ static void sleepCallback(void * controller, io_service_t y, natural_t messageTy [self applyFilter]; } +- (NSArray *)selectedTorrents +{ + return [fTableView selectedTorrents]; +} + - (void) showPreferenceWindow: (id) sender { NSWindow * window = [fPrefsController window]; @@ -3804,9 +3811,34 @@ static void sleepCallback(void * controller, io_service_t y, natural_t messageTy } } +- (void) showToolbarShare: (id) sender +{ + NSParameterAssert([sender isKindOfClass:[NSButton class]]); + + NSSharingServicePicker * picker = [[NSSharingServicePicker alloc] initWithItems: [ShareToolbarItem shareTorrentURLs]]; + picker.delegate = self; + + [picker showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge]; +} + +- (id)sharingServicePicker:(NSSharingServicePicker *)sharingServicePicker delegateForSharingService:(NSSharingService *)sharingService +{ + return self; +} + +- (NSWindow *)sharingService:(NSSharingService *)sharingService sourceWindowForShareItems:(NSArray *)items sharingContentScope:(NSSharingContentScope *)sharingContentScope +{ + return fWindow; +} + - (ButtonToolbarItem *) standardToolbarButtonWithIdentifier: (NSString *) ident { - ButtonToolbarItem * item = [[ButtonToolbarItem alloc] initWithItemIdentifier: ident]; + return [self toolbarButtonWithIdentifier: ident forToolbarButtonClass: [ButtonToolbarItem class]]; +} + +- (id) toolbarButtonWithIdentifier: (NSString *) ident forToolbarButtonClass:(Class)class +{ + ButtonToolbarItem * item = [[class alloc] initWithItemIdentifier: ident]; NSButton * button = [[NSButton alloc] init]; [button setBezelStyle: NSTexturedRoundedBezelStyle]; @@ -4007,6 +4039,23 @@ static void sleepCallback(void * controller, io_service_t y, natural_t messageTy return item; } + else if ([ident isEqualToString: TOOLBAR_SHARE]) + { + ShareToolbarItem * item = [self toolbarButtonWithIdentifier: ident forToolbarButtonClass: [ShareToolbarItem class]]; + + [item setLabel: NSLocalizedString(@"Share", "Share toolbar item -> label")]; + [item setPaletteLabel: NSLocalizedString(@"Share", "Share toolbar item -> palette label")]; + [item setToolTip: NSLocalizedString(@"Share torrent file", "Share toolbar item -> tooltip")]; + [item setImage: [NSImage imageNamed: NSImageNameShareTemplate]]; + [item setVisibilityPriority: NSToolbarItemVisibilityPriorityLow]; + + NSButton *itemButton = (NSButton *)[item view]; + [itemButton setTarget: self]; + [itemButton setAction: @selector(showToolbarShare:)]; + [itemButton sendActionOn:NSLeftMouseDownMask]; + + return item; + } else return nil; } @@ -4043,22 +4092,30 @@ static void sleepCallback(void * controller, io_service_t y, natural_t messageTy - (NSArray *) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar { - return [NSArray arrayWithObjects: - TOOLBAR_CREATE, TOOLBAR_OPEN_FILE, TOOLBAR_OPEN_WEB, TOOLBAR_REMOVE, - TOOLBAR_PAUSE_RESUME_SELECTED, TOOLBAR_PAUSE_RESUME_ALL, - TOOLBAR_QUICKLOOK, TOOLBAR_FILTER, TOOLBAR_INFO, - NSToolbarSeparatorItemIdentifier, - NSToolbarSpaceItemIdentifier, - NSToolbarFlexibleSpaceItemIdentifier, - NSToolbarCustomizeToolbarItemIdentifier, nil]; + NSMutableArray *items = [NSMutableArray arrayWithObjects: + TOOLBAR_CREATE, TOOLBAR_OPEN_FILE, TOOLBAR_OPEN_WEB, TOOLBAR_REMOVE, + TOOLBAR_PAUSE_RESUME_SELECTED, TOOLBAR_PAUSE_RESUME_ALL, + TOOLBAR_SHARE, TOOLBAR_QUICKLOOK, TOOLBAR_FILTER, TOOLBAR_INFO, + NSToolbarSeparatorItemIdentifier, + NSToolbarSpaceItemIdentifier, + NSToolbarFlexibleSpaceItemIdentifier, + NSToolbarCustomizeToolbarItemIdentifier, nil]; + if (![NSApp isOnMountainLionOrBetter]) { + [items removeObject:TOOLBAR_SHARE]; + } + return items; } - (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar { - return [NSArray arrayWithObjects: - TOOLBAR_CREATE, TOOLBAR_OPEN_FILE, TOOLBAR_REMOVE, NSToolbarSpaceItemIdentifier, - TOOLBAR_PAUSE_RESUME_ALL, NSToolbarFlexibleSpaceItemIdentifier, - TOOLBAR_QUICKLOOK, TOOLBAR_FILTER, TOOLBAR_INFO, nil]; + NSMutableArray *items = [NSMutableArray arrayWithObjects: + TOOLBAR_CREATE, TOOLBAR_OPEN_FILE, TOOLBAR_REMOVE, NSToolbarSpaceItemIdentifier, + TOOLBAR_PAUSE_RESUME_ALL, NSToolbarFlexibleSpaceItemIdentifier, + TOOLBAR_SHARE, TOOLBAR_QUICKLOOK, TOOLBAR_FILTER, TOOLBAR_INFO, nil]; + if (![NSApp isOnMountainLionOrBetter]) { + [items removeObject:TOOLBAR_SHARE]; + } + return items; } - (BOOL) validateToolbarItem: (NSToolbarItem *) toolbarItem @@ -4125,7 +4182,11 @@ static void sleepCallback(void * controller, io_service_t y, natural_t messageTy [(NSButton *)[toolbarItem view] setState: [QLPreviewPanel sharedPreviewPanelExists] && [[QLPreviewPanel sharedPreviewPanel] isVisible]]; return YES; } - + + //enable share item + if ([ident isEqualToString: TOOLBAR_SHARE]) + return [fTableView numberOfSelectedRows] > 0; + return YES; } diff --git a/macosx/ShareToolbarItem.h b/macosx/ShareToolbarItem.h new file mode 100644 index 000000000..7b1c76920 --- /dev/null +++ b/macosx/ShareToolbarItem.h @@ -0,0 +1,15 @@ +// +// ShareButtonToolbarItem.h +// Transmission +// +// Created by Mitchell Livingston on 1/8/14. +// Copyright (c) 2014 The Transmission Project. All rights reserved. +// + +#import "ButtonToolbarItem.h" + +@interface ShareToolbarItem : ButtonToolbarItem + ++ (NSArray *)shareTorrentURLs; + +@end diff --git a/macosx/ShareToolbarItem.m b/macosx/ShareToolbarItem.m new file mode 100644 index 000000000..2811c8cea --- /dev/null +++ b/macosx/ShareToolbarItem.m @@ -0,0 +1,65 @@ +// +// ShareToolbarItem.m +// Transmission +// +// Created by Mitchell Livingston on 1/8/14. +// Copyright (c) 2014 The Transmission Project. All rights reserved. +// + +#import "ShareToolbarItem.h" +#import "Controller.h" +#import "NSApplicationAdditions.h" +#import "Torrent.h" + +@implementation ShareToolbarItem + +// move somewhere else? ++ (NSArray *)shareTorrentURLs +{ + NSArray * torrents = [(Controller *)[NSApp delegate] selectedTorrents]; + NSMutableArray * fileURLs = [NSMutableArray arrayWithCapacity: [torrents count]]; + for (Torrent * torrent in torrents) + { + NSString * location = [torrent torrentLocation]; + if ([location length] > 0) { + [fileURLs addObject: [NSURL fileURLWithPath:location]]; + } + } + return fileURLs; +} + +- (NSMenuItem *) menuFormRepresentation +{ + NSMenuItem * menuItem = [[NSMenuItem alloc] initWithTitle: [self label] action: nil keyEquivalent: @""]; + [menuItem setEnabled: [[self target] validateToolbarItem: self]]; + + NSArray * fileURLs = [[self class] shareTorrentURLs]; + if ([menuItem isEnabled] && [fileURLs count] > 0) { + NSMenu *servicesMenu = [[NSMenu alloc] initWithTitle: @""]; + for (NSSharingService * service in [NSSharingService sharingServicesForItems: fileURLs]) + { + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle: service.title // 10.9: change to menuItemTitle + action: @selector(performShareAction:) + keyEquivalent: @""]; + item.image = service.image; + item.representedObject = service; + service.delegate = (Controller *)[NSApp delegate]; + item.target = self; + [servicesMenu addItem:item]; + [item release]; + } + + [menuItem setSubmenu:servicesMenu]; + [servicesMenu release]; // can't believe we're not using ARC yet! + } + + return menuItem; +} + +- (void)performShareAction:(NSMenuItem *)item +{ + NSSharingService * service = item.representedObject; + [service performWithItems: [[self class] shareTorrentURLs]]; // on 10.9, use attachmentFileURLs? +} + +@end