diff --git a/Telegram/Resources/lang.txt b/Telegram/Resources/lang.txt index 2334335046..2824bf74f2 100644 --- a/Telegram/Resources/lang.txt +++ b/Telegram/Resources/lang.txt @@ -380,5 +380,16 @@ This software is licensed under [a href=\"https://github.com/telegramdesktop/tde source code is available on [a href=\"https://github.com/telegramdesktop/tdesktop\"]GitHub[/a]."; lng_about_done: "Done"; +// Mac specific + +lng_mac_choose_app: "Choose Application"; +lng_mac_choose_text: "Choose an application to open the document \"{file}\"."; +lng_mac_enable_filter: "Enable:"; +lng_mac_recommended_apps: "Recommended Applications"; +lng_mac_all_apps: "All Applications"; +lng_mac_always_open_with: "Always Open With"; +lng_mac_this_app_can_open: "This application can open \"{file}\"."; +lng_mac_not_known_app: "It's not known if this application can open \"{file}\"."; + // Keys finished diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index ea2129b826..a7aa82ee40 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -1385,3 +1385,13 @@ emojiPanSub: 0px; emojiPanDuration: 200; emojiPanHover: #f0f0f0; emojiPanRound: 2px; + +// Mac specific + +macAccessoryHeight: 90; +macEnableFilterAdd: 2; +macEnableFilterTop: 5; +macSelectorTop: 6; +macAlwaysThisAppTop: 4; +macAppHintTop: 8; +macCautionIconSize: size(16, 16); diff --git a/Telegram/SourceFiles/_other/genlang.cpp b/Telegram/SourceFiles/_other/genlang.cpp index ce3cee61b3..c02a9bbe06 100644 --- a/Telegram/SourceFiles/_other/genlang.cpp +++ b/Telegram/SourceFiles/_other/genlang.cpp @@ -53,8 +53,8 @@ bool skipComment(const char *&from, const char *end) { while (from < end && *from != '\n' && *from != '\r') { ++from; } - ++from; - return (from < end); + if (from < end) ++from; + return true; } else { return true; } diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 175914d48c..ca838cd8df 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -271,7 +271,7 @@ void VideoOpenLink::onClick(Qt::MouseButton button) const { QString already = data->already(true); if (!already.isEmpty()) { - QDesktopServices::openUrl(QUrl::fromLocalFile(already)); + psOpenFile(already); return; } @@ -331,7 +331,7 @@ void AudioOpenLink::onClick(Qt::MouseButton button) const { QString already = data->already(true); if (!already.isEmpty()) { - QDesktopServices::openUrl(QUrl::fromLocalFile(already)); + psOpenFile(already); return; } @@ -391,7 +391,7 @@ void DocumentOpenLink::onClick(Qt::MouseButton button) const { QString already = data->already(true); if (!already.isEmpty()) { - QDesktopServices::openUrl(QUrl::fromLocalFile(already)); + psOpenFile(already); return; } diff --git a/Telegram/SourceFiles/main.cpp b/Telegram/SourceFiles/main.cpp index 8174807e26..6c7cc3ebc7 100644 --- a/Telegram/SourceFiles/main.cpp +++ b/Telegram/SourceFiles/main.cpp @@ -47,6 +47,8 @@ int main(int argc, char *argv[]) { Application app(argc, argv); int result = App::quiting() ? 0 : app.exec(); + + psFinish(); DEBUG_LOG(("Application Info: Telegram done, result: %1").arg(result)); diff --git a/Telegram/SourceFiles/pspecific_mac.cpp b/Telegram/SourceFiles/pspecific_mac.cpp index 449ce75ef3..072616a1b0 100644 --- a/Telegram/SourceFiles/pspecific_mac.cpp +++ b/Telegram/SourceFiles/pspecific_mac.cpp @@ -1631,6 +1631,10 @@ void psShowInFolder(const QString &name) { objc_showInFinder(name.toUtf8().constData(), QFileInfo(name).absolutePath().toUtf8().constData()); } +void psFinish() { + objc_finish(); +} + void psExecUpdater() { /*QString targs = qsl("-update"); if (cFromAutoStart()) targs += qsl(" -autostart"); diff --git a/Telegram/SourceFiles/pspecific_mac.h b/Telegram/SourceFiles/pspecific_mac.h index 5d3ff10b1a..2ff8966c54 100644 --- a/Telegram/SourceFiles/pspecific_mac.h +++ b/Telegram/SourceFiles/pspecific_mac.h @@ -265,3 +265,4 @@ void psExecTelegram(); void psPostprocessFile(const QString &name); void psOpenFile(const QString &name, bool openWith = false); void psShowInFolder(const QString &name); +void psFinish(); diff --git a/Telegram/SourceFiles/pspecific_mac_p.h b/Telegram/SourceFiles/pspecific_mac_p.h index 1e1a31a598..c6edd93498 100644 --- a/Telegram/SourceFiles/pspecific_mac_p.h +++ b/Telegram/SourceFiles/pspecific_mac_p.h @@ -54,3 +54,4 @@ int64 objc_idleTime(); void objc_showInFinder(const char *utf8file, const char *utf8path); void objc_openFile(const char *utf8file, bool openwith); +void objc_finish(); diff --git a/Telegram/SourceFiles/pspecific_mac_p.mm b/Telegram/SourceFiles/pspecific_mac_p.mm index d6b57d34e7..5a0611fd35 100644 --- a/Telegram/SourceFiles/pspecific_mac_p.mm +++ b/Telegram/SourceFiles/pspecific_mac_p.mm @@ -18,10 +18,47 @@ Copyright (c) 2014 John Preston, https://tdesktop.com #include "stdafx.h" #include "pspecific_mac_p.h" +#include "lang.h" + #include #include #include +class QNSString { +public: + QNSString(const QString &str) : _str([[NSString alloc] initWithUTF8String:str.toUtf8().constData()]) { + } + QNSString &operator=(const QNSString &other) { + if (this != &other) { + [_str release]; + _str = [other._str copy]; + } + return *this; + } + QNSString(const QNSString &other) : _str([other._str copy]) { + } + ~QNSString() { + [_str release]; + } + + NSString *s() { + return _str; + } +private: + NSString *_str; +}; + +typedef QMap ObjcLang; +ObjcLang objcLang; + +QNSString objc_lang(LangKey key) { + ObjcLang::const_iterator i = objcLang.constFind(key); + if (i == objcLang.cend()) { + i = objcLang.insert(key, lang(key)); + } + return i.value(); +} + @interface ObserverHelper : NSObject { } @@ -299,8 +336,10 @@ void objc_showInFinder(const char *utf8file, const char *utf8path) { @interface ChooseApplicationDelegate : NSObject { } -- (id) init:(NSArray *)recommendedApps; +- (id) init:(NSArray *)recommendedApps withPanel:(NSOpenPanel *)creator withSelector:(NSPopUpButton *)menu withGood:(NSTextField *)goodLabel withBad:(NSTextField *)badLabel withIcon:(NSImageView *)badIcon withAccessory:(NSView *)acc; - (BOOL) panel:(id)sender shouldEnableURL:(NSURL *)url; +- (void) panelSelectionDidChange:(id)sender; +- (void) menuDidClose; - (void) dealloc; @end @@ -308,16 +347,41 @@ void objc_showInFinder(const char *utf8file, const char *utf8path) { @implementation ChooseApplicationDelegate { BOOL onlyRecommended; NSArray *apps; + NSOpenPanel *panel; + NSPopUpButton *selector; + NSTextField *good, *bad; + NSImageView *icon; + NSString *recom; + NSView *accessory; } -- (id) init:(NSArray *)recommendedApps { +- (id) init:(NSArray *)recommendedApps withPanel:(NSOpenPanel *)creator withSelector:(NSPopUpButton *)menu withGood:(NSTextField *)goodLabel withBad:(NSTextField *)badLabel withIcon:(NSImageView *)badIcon withAccessory:(NSView *)acc { if (self = [super init]) { onlyRecommended = YES; + recom = [objc_lang(lng_mac_recommended_apps).s() copy]; apps = recommendedApps; + panel = creator; + selector = menu; + good = goodLabel; + bad = badLabel; + icon = badIcon; + accessory = acc; + [selector setAction:@selector(menuDidClose)]; } return self; } +- (BOOL) isRecommended:(NSURL *)url { + if (apps) { + for (id app in apps) { + if ([(NSURL*)app isEquivalent:url]) { + return YES; + } + } + } + return NO; +} + - (BOOL) panel:(id)sender shouldEnableURL:(NSURL *)url { NSNumber *isDirectory; if ([url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil] && isDirectory != nil && [isDirectory boolValue]) { @@ -325,14 +389,7 @@ void objc_showInFinder(const char *utf8file, const char *utf8path) { CFStringRef ext = CFURLCopyPathExtension((CFURLRef)url); NSNumber *isPackage; if ([url getResourceValue:&isPackage forKey:NSURLIsPackageKey error:nil] && isPackage != nil && [isPackage boolValue]) { - if (apps) { - for (id app in apps) { - if ([(NSURL*)app isEquivalent:url]) { - return YES; - } - } - } - return NO; + return [self isRecommended:url]; } } return YES; @@ -340,9 +397,59 @@ void objc_showInFinder(const char *utf8file, const char *utf8path) { return NO; } +- (void) panelSelectionDidChange:(id)sender { + NSArray *urls = [panel URLs]; + if ([urls count]) { + if ([self isRecommended:[urls firstObject]]) { + [bad removeFromSuperview]; + [icon removeFromSuperview]; + [accessory addSubview:good]; + } else { + [good removeFromSuperview]; + [accessory addSubview:bad]; + [accessory addSubview:icon]; + } + } else { + [good removeFromSuperview]; + [bad removeFromSuperview]; + [icon removeFromSuperview]; + } +} + +- (void) menuDidClose { + onlyRecommended = [[[selector selectedItem] title] isEqualToString:recom]; + [self refreshPanelTable]; +} + +- (BOOL) refreshDataInViews: (NSArray*)subviews { + for (id view in subviews) { + NSString *cls = [view className]; + if ([cls isEqualToString:@"FI_TBrowserTableView"]) { + [view reloadData]; + } else if ([cls isEqualToString:@"FI_TListView"] || [cls isEqualToString:@"FI_TIconView"]) { + [view reloadData]; + return YES; + } else { + NSArray *next = [view subviews]; + if ([next count] && [self refreshDataInViews:next]) { + return YES; + } + } + } + + return NO; +} + + +- (void) refreshPanelTable { + [self refreshDataInViews:[[panel contentView] subviews]]; + [panel validateVisibleColumns]; +} + - (void) dealloc { if (apps) { [apps release]; + [recom release]; } [super dealloc]; } @@ -352,22 +459,150 @@ void objc_showInFinder(const char *utf8file, const char *utf8path) { void objc_openFile(const char *utf8file, bool openwith) { NSString *file = [[NSString alloc] initWithUTF8String:utf8file]; if (openwith || [[NSWorkspace sharedWorkspace] openFile:file] == NO) { - NSURL *url = [NSURL fileURLWithPath:file]; - NSArray *apps = (NSArray*)LSCopyApplicationURLsForURL(CFURLRef(url), kLSRolesAll); - - ChooseApplicationDelegate *delegate = [[ChooseApplicationDelegate alloc] init:apps]; - NSOpenPanel *openPanel = [NSOpenPanel openPanel]; - - [openPanel setCanChooseDirectories:NO]; - [openPanel setCanChooseFiles:YES]; - [openPanel setAllowsMultipleSelection:NO]; - [openPanel setDelegate:delegate]; - [openPanel setTitle:@"Choose Application"]; - [openPanel setMessage:@"Choose an application to open the document \"blabla.png\"."]; - if ([openPanel runModal] == NSOKButton) { - NSArray *result = [openPanel URLs]; + @try { + NSURL *url = [NSURL fileURLWithPath:file]; + NSString *ext = [url pathExtension]; + NSArray *names =[url pathComponents]; + NSString *name = [names count] ? [names lastObject] : @""; + NSArray *apps = (NSArray*)LSCopyApplicationURLsForURL(CFURLRef(url), kLSRolesAll); + + NSOpenPanel *openPanel = [NSOpenPanel openPanel]; + + NSView *accessory = [[NSView alloc] init]; + + [openPanel setAccessoryView:accessory]; + NSRect fullRect = [[accessory superview] frame]; + fullRect.origin = NSMakePoint(0, 0); + fullRect.size.height = st::macAccessoryHeight; + [accessory setFrame:fullRect]; + [accessory setAutoresizesSubviews:YES]; + + NSPopUpButton *selector = [[NSPopUpButton alloc] init]; + [accessory addSubview:selector]; + [selector addItemWithTitle:objc_lang(lng_mac_recommended_apps).s()]; + [selector addItemWithTitle:objc_lang(lng_mac_all_apps).s()]; + [selector sizeToFit]; + + NSTextField *enableLabel = [[NSTextField alloc] init]; + [accessory addSubview:enableLabel]; + [enableLabel setStringValue:objc_lang(lng_mac_enable_filter).s()]; + [enableLabel setFont:[selector font]]; + [enableLabel setBezeled:NO]; + [enableLabel setDrawsBackground:NO]; + [enableLabel setEditable:NO]; + [enableLabel setSelectable:NO]; + [enableLabel sizeToFit]; + + NSRect selectorFrame = [selector frame], enableFrame = [enableLabel frame]; + enableFrame.size.width += st::macEnableFilterAdd; + enableFrame.origin.x = (fullRect.size.width - selectorFrame.size.width - enableFrame.size.width) / 2.; + selectorFrame.origin.x = (fullRect.size.width - selectorFrame.size.width + enableFrame.size.width) / 2.; + enableFrame.origin.y = fullRect.size.height - selectorFrame.size.height - st::macEnableFilterTop + (selectorFrame.size.height - enableFrame.size.height) / 2.; + selectorFrame.origin.y = fullRect.size.height - selectorFrame.size.height - st::macSelectorTop; + [enableLabel setFrame:enableFrame]; + [enableLabel setAutoresizingMask:NSViewMinXMargin|NSViewMaxXMargin]; + [selector setFrame:selectorFrame]; + [selector setAutoresizingMask:NSViewMinXMargin|NSViewMaxXMargin]; + + NSButton *button = [[NSButton alloc] init]; + [accessory addSubview:button]; + [button setButtonType:NSSwitchButton]; + [button setFont:[selector font]]; + [button setTitle:objc_lang(lng_mac_always_open_with).s()]; + [button sizeToFit]; + NSRect alwaysRect = [button frame]; + alwaysRect.origin.x = (fullRect.size.width - alwaysRect.size.width) / 2; + alwaysRect.origin.y = selectorFrame.origin.y - alwaysRect.size.height - st::macAlwaysThisAppTop; + [button setFrame:alwaysRect]; + [button setAutoresizingMask:NSViewMinXMargin|NSViewMaxXMargin]; + + NSTextField *goodLabel = [[NSTextField alloc] init]; + [goodLabel setStringValue:[objc_lang(lng_mac_this_app_can_open).s() stringByReplacingOccurrencesOfString:@"{file}" withString:name]]; + [goodLabel setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; + [goodLabel setBezeled:NO]; + [goodLabel setDrawsBackground:NO]; + [goodLabel setEditable:NO]; + [goodLabel setSelectable:NO]; + [goodLabel sizeToFit]; + NSRect goodFrame = [goodLabel frame]; + goodFrame.origin.x = (fullRect.size.width - goodFrame.size.width) / 2.; + goodFrame.origin.y = alwaysRect.origin.y - goodFrame.size.height - st::macAppHintTop; + [goodLabel setFrame:goodFrame]; + + NSTextField *badLabel = [[NSTextField alloc] init]; + [badLabel setStringValue:[objc_lang(lng_mac_not_known_app).s() stringByReplacingOccurrencesOfString:@"{file}" withString:name]]; + [badLabel setFont:[goodLabel font]]; + [badLabel setBezeled:NO]; + [badLabel setDrawsBackground:NO]; + [badLabel setEditable:NO]; + [badLabel setSelectable:NO]; + [badLabel sizeToFit]; + NSImageView *badIcon = [[NSImageView alloc] init]; + NSImage *badImage = [NSImage imageNamed:NSImageNameCaution]; + [badIcon setImage:badImage]; + [badIcon setFrame:NSMakeRect(0, 0, st::macCautionIconSize.width(), st::macCautionIconSize.height())]; + + NSRect badFrame = [badLabel frame], badIconFrame = [badIcon frame]; + badFrame.origin.x = (fullRect.size.width - badFrame.size.width + badIconFrame.size.width) / 2.; + badIconFrame.origin.x = (fullRect.size.width - badFrame.size.width - badIconFrame.size.width) / 2.; + badFrame.origin.y = alwaysRect.origin.y - badFrame.size.height - st::macAppHintTop; + badIconFrame.origin.y = badFrame.origin.y; + [badLabel setFrame:badFrame]; + [badIcon setFrame:badIconFrame]; + + ChooseApplicationDelegate *delegate = [[ChooseApplicationDelegate alloc] init:apps withPanel:openPanel withSelector:selector withGood:goodLabel withBad:badLabel withIcon:badIcon withAccessory:accessory]; + [openPanel setDelegate:delegate]; + + [openPanel setCanChooseDirectories:NO]; + [openPanel setCanChooseFiles:YES]; + [openPanel setAllowsMultipleSelection:NO]; + [openPanel setResolvesAliases:YES]; + [openPanel setTitle:objc_lang(lng_mac_choose_app).s()]; + [openPanel setMessage:[objc_lang(lng_mac_choose_text).s() stringByReplacingOccurrencesOfString:@"{file}" withString:name]]; + + NSArray *appsPaths = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationDirectory inDomains:NSLocalDomainMask]; + if ([appsPaths count]) [openPanel setDirectoryURL:[appsPaths firstObject]]; + [openPanel beginWithCompletionHandler:^(NSInteger result){ + if (result == NSFileHandlingPanelOKButton) { + if ([[openPanel URLs] count] > 0) { + NSURL *app = [[openPanel URLs] objectAtIndex:0]; + NSString *path = [app path]; + if ([button state] == NSOnState) { + NSArray *UTIs = (NSArray *)UTTypeCreateAllIdentifiersForTag(kUTTagClassFilenameExtension, + (CFStringRef)ext, + nil); + for (NSString *UTI in UTIs) { + LSSetDefaultRoleHandlerForContentType((CFStringRef)UTI, + kLSRolesEditor, + (CFStringRef)[[NSBundle bundleWithPath:path] bundleIdentifier]); + } + + [UTIs release]; + } + [[NSWorkspace sharedWorkspace] openFile:file withApplication:[app path]]; + } + } + [selector release]; + [button release]; + [enableLabel release]; + [goodLabel release]; + [badLabel release]; + [badIcon release]; + [accessory release]; + [delegate release]; + }]; + } + @catch (NSException *exception) { + [[NSWorkspace sharedWorkspace] openFile:file]; + } + @finally { } - [delegate release]; } [file release]; } + +void objc_finish() { + if (!objcLang.isEmpty()) { + objcLang.clear(); + } +} diff --git a/Telegram/SourceFiles/pspecific_wnd.cpp b/Telegram/SourceFiles/pspecific_wnd.cpp index 4bf579be4b..1f82295331 100644 --- a/Telegram/SourceFiles/pspecific_wnd.cpp +++ b/Telegram/SourceFiles/pspecific_wnd.cpp @@ -2639,6 +2639,9 @@ void psShowInFolder(const QString &name) { ShellExecute(0, 0, qsl("explorer").toStdWString().c_str(), (qsl("/select,") + nameEscaped).toStdWString().c_str(), 0, SW_SHOWNORMAL); } +void psFinish() { +} + void psExecUpdater() { QString targs = qsl("-update"); if (cFromAutoStart()) targs += qsl(" -autostart"); diff --git a/Telegram/SourceFiles/pspecific_wnd.h b/Telegram/SourceFiles/pspecific_wnd.h index 6189c380d3..be6b205bb9 100644 --- a/Telegram/SourceFiles/pspecific_wnd.h +++ b/Telegram/SourceFiles/pspecific_wnd.h @@ -259,3 +259,4 @@ void psExecTelegram(); void psPostprocessFile(const QString &name); void psOpenFile(const QString &name, bool openWith = false); void psShowInFolder(const QString &name); +void psFinish(); diff --git a/Telegram/Telegram/Images.xcassets/AppIcon-2.appiconset/Contents.json b/Telegram/Telegram/Images.xcassets/AppIcon-2.appiconset/Contents.json deleted file mode 100644 index 50ab7bd32c..0000000000 --- a/Telegram/Telegram/Images.xcassets/AppIcon-2.appiconset/Contents.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "images" : [ - { - "idiom" : "mac", - "scale" : "1x", - "size" : "16x16" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "16x16" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "32x32" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "32x32" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "128x128" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "128x128" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "256x256" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "256x256" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "512x512" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "512x512" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file