mirror of
https://github.com/nextcloud/desktop.git
synced 2024-12-11 18:26:31 +03:00
9ef8658122
Do not request the status of all entries in the cache. Instead force Finder to request the ones that it deems necessary by keeping the old statuses in a separate dictionary which are only used while the new status arrives.
357 lines
9.7 KiB
Objective-C
357 lines
9.7 KiB
Objective-C
/**
|
|
* Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
|
|
*
|
|
* This library is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU Lesser General Public License as published by the Free
|
|
* Software Foundation; either version 2.1 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*/
|
|
|
|
#import <AppKit/NSApplication.h>
|
|
#import <AppKit/NSWindow.h>
|
|
#import <objc/runtime.h>
|
|
#import "ContentManager.h"
|
|
#import "MenuManager.h"
|
|
#import "RequestManager.h"
|
|
#import "IconCache.h"
|
|
|
|
static ContentManager* sharedInstance = nil;
|
|
|
|
@implementation ContentManager
|
|
- init
|
|
{
|
|
self = [super init];
|
|
|
|
if (self)
|
|
{
|
|
_fileNamesCache = [[NSMutableDictionary alloc] init];
|
|
_oldFileNamesCache = [[NSMutableDictionary alloc] init];
|
|
_fileIconsEnabled = TRUE;
|
|
_hasChangedContent = TRUE;
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
[self removeAllIcons];
|
|
[_fileNamesCache release];
|
|
[_oldFileNamesCache release];
|
|
sharedInstance = nil;
|
|
|
|
[super dealloc];
|
|
}
|
|
|
|
+ (ContentManager*)sharedInstance
|
|
{
|
|
@synchronized(self)
|
|
{
|
|
if (sharedInstance == nil)
|
|
{
|
|
sharedInstance = [[self alloc] init];
|
|
}
|
|
}
|
|
|
|
return sharedInstance;
|
|
}
|
|
|
|
- (void)loadIconResourcePath:(NSString*)path
|
|
{
|
|
NSString *base = path;
|
|
|
|
_icnOk = [[IconCache sharedInstance] registerIcon:[base stringByAppendingPathComponent:@"ok.icns"]];
|
|
_icnSync = [[IconCache sharedInstance] registerIcon:[base stringByAppendingPathComponent:@"sync.icns"]];
|
|
_icnWarn = [[IconCache sharedInstance] registerIcon:[base stringByAppendingPathComponent:@"warning.icns"]];
|
|
_icnErr = [[IconCache sharedInstance] registerIcon:[base stringByAppendingPathComponent:@"error.icns"]];
|
|
_icnOkSwm = [[IconCache sharedInstance] registerIcon:[base stringByAppendingPathComponent:@"ok_swm.icns"]];
|
|
_icnSyncSwm = [[IconCache sharedInstance] registerIcon:[base stringByAppendingPathComponent:@"sync_swm.icns"]];
|
|
_icnWarnSwm = [[IconCache sharedInstance] registerIcon:[base stringByAppendingPathComponent:@"warning_swm.icns"]];
|
|
_icnErrSwm = [[IconCache sharedInstance] registerIcon:[base stringByAppendingPathComponent:@"error_swm.icns"]];
|
|
|
|
// NSLog(@"Icon ok identifier: %d from %@", [_icnOk intValue], [base stringByAppendingString:@"ok.icns"]);
|
|
}
|
|
|
|
- (void)enableFileIcons:(BOOL)enable
|
|
{
|
|
_fileIconsEnabled = enable;
|
|
|
|
[self repaintAllWindows];
|
|
}
|
|
|
|
- (void)setResultForPath:(NSString*)path result:(NSString*)result
|
|
{
|
|
if (_icnOk == nil) {
|
|
// no icon resource path registered yet
|
|
return;
|
|
}
|
|
|
|
NSNumber *res;
|
|
res = [NSNumber numberWithInt:0];
|
|
|
|
if( [result isEqualToString:@"OK"] ) {
|
|
res = _icnOk;
|
|
} else if( [result isEqualToString:@"SYNC"] || [result isEqualToString:@"NEW"] ) {
|
|
res = _icnSync;
|
|
} else if( [result isEqualToString:@"IGNORE"]) {
|
|
res = _icnWarn;
|
|
} else if( [result isEqualToString:@"ERROR"]) {
|
|
res = _icnErr;
|
|
} else if( [result isEqualToString:@"OK+SWM"] ) {
|
|
res = _icnOkSwm;
|
|
} else if( [result isEqualToString:@"SYNC+SWM"] || [result isEqualToString:@"NEW+SWM"] ) {
|
|
res = _icnSyncSwm;
|
|
} else if( [result isEqualToString:@"IGNORE+SWM"]) {
|
|
res = _icnWarnSwm;
|
|
} else if( [result isEqualToString:@"ERROR+SWM"]) {
|
|
res = _icnErrSwm;
|
|
}else if( [result isEqualToString:@"NOP"]) {
|
|
// Nothing.
|
|
} else {
|
|
NSLog(@"SyncState: Unknown status code %@", result);
|
|
}
|
|
|
|
NSString* normalizedPath = [path decomposedStringWithCanonicalMapping];
|
|
|
|
if (![_fileNamesCache objectForKey:normalizedPath] || ![[_fileNamesCache objectForKey:normalizedPath] isEqualTo:res]) {
|
|
[_fileNamesCache setObject:res forKey:normalizedPath];
|
|
//NSLog(@"SET value %d %@", [res intValue], normalizedPath);
|
|
_hasChangedContent = YES;
|
|
[self performSelector:@selector(repaintAllWindowsIfNeeded) withObject:0 afterDelay:1.0]; // 1 sec
|
|
}
|
|
}
|
|
|
|
- (NSNumber*)iconByPath:(NSString*)path isDirectory:(BOOL)isDir
|
|
{
|
|
//NSLog(@"%@ %@", NSStringFromSelector(_cmd), path);
|
|
if (!_fileIconsEnabled)
|
|
{
|
|
NSLog(@"SyncState: Icons are NOT ENABLED!");
|
|
// return nil;
|
|
}
|
|
|
|
if( path == nil ) {
|
|
NSNumber *res = [NSNumber numberWithInt:0];
|
|
return res;
|
|
}
|
|
NSString* normalizedPath = [path decomposedStringWithCanonicalMapping];
|
|
|
|
if (![[RequestManager sharedInstance] isRegisteredPath:normalizedPath isDirectory:isDir]) {
|
|
return [NSNumber numberWithInt:0];
|
|
}
|
|
|
|
NSNumber* result = [_fileNamesCache objectForKey:normalizedPath];
|
|
// NSLog(@"XXXXXXX Asking for icon for path %@ = %d",normalizedPath, [result intValue]);
|
|
|
|
if( result == nil ) {
|
|
// start the async call
|
|
[[RequestManager sharedInstance] askForIcon:normalizedPath isDirectory:isDir];
|
|
result = [NSNumber numberWithInt:0];
|
|
// Set 0 into the cache, meaning "don't have an icon, but already requested it"
|
|
[_fileNamesCache setObject:result forKey:normalizedPath];
|
|
}
|
|
if ([result intValue] == 0) {
|
|
// Show the old state while we wait for the new one
|
|
NSNumber* oldResult = [_oldFileNamesCache objectForKey:normalizedPath];
|
|
if (oldResult)
|
|
result = oldResult;
|
|
}
|
|
// NSLog(@"iconByPath return value %d", [result intValue]);
|
|
|
|
return result;
|
|
}
|
|
|
|
// Clears the entries from the hash to make it call again home to the desktop client.
|
|
- (void)clearFileNameCache
|
|
{
|
|
[_fileNamesCache release];
|
|
_fileNamesCache = [[NSMutableDictionary alloc] init];
|
|
[_oldFileNamesCache removeAllObjects];
|
|
}
|
|
|
|
- (void)reFetchFileNameCacheForPath:(NSString*)path
|
|
{
|
|
//NSLog(@"%@", NSStringFromSelector(_cmd));
|
|
|
|
// We won't request the new state if if finds the path in _fileNamesCache
|
|
// Move all entries to _oldFileNamesCache so that the get re-requested, but
|
|
// still available while we refill the cache
|
|
[_oldFileNamesCache addEntriesFromDictionary:_fileNamesCache];
|
|
[_fileNamesCache removeAllObjects];
|
|
|
|
[self repaintAllWindows];
|
|
}
|
|
|
|
|
|
- (void)removeAllIcons
|
|
{
|
|
[_fileNamesCache removeAllObjects];
|
|
[_oldFileNamesCache removeAllObjects];
|
|
|
|
[self repaintAllWindows];
|
|
}
|
|
|
|
- (void)repaintAllWindowsIfNeeded
|
|
{
|
|
if (!_hasChangedContent) {
|
|
//NSLog(@"%@ Repaint scheduled but not needed", NSStringFromSelector(_cmd));
|
|
return;
|
|
}
|
|
|
|
_hasChangedContent = NO;
|
|
[self repaintAllWindows];
|
|
}
|
|
|
|
- (void)repaintAllWindows
|
|
{
|
|
//NSLog(@"%@", NSStringFromSelector(_cmd));
|
|
NSArray* windows = [[NSApplication sharedApplication] windows];
|
|
|
|
for (int i = 0; i < [windows count]; i++)
|
|
{
|
|
NSWindow* window = [windows objectAtIndex:i];
|
|
|
|
if (![window isVisible])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
MenuManager* menuManager = [MenuManager sharedInstance];
|
|
RequestManager* requestManager = [RequestManager sharedInstance];
|
|
|
|
if ([[window className] isEqualToString:@"TBrowserWindow"])
|
|
{
|
|
NSObject* browserWindowController = [window browserWindowController];
|
|
|
|
BOOL repaintWindow = YES;
|
|
|
|
NSString* filterFolder = [requestManager filterFolder];
|
|
|
|
if (filterFolder)
|
|
{
|
|
repaintWindow = NO;
|
|
|
|
struct TFENodeVector* targetPath;
|
|
|
|
if ([browserWindowController respondsToSelector:@selector(targetPath)])
|
|
{
|
|
// 10.7 & 10.8
|
|
targetPath = [browserWindowController targetPath];
|
|
}
|
|
else if ([browserWindowController respondsToSelector:@selector(activeContainer)])
|
|
{
|
|
// 10.9
|
|
targetPath = [[browserWindowController activeContainer] targetPath];
|
|
}
|
|
else
|
|
{
|
|
NSLog(@"SyncState: refreshing icon badges failed");
|
|
|
|
return;
|
|
}
|
|
|
|
NSArray* folderPaths = [menuManager pathsForNodes:targetPath];
|
|
|
|
for (NSString* folderPath in folderPaths)
|
|
{
|
|
if ([folderPath hasPrefix:filterFolder] || [filterFolder hasPrefix:folderPath])
|
|
{
|
|
repaintWindow = YES;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (repaintWindow)
|
|
{
|
|
if ([browserWindowController respondsToSelector:@selector(browserViewController)])
|
|
{
|
|
// 10.7 & 10.8
|
|
NSObject* browserViewController = [browserWindowController browserViewController];
|
|
|
|
NSObject* browserView = [browserViewController browserView];
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{[browserView setNeedsDisplay:YES];});
|
|
}
|
|
else if ([browserWindowController respondsToSelector:@selector(activeBrowserViewController)])
|
|
{
|
|
// 10.9
|
|
NSObject* browserViewController = [browserWindowController activeBrowserViewController];
|
|
|
|
NSObject* browserView = [browserViewController browserView];
|
|
|
|
if ([browserView isKindOfClass:(id)objc_getClass("TListView")])
|
|
{
|
|
// List or Coverflow View
|
|
[self setNeedsDisplayForListView:browserView];
|
|
}
|
|
else
|
|
{
|
|
// Icon or Column View
|
|
dispatch_async(dispatch_get_main_queue(), ^{[browserView setNeedsDisplay:YES];});
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NSLog(@"SyncState: refreshing icon badges failed");
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)setIcons:(NSDictionary*)iconDictionary filterByFolder:(NSString*)filterFolder
|
|
{
|
|
NSLog(@"%@", NSStringFromSelector(_cmd));
|
|
for (NSString* path in iconDictionary)
|
|
{
|
|
if (filterFolder && ![path hasPrefix:filterFolder])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
NSString* normalizedPath = [path decomposedStringWithCanonicalMapping];
|
|
NSNumber* iconId = [iconDictionary objectForKey:path];
|
|
|
|
if ([iconId intValue] == -1)
|
|
{
|
|
[_fileNamesCache removeObjectForKey:normalizedPath];
|
|
}
|
|
else
|
|
{
|
|
[_oldFileNamesCache removeObjectForKey:normalizedPath];
|
|
[_fileNamesCache setObject:iconId forKey:normalizedPath];
|
|
}
|
|
}
|
|
|
|
[self repaintAllWindows];
|
|
}
|
|
|
|
- (void)setNeedsDisplayForListView:(NSView*)view
|
|
{
|
|
NSArray* subviews = [view subviews];
|
|
|
|
for (int i = 0; i < [subviews count]; i++)
|
|
{
|
|
NSView* subview = [subviews objectAtIndex:i];
|
|
|
|
if ([subview isKindOfClass:(id)objc_getClass("TListRowView")])
|
|
{
|
|
[self setNeedsDisplayForListView:subview];
|
|
}
|
|
else if ([subview isKindOfClass:(id)objc_getClass("TListNameCellView")])
|
|
{
|
|
dispatch_async(dispatch_get_main_queue(), ^{[subview setNeedsDisplay:YES];});
|
|
}
|
|
}
|
|
}
|
|
|
|
@end
|