tweak history impl so as not to require opening and resaving history just to append

This commit is contained in:
anthony 2020-12-31 22:55:28 +00:00
parent 8046fb8af2
commit 544ae837d5
7 changed files with 122 additions and 138 deletions

View File

@ -26,6 +26,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
@interface AppDelegate: NSResponder<NSApplicationDelegate> { @interface AppDelegate: NSResponder<NSApplicationDelegate> {
@private @private
NSMutableArray *recentHistory;
id downloadsWindowController; id downloadsWindowController;
id findPanelController; id findPanelController;
id historyWindowController; id historyWindowController;

View File

@ -15,6 +15,8 @@
#import "HistoryWindowController.h" #import "HistoryWindowController.h"
#import "Website.h" #import "Website.h"
#define MAX_RECENT_HISTORY 6
/** /**
* Set option defaults for (taken from the cocoa frontend) * Set option defaults for (taken from the cocoa frontend)
* *
@ -43,26 +45,26 @@ static nserror set_defaults(struct nsoption_s *defaults)
} }
-(void)historyUpdated: (NSNotification*)aNotification { -(void)historyUpdated: (NSNotification*)aNotification {
NSLog(@"history updated..."); NSLog(@"history updated... %@", aNotification);
NSArray *history = [Website historicWebsites]; id object = [aNotification object];
NSMenu *historyMenu = [[[NSApp menu] itemWithTag: TAG_SUBMENU_HISTORY] submenu]; NSMenu *historyMenu = [[[NSApp menu] itemWithTag: TAG_SUBMENU_HISTORY] submenu];
for (NSInteger i = [historyMenu numberOfItems] - 1; i > 0; i--) {
[historyMenu removeItemAtIndex: i]; if ([object isKindOfClass: [Website class]]) {
} [recentHistory insertObject: object atIndex: 0];
Website *website; NSMenuItem *menuItem = [[[NSMenuItem alloc] initWithTitle: [object name]
NSMenuItem *menuItem;
for (NSInteger i = 0; i < [history count] && i < 5; i++) {
website = [history objectAtIndex: i];
menuItem = [[[NSMenuItem alloc] initWithTitle: [website name]
action: @selector(open) keyEquivalent: nil] autorelease]; action: @selector(open) keyEquivalent: nil] autorelease];
[menuItem setTarget: website]; [menuItem setTarget: object];
[historyMenu addItem: menuItem]; [historyMenu insertItem: menuItem atIndex: 1];
if ([recentHistory count] > MAX_RECENT_HISTORY) {
[recentHistory removeLastObject];
[historyMenu removeItemAtIndex: [historyMenu numberOfItems] - 1];
}
} }
[historyMenu update];
} }
-(void)awakeFromNib { -(void)awakeFromNib {
NSLog(@"App awake from nib"); NSLog(@"App awake from nib");
recentHistory = [[NSMutableArray alloc] init];
[[NSNotificationCenter defaultCenter] addObserver: self [[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(historyUpdated:) selector: @selector(historyUpdated:)
name: WebsiteHistoryUpdatedNotificationName name: WebsiteHistoryUpdatedNotificationName
@ -127,7 +129,7 @@ static nserror set_defaults(struct nsoption_s *defaults)
struct nsurl *url; struct nsurl *url;
nserror error; nserror error;
error = nsurl_create([[[aWebsite url] absoluteString] cString], &url); error = nsurl_create([[aWebsite url] cString], &url);
if (error == NSERROR_OK) { if (error == NSERROR_OK) {
error = browser_window_create(BW_CREATE_HISTORY, url, NULL, NULL, NULL); error = browser_window_create(BW_CREATE_HISTORY, url, NULL, NULL, NULL);
nsurl_unref(url); nsurl_unref(url);

View File

@ -131,7 +131,7 @@
NSString *name = [NSString stringWithCString: title]; NSString *name = [NSString stringWithCString: title];
NSString *urlStr = [NSString stringWithCString: nsurl_access(url)]; NSString *urlStr = [NSString stringWithCString: nsurl_access(url)];
Website *website = [[Website alloc] initWithName: name Website *website = [[Website alloc] initWithName: name
url: [NSURL URLWithString: urlStr]]; url: urlStr];
[website addToHistory]; [website addToHistory];
[website release]; [website release];
} }

View File

@ -3,7 +3,7 @@
@interface HistoryWindowController: NSWindowController { @interface HistoryWindowController: NSWindowController {
id outlineView; id outlineView;
BOOL ignoreRefresh; BOOL ignoreRefresh;
NSMutableDictionary *historyItems; NSArray *sections;
} }
@end @end

View File

@ -1,28 +1,63 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#import "HistoryWindowController.h" #import "HistoryWindowController.h"
#import "Website.h" #import "Website.h"
#import "AppDelegate.h" #import "AppDelegate.h"
#import "desktop/global_history.h"
@interface Section: NSObject {
NSString *name;
NSArray *items;
}
@end
@implementation Section
+(id)sectionWithName: (NSString*)aName items: (NSArray*)someItems {
Section *section = [[[Section alloc] init] autorelease];
section->name = [aName retain];
section->items = [someItems retain];
return section;
}
-(NSString*)name {
return name;
}
-(NSArray*)items {
return items;
}
-(void)setItems: (NSArray*)someItems {
[items release];
items = [someItems retain];
}
-(void)dealloc {
[name release];
[items release];
[super dealloc];
}
@end
@implementation HistoryWindowController @implementation HistoryWindowController
-(id)init { -(id)init {
if (self = [super initWithWindowNibName: @"History"]) { if (self = [super initWithWindowNibName: @"History"]) {
historyItems = [[NSMutableDictionary alloc] init];
[historyItems setObject: [Website historicWebsites] forKey: @"recent"];
ignoreRefresh = NO; ignoreRefresh = NO;
sections = [[NSArray arrayWithObjects: [Section sectionWithName: @"Recent"
items: [NSArray array]], [Section sectionWithName:
@"More than 2 months ago..." items: [NSArray array]], nil]
retain];
[self updateItems: nil];
} }
return self; return self;
} }
-(void)dealloc { -(void)dealloc {
[historyItems release]; [sections release];
[super dealloc]; [super dealloc];
} }
-(void)updateItems: (NSNotification*)aNotification { -(void)updateItems: (NSNotification*)aNotification {
if (!ignoreRefresh) { if (!ignoreRefresh) {
[historyItems setObject: [Website historicWebsites] forKey: @"recent"]; [[sections objectAtIndex: 0] setItems: [NSArray array]];
[[sections objectAtIndex: 1] setItems: [NSArray array]];
[outlineView reloadData]; [outlineView reloadData];
} }
} }
@ -47,7 +82,7 @@
-(void)awakeFromNib { -(void)awakeFromNib {
[[self window] makeKeyAndOrderFront: self]; [[self window] makeKeyAndOrderFront: self];
[self registerForHistoryNotifications]; [self registerForHistoryNotifications];
[outlineView expandItem: [[historyItems allValues] firstObject] expandChildren: NO]; [outlineView expandItem: [sections firstObject] expandChildren: NO];
} }
-(BOOL)validateMenuItem: (NSMenuItem*)aMenuItem { -(BOOL)validateMenuItem: (NSMenuItem*)aMenuItem {
@ -99,14 +134,14 @@
-(id)outlineView: (NSOutlineView*)outlineView child: (NSInteger)index ofItem: (id)item { -(id)outlineView: (NSOutlineView*)outlineView child: (NSInteger)index ofItem: (id)item {
if (item == nil) { if (item == nil) {
return [[historyItems allValues] firstObject]; return [sections objectAtIndex: index];
} else { } else {
return [item objectAtIndex: index]; return [[item items] objectAtIndex: index];
} }
} }
-(BOOL)outlineView: (NSOutlineView*)outlineView isItemExpandable: (id)item { -(BOOL)outlineView: (NSOutlineView*)outlineView isItemExpandable: (id)item {
if ([item isKindOfClass: [NSArray class]]) { if ([item isKindOfClass: [Section class]]) {
return YES; return YES;
} else { } else {
return NO; return NO;
@ -115,20 +150,16 @@
-(NSInteger)outlineView: (NSOutlineView*)outlineView numberOfChildrenOfItem: (id)item { -(NSInteger)outlineView: (NSOutlineView*)outlineView numberOfChildrenOfItem: (id)item {
if (item == nil) { if (item == nil) {
return 1; return [sections count];
} else if ([item isKindOfClass: [Section class]]) {
return [[item items] count];
} else {
return 0;
} }
return [item count];
} }
-(id)outlineView: (NSOutlineView*)outlineView objectValueForTableColumn: (NSTableColumn*)tableColumn byItem: (id)item { -(id)outlineView: (NSOutlineView*)outlineView objectValueForTableColumn: (NSTableColumn*)tableColumn byItem: (id)item {
if ([item isKindOfClass: [NSArray class]]) { return [item name];
return @"Recent History";
} else if ([item isKindOfClass: [Website class]]) {
return [item name];
} else {
NSLog(@"clas: %@", [item class]);
return @"Error";
}
} }
-(BOOL)outlineView: (NSOutlineView*)outlineView shouldSelectItem: (id)item { -(BOOL)outlineView: (NSOutlineView*)outlineView shouldSelectItem: (id)item {

View File

@ -2,21 +2,21 @@
#define WebsiteHistoryUpdatedNotificationName @"WebsiteHistoryUpdatedNotification" #define WebsiteHistoryUpdatedNotificationName @"WebsiteHistoryUpdatedNotification"
struct website_data {
int len_name;
int len_url;
char data[];
};
@class BookmarkFolder; @class BookmarkFolder;
@interface Website: NSObject { @interface Website: NSObject {
NSString *name; struct website_data *data;
NSURL *url;
NSDate *lastVisited;
} }
-(id)initWithName: (NSString*)aName url: (NSURL*)aUrl; -(id)initWithName: (NSString*)aName url: (NSString*)aUrl;
-(NSString*)name; -(NSString*)name;
-(NSURL*)url; -(NSString*)url;
-(void)open; -(void)open;
-(void)addToHistory; -(void)addToHistory;
-(void)removeFromHistory;
+(NSArray*)historicWebsites;
@end @end

View File

@ -1,36 +1,50 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#import <stdio.h>
#import <string.h>
#import <errno.h>
#import "Website.h" #import "Website.h"
#import "AppDelegate.h"
#define HISTORY_PATH @".cache/NetSurf" #define HISTORY_PATH @"/.cache/NetSurf"
static NSMutableArray *history; static NSMutableArray *recentHistory;
static NSMutableArray *olderHistory;
@implementation Website @implementation Website
-(id)initWithName: (NSString*)aName url: (NSURL*)aUrl { -(id)initWithName: (NSString*)aName url: (NSString*)aUrl {
if (self = [super init]) { if (self = [super init]) {
[aName retain]; int nlen = [aName length];
[aUrl retain]; int urlen = [aUrl length];
name = aName; data = malloc(sizeof (struct website_data) + nlen + urlen);
url = aUrl; data->len_name = nlen;
lastVisited = nil; data->len_url = urlen;
memcpy(data->data, [aName cString], nlen);
memcpy(data->data + nlen, [aUrl cString], urlen);
}
return self;
}
-(id)initWithData: (struct website_data*)someData {
if (self = [super init]) {
data = someData;
} }
return self; return self;
} }
-(void)dealloc { -(void)dealloc {
[name release]; free(data);
[url release];
[lastVisited release];
[super dealloc]; [super dealloc];
} }
-(NSString*)name { -(NSString*)name {
return name; return [NSString stringWithCString: data->data length: data->len_name];
} }
-(NSURL*)url { -(NSString*)url {
return url; return [NSString stringWithCString: data->data + data->len_name length:
data->len_url];
} }
-(void)open { -(void)open {
@ -39,90 +53,26 @@ static NSMutableArray *history;
// MARK: - History implementation // MARK: - History implementation
+(id)websiteWithDictionary: (NSDictionary*)dictionary {
Website *ret = [[[Website alloc] init] autorelease];
if (ret != nil) {
ret->name = [dictionary objectForKey: @"name"];
[ret->name retain];
ret->url = [NSURL URLWithString: [dictionary objectForKey: @"url"]];
[ret->url retain];
ret->lastVisited = [NSDate dateWithTimeIntervalSince1970: [[dictionary
objectForKey: @"date"] doubleValue]];
[ret->lastVisited retain];
}
return ret;
}
-(NSDictionary*)toDictionary {
return [NSDictionary dictionaryWithObjectsAndKeys: name, @"name",
[url absoluteString], @"url",
[NSNumber numberWithDouble: [lastVisited timeIntervalSince1970]], @"date",
nil];
}
+(void)saveHistoryToDisk {
NSLog(@"Save history to disk");
if (history == nil) {
return;
}
NSError *error = nil;
NSDictionary *attrs = [NSDictionary dictionary];
BOOL ok = [[NSFileManager defaultManager] createDirectoryAtPath: [NSString
pathWithComponents: [NSArray arrayWithObjects: NSHomeDirectory(),
HISTORY_PATH, nil]] withIntermediateDirectories: YES attributes: attrs
error: &error];
if (!ok) {
NSLog(@"Error creating cache dir!");
}
NSMutableArray *toSave = [NSMutableArray array];
for (NSUInteger i = 0; i < [history count]; i++) {
[toSave addObject: [[history objectAtIndex: i] toDictionary]];
}
ok = [toSave writeToFile: [NSString pathWithComponents: [NSArray
arrayWithObjects: NSHomeDirectory(), HISTORY_PATH, @"history", nil]]
atomically: YES];
if (!ok) {
NSLog(@"Failed to save latest history to file");
}
}
+(void)initHistoryIfNeeded {
if (history == nil) {
NSArray *historyDicts = [NSMutableArray arrayWithContentsOfFile:
[NSString pathWithComponents: [NSArray arrayWithObjects:
NSHomeDirectory(), HISTORY_PATH, @"history", nil]]];
history = [[NSMutableArray alloc] init];
for (NSUInteger i = 0; i < [historyDicts count]; i++) {
[history addObject: [Website websiteWithDictionary: [historyDicts
objectAtIndex: i]]];
}
[[NSNotificationCenter defaultCenter] addObserver: [self class]
selector: @selector(saveHistoryToDisk)
name: NSApplicationWillTerminateNotification
object: nil];
}
}
-(void)removeFromHistory {
NSLog(@"remove self from history");
[history removeObject: self];
[[NSNotificationCenter defaultCenter] postNotificationName:
WebsiteHistoryUpdatedNotificationName object: nil];
}
-(void)addToHistory { -(void)addToHistory {
[Website initHistoryIfNeeded]; static NSString *path = nil;
[lastVisited release]; if (path == nil) {
lastVisited = [[NSDate alloc] init]; NSCalendarDate *date = [NSCalendarDate calendarDate];
[history insertObject: self atIndex: 0]; int month = [date monthOfYear];
NSLog(@"Added %@ , %@ to history!", [self name], [self url]); int year = [date yearOfCommonEra];
path = [[NSString alloc] initWithFormat: @"%@/%@/history_%d_%d",
NSHomeDirectory(), HISTORY_PATH, year, month];
}
NSLog(@"name: %@", [self name]);
NSLog(@"url: %@", [self url]);
FILE *f = fopen([path cString], "a");
if (f != NULL) {
int len = sizeof (struct website_data) + data->len_url + data->len_name;
fwrite(data, len, 1, f);
fclose(f);
}
[[NSNotificationCenter defaultCenter] postNotificationName: [[NSNotificationCenter defaultCenter] postNotificationName:
WebsiteHistoryUpdatedNotificationName object: self]; WebsiteHistoryUpdatedNotificationName object: self];
} }
+(NSArray*)historicWebsites {
[Website initHistoryIfNeeded];
return history;
}
@end @end