file_utilities_mac.mm 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "platform/mac/file_utilities_mac.h"
  8. #include "base/platform/mac/base_utilities_mac.h"
  9. #include "lang/lang_keys.h"
  10. #include "styles/style_window.h"
  11. #include <Cocoa/Cocoa.h>
  12. #include <CoreFoundation/CFURL.h>
  13. namespace {
  14. using namespace Platform;
  15. QString strNeedToReload() {
  16. const uint32 letters[] = { 0xAD92C02B, 0xA2217C97, 0x5E55F4F5, 0x2207DAAC, 0xD18BA536, 0x03E41869, 0xB96D2BFD, 0x810C7284, 0xE412099E, 0x5AAD0837, 0xE6637AEE, 0x8E5E2FF5, 0xE3BDA123, 0x94A5CE38, 0x4A42F7D1, 0xCE4677DC, 0x40A81701, 0x9C5B38CD, 0x61801E1A, 0x6FF16179 };
  17. return MakeFromLetters(letters);
  18. }
  19. QString strNeedToRefresh1() {
  20. const uint32 letters[] = { 0xEDDFCD66, 0x434DF1FB, 0x820B76AB, 0x48CE7965, 0x3609C0BA, 0xFC9A990C, 0x3EDD1C51, 0xE2BDA036, 0x7140CEE9, 0x65DB414D, 0x88592EC3, 0x2CB2613A };
  21. return MakeFromLetters(letters);
  22. }
  23. QString strNeedToRefresh2() {
  24. const uint32 letters[] = { 0x8AE4915D, 0x7159D7EF, 0x79C74167, 0x29B7611C, 0x0E6B9ADD, 0x0D93610F, 0xEBEAFE7A, 0x5BD17540, 0x121EF3B7, 0x61B02E26, 0x2174AAEE, 0x61AD3325 };
  25. return MakeFromLetters(letters);
  26. }
  27. } // namespace
  28. @interface OpenWithApp : NSObject {
  29. NSString *fullname;
  30. NSURL *app;
  31. NSImage *icon;
  32. }
  33. @property (nonatomic, retain) NSString *fullname;
  34. @property (nonatomic, retain) NSURL *app;
  35. @property (nonatomic, retain) NSImage *icon;
  36. @end // @interface OpenWithApp
  37. @implementation OpenWithApp
  38. @synthesize fullname, app, icon;
  39. - (void) dealloc {
  40. [fullname release];
  41. [app release];
  42. [icon release];
  43. [super dealloc];
  44. }
  45. @end // @implementation OpenWithApp
  46. @interface OpenFileWithInterface : NSObject {
  47. }
  48. - (id) init:(NSString *)file;
  49. - (BOOL) popupAt:(NSPoint)point;
  50. - (void) itemChosen:(id)sender;
  51. - (void) dealloc;
  52. @end // @interface OpenFileWithInterface
  53. @implementation OpenFileWithInterface {
  54. NSString *toOpen;
  55. NSURL *defUrl;
  56. NSString *defBundle, *defName, *defVersion;
  57. NSImage *defIcon;
  58. NSMutableArray *apps;
  59. NSMenu *menu;
  60. }
  61. - (void) fillAppByUrl:(NSURL*)url bundle:(NSString**)bundle name:(NSString**)name version:(NSString**)version icon:(NSImage**)icon {
  62. NSBundle *b = [NSBundle bundleWithURL:url];
  63. if (b) {
  64. NSString *path = [url path];
  65. *name = [[NSFileManager defaultManager] displayNameAtPath: path];
  66. if (!*name) *name = (NSString*)[b objectForInfoDictionaryKey:@"CFBundleDisplayName"];
  67. if (!*name) *name = (NSString*)[b objectForInfoDictionaryKey:@"CFBundleName"];
  68. if (*name) {
  69. *bundle = [b bundleIdentifier];
  70. if (bundle) {
  71. *version = (NSString*)[b objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
  72. *icon = [[NSWorkspace sharedWorkspace] iconForFile: path];
  73. if (*icon && [*icon isValid]) [*icon setSize: CGSizeMake(16., 16.)];
  74. return;
  75. }
  76. }
  77. }
  78. *bundle = *name = *version = nil;
  79. *icon = nil;
  80. }
  81. - (id) init:(NSString*)file {
  82. toOpen = [file retain];
  83. if (self = [super init]) {
  84. NSURL *url = [NSURL fileURLWithPath:file];
  85. defUrl = [[NSWorkspace sharedWorkspace] URLForApplicationToOpenURL:url];
  86. if (defUrl) {
  87. [self fillAppByUrl:defUrl bundle:&defBundle name:&defName version:&defVersion icon:&defIcon];
  88. if (!defBundle || !defName) {
  89. defUrl = nil;
  90. }
  91. }
  92. NSArray *appsList = (NSArray*)LSCopyApplicationURLsForURL(CFURLRef(url), kLSRolesAll);
  93. NSMutableDictionary *data = [NSMutableDictionary dictionaryWithCapacity:16];
  94. int fullcount = 0;
  95. for (id app in appsList) {
  96. if (fullcount > 15) break;
  97. NSString *bundle = nil, *name = nil, *version = nil;
  98. NSImage *icon = nil;
  99. [self fillAppByUrl:(NSURL*)app bundle:&bundle name:&name version:&version icon:&icon];
  100. if (bundle && name) {
  101. if ([bundle isEqualToString:defBundle] && [version isEqualToString:defVersion]) continue;
  102. NSString *key = [[NSArray arrayWithObjects:bundle, name, nil] componentsJoinedByString:@"|"];
  103. if (!version) version = @"";
  104. NSMutableDictionary *versions = (NSMutableDictionary*)[data objectForKey:key];
  105. if (!versions) {
  106. versions = [NSMutableDictionary dictionaryWithCapacity:2];
  107. [data setValue:versions forKey:key];
  108. }
  109. if (![versions objectForKey:version]) {
  110. [versions setValue:[NSArray arrayWithObjects:name, icon, app, nil] forKey:version];
  111. ++fullcount;
  112. }
  113. }
  114. }
  115. if (fullcount || defUrl) {
  116. apps = [NSMutableArray arrayWithCapacity:fullcount];
  117. for (id key in data) {
  118. NSMutableDictionary *val = (NSMutableDictionary*)[data objectForKey:key];
  119. for (id ver in val) {
  120. NSArray *app = (NSArray*)[val objectForKey:ver];
  121. OpenWithApp *a = [[OpenWithApp alloc] init];
  122. NSString *fullname = (NSString*)[app objectAtIndex:0], *version = (NSString*)ver;
  123. BOOL showVersion = ([val count] > 1);
  124. if (!showVersion) {
  125. NSError *error = NULL;
  126. NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^\\d+\\.\\d+\\.\\d+(\\.\\d+)?$" options:NSRegularExpressionCaseInsensitive error:&error];
  127. showVersion = ![regex numberOfMatchesInString:version options:NSMatchingWithoutAnchoringBounds range:{0,[version length]}];
  128. }
  129. if (showVersion) fullname = [[NSArray arrayWithObjects:fullname, @" (", version, @")", nil] componentsJoinedByString:@""];
  130. [a setFullname:fullname];
  131. [a setIcon:(NSImage*)[app objectAtIndex:1]];
  132. [a setApp:(NSURL*)[app objectAtIndex:2]];
  133. [apps addObject:a];
  134. [a release];
  135. }
  136. }
  137. }
  138. [apps sortUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"fullname" ascending:YES]]];
  139. [appsList release];
  140. menu = nil;
  141. }
  142. return self;
  143. }
  144. - (BOOL) popupAt:(NSPoint)point {
  145. if (![apps count] && !defName) return NO;
  146. menu = [[NSMenu alloc] initWithTitle:@"Open With"];
  147. int index = 0;
  148. if (defName) {
  149. NSMenuItem *item = [menu insertItemWithTitle:[[NSArray arrayWithObjects:defName, @" (default)", nil] componentsJoinedByString:@""] action:@selector(itemChosen:) keyEquivalent:@"" atIndex:index++];
  150. if (defIcon) [item setImage:defIcon];
  151. [item setTarget:self];
  152. [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
  153. }
  154. if ([apps count]) {
  155. for (id a in apps) {
  156. OpenWithApp *app = (OpenWithApp*)a;
  157. NSMenuItem *item = [menu insertItemWithTitle:[a fullname] action:@selector(itemChosen:) keyEquivalent:@"" atIndex:index++];
  158. if ([app icon]) [item setImage:[app icon]];
  159. [item setTarget:self];
  160. }
  161. [menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
  162. }
  163. NSMenuItem *item = [menu insertItemWithTitle:Q2NSString(tr::lng_mac_choose_program_menu(tr::now)) action:@selector(itemChosen:) keyEquivalent:@"" atIndex:index++];
  164. [item setTarget:self];
  165. [menu popUpMenuPositioningItem:nil atLocation:point inView:nil];
  166. return YES;
  167. }
  168. - (void) itemChosen:(id)sender {
  169. NSArray *items = [menu itemArray];
  170. NSURL *url = nil;
  171. for (int i = 0, l = [items count]; i < l; ++i) {
  172. if ([items objectAtIndex:i] == sender) {
  173. if (defName) i -= 2;
  174. if (i < 0) {
  175. url = defUrl;
  176. } else if (i < int([apps count])) {
  177. url = [(OpenWithApp*)[apps objectAtIndex:i] app];
  178. }
  179. break;
  180. }
  181. }
  182. if (url) {
  183. [[NSWorkspace sharedWorkspace] openFile:toOpen withApplication:[url path]];
  184. } else if (!Platform::File::UnsafeShowOpenWith(NS2QString(toOpen))) {
  185. Platform::File::UnsafeLaunch(NS2QString(toOpen));
  186. }
  187. }
  188. - (void) dealloc {
  189. [toOpen release];
  190. if (menu) [menu release];
  191. [super dealloc];
  192. }
  193. @end // @implementation OpenFileWithInterface
  194. @interface NSURL(CompareUrls)
  195. - (BOOL) isEquivalent:(NSURL *)aURL;
  196. @end // @interface NSURL(CompareUrls)
  197. @implementation NSURL(CompareUrls)
  198. - (BOOL) isEquivalent:(NSURL *)aURL {
  199. if ([self isEqual:aURL]) return YES;
  200. if ([[self scheme] caseInsensitiveCompare:[aURL scheme]] != NSOrderedSame) return NO;
  201. if ([[self host] caseInsensitiveCompare:[aURL host]] != NSOrderedSame) return NO;
  202. if ([[self path] compare:[aURL path]] != NSOrderedSame) return NO;
  203. if ([[self port] compare:[aURL port]] != NSOrderedSame) return NO;
  204. if ([[self query] compare:[aURL query]] != NSOrderedSame) return NO;
  205. return YES;
  206. }
  207. @end // @implementation NSURL(CompareUrls)
  208. @interface ChooseApplicationDelegate : NSObject<NSOpenSavePanelDelegate> {
  209. }
  210. - (id) init:(NSArray *)recommendedApps withPanel:(NSOpenPanel *)creator withSelector:(NSPopUpButton *)menu withGood:(NSTextField *)goodLabel withBad:(NSTextField *)badLabel withIcon:(NSImageView *)badIcon withAccessory:(NSView *)acc;
  211. - (BOOL) panel:(id)sender shouldEnableURL:(NSURL *)url;
  212. - (void) panelSelectionDidChange:(id)sender;
  213. - (void) menuDidClose;
  214. - (void) dealloc;
  215. @end // @interface ChooseApplicationDelegate
  216. @implementation ChooseApplicationDelegate {
  217. BOOL onlyRecommended;
  218. NSArray *apps;
  219. NSOpenPanel *panel;
  220. NSPopUpButton *selector;
  221. NSTextField *good, *bad;
  222. NSImageView *icon;
  223. NSString *recom;
  224. NSView *accessory;
  225. }
  226. - (id) init:(NSArray *)recommendedApps withPanel:(NSOpenPanel *)creator withSelector:(NSPopUpButton *)menu withGood:(NSTextField *)goodLabel withBad:(NSTextField *)badLabel withIcon:(NSImageView *)badIcon withAccessory:(NSView *)acc {
  227. if (self = [super init]) {
  228. onlyRecommended = YES;
  229. recom = [Q2NSString(tr::lng_mac_recommended_apps(tr::now)) copy];
  230. apps = recommendedApps;
  231. panel = creator;
  232. selector = menu;
  233. good = goodLabel;
  234. bad = badLabel;
  235. icon = badIcon;
  236. accessory = acc;
  237. [selector setAction:@selector(menuDidClose)];
  238. }
  239. return self;
  240. }
  241. - (BOOL) isRecommended:(NSURL *)url {
  242. if (apps) {
  243. for (id app in apps) {
  244. if ([(NSURL*)app isEquivalent:url]) {
  245. return YES;
  246. }
  247. }
  248. }
  249. return NO;
  250. }
  251. - (BOOL) panel:(id)sender shouldEnableURL:(NSURL *)url {
  252. NSNumber *isDirectory;
  253. if ([url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil] && isDirectory != nil && [isDirectory boolValue]) {
  254. if (onlyRecommended) {
  255. CFStringRef ext = CFURLCopyPathExtension((CFURLRef)url);
  256. NSNumber *isPackage;
  257. if ([url getResourceValue:&isPackage forKey:NSURLIsPackageKey error:nil] && isPackage != nil && [isPackage boolValue]) {
  258. return [self isRecommended:url];
  259. }
  260. }
  261. return YES;
  262. }
  263. return NO;
  264. }
  265. - (void) panelSelectionDidChange:(id)sender {
  266. NSArray *urls = [panel URLs];
  267. if ([urls count]) {
  268. if ([self isRecommended:[urls firstObject]]) {
  269. [bad removeFromSuperview];
  270. [icon removeFromSuperview];
  271. [accessory addSubview:good];
  272. } else {
  273. [good removeFromSuperview];
  274. [accessory addSubview:bad];
  275. [accessory addSubview:icon];
  276. }
  277. } else {
  278. [good removeFromSuperview];
  279. [bad removeFromSuperview];
  280. [icon removeFromSuperview];
  281. }
  282. }
  283. - (void) menuDidClose {
  284. onlyRecommended = [[[selector selectedItem] title] isEqualToString:recom];
  285. [self refreshPanelTable];
  286. }
  287. - (BOOL) refreshDataInViews: (NSArray*)subviews {
  288. for (id view in subviews) {
  289. NSString *cls = [view className];
  290. if ([cls isEqualToString:Q2NSString(strNeedToReload())]) {
  291. [view reloadData];
  292. } else if ([cls isEqualToString:Q2NSString(strNeedToRefresh1())] || [cls isEqualToString:Q2NSString(strNeedToRefresh2())]) {
  293. [view reloadData];
  294. return YES;
  295. } else {
  296. NSArray *next = [view subviews];
  297. if ([next count] && [self refreshDataInViews:next]) {
  298. return YES;
  299. }
  300. }
  301. }
  302. return NO;
  303. }
  304. - (void) refreshPanelTable {
  305. @autoreleasepool {
  306. [self refreshDataInViews:[[panel contentView] subviews]];
  307. [panel validateVisibleColumns];
  308. }
  309. }
  310. - (void) dealloc {
  311. if (apps) {
  312. [apps release];
  313. [recom release];
  314. }
  315. [super dealloc];
  316. }
  317. @end // @implementation ChooseApplicationDelegate
  318. namespace Platform {
  319. namespace File {
  320. QString UrlToLocal(const QUrl &url) {
  321. auto result = url.toLocalFile();
  322. if (result.startsWith(u"/.file/id="_q)) {
  323. NSString *nsurl = [[[NSURL URLWithString: [NSString stringWithUTF8String: (u"file://"_q + result).toUtf8().constData()]] filePathURL] path];
  324. if (!nsurl) return QString();
  325. return NS2QString(nsurl);
  326. }
  327. return result;
  328. }
  329. bool UnsafeShowOpenWithDropdown(const QString &filepath) {
  330. @autoreleasepool {
  331. NSString *file = Q2NSString(filepath);
  332. @try {
  333. OpenFileWithInterface *menu = [[[OpenFileWithInterface alloc] init:file] autorelease];
  334. return !![menu popupAt:[NSEvent mouseLocation]];
  335. }
  336. @catch (NSException *exception) {
  337. }
  338. @finally {
  339. }
  340. }
  341. return false;
  342. }
  343. bool UnsafeShowOpenWith(const QString &filepath) {
  344. @autoreleasepool {
  345. NSString *file = Q2NSString(filepath);
  346. @try {
  347. NSURL *url = [NSURL fileURLWithPath:file];
  348. NSString *ext = [url pathExtension];
  349. NSArray *names = [url pathComponents];
  350. NSString *name = [names count] ? [names lastObject] : @"";
  351. NSArray *apps = (NSArray*)LSCopyApplicationURLsForURL(CFURLRef(url), kLSRolesAll);
  352. NSOpenPanel *openPanel = [NSOpenPanel openPanel];
  353. NSRect fullRect = { { 0., 0. }, { st::macAccessoryWidth, st::macAccessoryHeight } };
  354. NSView *accessory = [[NSView alloc] initWithFrame:fullRect];
  355. [accessory setAutoresizesSubviews:YES];
  356. NSPopUpButton *selector = [[NSPopUpButton alloc] init];
  357. [accessory addSubview:selector];
  358. [selector addItemWithTitle:Q2NSString(tr::lng_mac_recommended_apps(tr::now))];
  359. [selector addItemWithTitle:Q2NSString(tr::lng_mac_all_apps(tr::now))];
  360. [selector sizeToFit];
  361. NSTextField *enableLabel = [[NSTextField alloc] init];
  362. [accessory addSubview:enableLabel];
  363. [enableLabel setStringValue:Q2NSString(tr::lng_mac_enable_filter(tr::now))];
  364. [enableLabel setFont:[selector font]];
  365. [enableLabel setBezeled:NO];
  366. [enableLabel setDrawsBackground:NO];
  367. [enableLabel setEditable:NO];
  368. [enableLabel setSelectable:NO];
  369. [enableLabel sizeToFit];
  370. NSRect selectorFrame = [selector frame], enableFrame = [enableLabel frame];
  371. enableFrame.size.width += st::macEnableFilterAdd;
  372. enableFrame.origin.x = (fullRect.size.width - selectorFrame.size.width - enableFrame.size.width) / 2.;
  373. selectorFrame.origin.x = (fullRect.size.width - selectorFrame.size.width + enableFrame.size.width) / 2.;
  374. enableFrame.origin.y = fullRect.size.height - selectorFrame.size.height - st::macEnableFilterTop + (selectorFrame.size.height - enableFrame.size.height) / 2.;
  375. selectorFrame.origin.y = fullRect.size.height - selectorFrame.size.height - st::macSelectorTop;
  376. [enableLabel setFrame:enableFrame];
  377. [enableLabel setAutoresizingMask:NSViewMinXMargin|NSViewMaxXMargin];
  378. [selector setFrame:selectorFrame];
  379. [selector setAutoresizingMask:NSViewMinXMargin|NSViewMaxXMargin];
  380. NSButton *button = [[NSButton alloc] init];
  381. [accessory addSubview:button];
  382. [button setButtonType:NSSwitchButton];
  383. [button setFont:[selector font]];
  384. [button setTitle:Q2NSString(tr::lng_mac_always_open_with(tr::now))];
  385. [button sizeToFit];
  386. NSRect alwaysRect = [button frame];
  387. alwaysRect.origin.x = (fullRect.size.width - alwaysRect.size.width) / 2;
  388. alwaysRect.origin.y = selectorFrame.origin.y - alwaysRect.size.height - st::macAlwaysThisAppTop;
  389. [button setFrame:alwaysRect];
  390. [button setAutoresizingMask:NSViewMinXMargin|NSViewMaxXMargin];
  391. #ifdef OS_MAC_STORE
  392. [button setHidden:YES];
  393. #endif // OS_MAC_STORE
  394. NSTextField *goodLabel = [[NSTextField alloc] init];
  395. [goodLabel setStringValue:Q2NSString(tr::lng_mac_this_app_can_open(tr::now, lt_file, NS2QString(name)))];
  396. [goodLabel setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
  397. [goodLabel setBezeled:NO];
  398. [goodLabel setDrawsBackground:NO];
  399. [goodLabel setEditable:NO];
  400. [goodLabel setSelectable:NO];
  401. [goodLabel sizeToFit];
  402. NSRect goodFrame = [goodLabel frame];
  403. goodFrame.origin.x = (fullRect.size.width - goodFrame.size.width) / 2.;
  404. goodFrame.origin.y = alwaysRect.origin.y - goodFrame.size.height - st::macAppHintTop;
  405. [goodLabel setFrame:goodFrame];
  406. NSTextField *badLabel = [[NSTextField alloc] init];
  407. [badLabel setStringValue:Q2NSString(tr::lng_mac_not_known_app(tr::now, lt_file, NS2QString(name)))];
  408. [badLabel setFont:[goodLabel font]];
  409. [badLabel setBezeled:NO];
  410. [badLabel setDrawsBackground:NO];
  411. [badLabel setEditable:NO];
  412. [badLabel setSelectable:NO];
  413. [badLabel sizeToFit];
  414. NSImageView *badIcon = [[NSImageView alloc] init];
  415. NSImage *badImage = [NSImage imageNamed:NSImageNameCaution];
  416. [badIcon setImage:badImage];
  417. [badIcon setFrame:NSMakeRect(0, 0, st::macCautionIconSize, st::macCautionIconSize)];
  418. NSRect badFrame = [badLabel frame], badIconFrame = [badIcon frame];
  419. badFrame.origin.x = (fullRect.size.width - badFrame.size.width + badIconFrame.size.width) / 2.;
  420. badIconFrame.origin.x = (fullRect.size.width - badFrame.size.width - badIconFrame.size.width) / 2.;
  421. badFrame.origin.y = alwaysRect.origin.y - badFrame.size.height - st::macAppHintTop;
  422. badIconFrame.origin.y = badFrame.origin.y;
  423. [badLabel setFrame:badFrame];
  424. [badIcon setFrame:badIconFrame];
  425. [openPanel setAccessoryView:accessory];
  426. ChooseApplicationDelegate *delegate = [[ChooseApplicationDelegate alloc] init:apps withPanel:openPanel withSelector:selector withGood:goodLabel withBad:badLabel withIcon:badIcon withAccessory:accessory];
  427. [openPanel setDelegate:delegate];
  428. [openPanel setCanChooseDirectories:NO];
  429. [openPanel setCanChooseFiles:YES];
  430. [openPanel setAllowsMultipleSelection:NO];
  431. [openPanel setResolvesAliases:YES];
  432. [openPanel setTitle:Q2NSString(tr::lng_mac_choose_app(tr::now))];
  433. [openPanel setMessage:Q2NSString(tr::lng_mac_choose_text(tr::now, lt_file, NS2QString(name)))];
  434. NSArray *appsPaths = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationDirectory inDomains:NSLocalDomainMask];
  435. if ([appsPaths count]) [openPanel setDirectoryURL:[appsPaths firstObject]];
  436. [openPanel beginWithCompletionHandler:^(NSInteger result){
  437. if (result == NSModalResponseOK) {
  438. if ([[openPanel URLs] count] > 0) {
  439. NSURL *app = [[openPanel URLs] objectAtIndex:0];
  440. NSString *path = [app path];
  441. if ([button state] == NSOnState) {
  442. NSArray *UTIs = (NSArray *)UTTypeCreateAllIdentifiersForTag(kUTTagClassFilenameExtension,
  443. (CFStringRef)ext,
  444. nil);
  445. for (NSString *UTI in UTIs) {
  446. OSStatus result = LSSetDefaultRoleHandlerForContentType((CFStringRef)UTI,
  447. kLSRolesAll,
  448. (CFStringRef)[[NSBundle bundleWithPath:path] bundleIdentifier]);
  449. DEBUG_LOG(("App Info: set default handler for '%1' UTI result: %2").arg(NS2QString(UTI)).arg(result));
  450. }
  451. [UTIs release];
  452. }
  453. [[NSWorkspace sharedWorkspace] openFile:file withApplication:[app path]];
  454. }
  455. }
  456. [selector release];
  457. [button release];
  458. [enableLabel release];
  459. [goodLabel release];
  460. [badLabel release];
  461. [badIcon release];
  462. [accessory release];
  463. [delegate release];
  464. }];
  465. }
  466. @catch (NSException *exception) {
  467. [[NSWorkspace sharedWorkspace] openFile:file];
  468. }
  469. @finally {
  470. }
  471. }
  472. return YES;
  473. }
  474. void UnsafeLaunch(const QString &filepath) {
  475. @autoreleasepool {
  476. NSString *file = Q2NSString(filepath);
  477. if ([[NSWorkspace sharedWorkspace] openFile:file] == NO) {
  478. UnsafeShowOpenWith(filepath);
  479. }
  480. }
  481. }
  482. } // namespace File
  483. } // namespace Platform