зеркало из https://github.com/mozilla/gecko-dev.git
history now listed as a flat list by day, ordered by visit time (bug 227618)
This commit is contained in:
Родитель
129535cc9c
Коммит
76a6e01068
|
@ -760,6 +760,8 @@
|
|||
3FB2BAB30545EA80002B9691,
|
||||
3FB2BAB50545EA80002B9691,
|
||||
3FC0FB8105A0D2DC002F47DE,
|
||||
3F7C6CBD05B4819E002FFFD3,
|
||||
3F7C6CBF05B4819E002FFFD3,
|
||||
);
|
||||
isa = PBXHeadersBuildPhase;
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -934,6 +936,8 @@
|
|||
3FB2BAB40545EA80002B9691,
|
||||
3FB2BAB60545EA80002B9691,
|
||||
3FC0FB8205A0D2DC002F47DE,
|
||||
3F7C6CBE05B4819E002FFFD3,
|
||||
3F7C6CC005B4819E002FFFD3,
|
||||
);
|
||||
isa = PBXSourcesBuildPhase;
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -1375,6 +1379,82 @@
|
|||
settings = {
|
||||
};
|
||||
};
|
||||
3F7C6CB905B4819E002FFFD3 = {
|
||||
fileEncoding = 30;
|
||||
isa = PBXFileReference;
|
||||
name = HistoryItem.h;
|
||||
path = src/history/HistoryItem.h;
|
||||
refType = 2;
|
||||
};
|
||||
3F7C6CBA05B4819E002FFFD3 = {
|
||||
fileEncoding = 30;
|
||||
isa = PBXFileReference;
|
||||
name = HistoryItem.mm;
|
||||
path = src/history/HistoryItem.mm;
|
||||
refType = 2;
|
||||
};
|
||||
3F7C6CBB05B4819E002FFFD3 = {
|
||||
fileEncoding = 30;
|
||||
isa = PBXFileReference;
|
||||
name = RDFItem.h;
|
||||
path = src/history/RDFItem.h;
|
||||
refType = 2;
|
||||
};
|
||||
3F7C6CBC05B4819E002FFFD3 = {
|
||||
fileEncoding = 30;
|
||||
isa = PBXFileReference;
|
||||
name = RDFItem.mm;
|
||||
path = src/history/RDFItem.mm;
|
||||
refType = 2;
|
||||
};
|
||||
3F7C6CBD05B4819E002FFFD3 = {
|
||||
fileRef = 3F7C6CB905B4819E002FFFD3;
|
||||
isa = PBXBuildFile;
|
||||
settings = {
|
||||
};
|
||||
};
|
||||
3F7C6CBE05B4819E002FFFD3 = {
|
||||
fileRef = 3F7C6CBA05B4819E002FFFD3;
|
||||
isa = PBXBuildFile;
|
||||
settings = {
|
||||
};
|
||||
};
|
||||
3F7C6CBF05B4819E002FFFD3 = {
|
||||
fileRef = 3F7C6CBB05B4819E002FFFD3;
|
||||
isa = PBXBuildFile;
|
||||
settings = {
|
||||
};
|
||||
};
|
||||
3F7C6CC005B4819E002FFFD3 = {
|
||||
fileRef = 3F7C6CBC05B4819E002FFFD3;
|
||||
isa = PBXBuildFile;
|
||||
settings = {
|
||||
};
|
||||
};
|
||||
3F7C6CC105B4819E002FFFD3 = {
|
||||
fileRef = 3F7C6CB905B4819E002FFFD3;
|
||||
isa = PBXBuildFile;
|
||||
settings = {
|
||||
};
|
||||
};
|
||||
3F7C6CC205B4819E002FFFD3 = {
|
||||
fileRef = 3F7C6CBA05B4819E002FFFD3;
|
||||
isa = PBXBuildFile;
|
||||
settings = {
|
||||
};
|
||||
};
|
||||
3F7C6CC305B4819E002FFFD3 = {
|
||||
fileRef = 3F7C6CBB05B4819E002FFFD3;
|
||||
isa = PBXBuildFile;
|
||||
settings = {
|
||||
};
|
||||
};
|
||||
3F7C6CC405B4819E002FFFD3 = {
|
||||
fileRef = 3F7C6CBC05B4819E002FFFD3;
|
||||
isa = PBXBuildFile;
|
||||
settings = {
|
||||
};
|
||||
};
|
||||
3F8D26DE0471ED0F00A80005 = {
|
||||
fileRef = 3FAD95540461E43700A80005;
|
||||
isa = PBXBuildFile;
|
||||
|
@ -7444,6 +7524,10 @@
|
|||
children = (
|
||||
F52F87CD027D75C301A80165,
|
||||
F52F87CE027D75C301A80165,
|
||||
3F7C6CB905B4819E002FFFD3,
|
||||
3F7C6CBA05B4819E002FFFD3,
|
||||
3F7C6CBB05B4819E002FFFD3,
|
||||
3F7C6CBC05B4819E002FFFD3,
|
||||
);
|
||||
isa = PBXGroup;
|
||||
name = History;
|
||||
|
@ -8447,6 +8531,8 @@
|
|||
3FB2BAD00545EA80002B9691,
|
||||
3FB2BAD20545EA80002B9691,
|
||||
3FC7E24905A228E900C557AA,
|
||||
3F7C6CC105B4819E002FFFD3,
|
||||
3F7C6CC305B4819E002FFFD3,
|
||||
);
|
||||
isa = PBXHeadersBuildPhase;
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -8622,6 +8708,8 @@
|
|||
3FB2BAD10545EA80002B9691,
|
||||
3FB2BAD30545EA80002B9691,
|
||||
3FC7E24805A228E900C557AA,
|
||||
3F7C6CC205B4819E002FFFD3,
|
||||
3F7C6CC405B4819E002FFFD3,
|
||||
);
|
||||
isa = PBXSourcesBuildPhase;
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
|
@ -716,7 +716,7 @@ const long kMinSearchPaneHeight = 80;
|
|||
if ( inRowIndex == kHistoryContainerIndex ) {
|
||||
[mItemPane setDataSource:mHistorySource];
|
||||
[mItemPane setDelegate:mHistorySource];
|
||||
[mHistorySource ensureDataSourceLoaded];
|
||||
[mHistorySource loadLazily];
|
||||
[self setCanEditSelectedContainerContents:NO];
|
||||
[mItemPane setTarget:mHistorySource];
|
||||
[mItemPane setDoubleAction: @selector(openHistoryItem:)];
|
||||
|
|
|
@ -629,7 +629,7 @@ static NSArray* sToolbarDefaults = nil;
|
|||
[mBookmarkViewController ensureBookmarks];
|
||||
|
||||
if ([[[mSidebarTabView selectedTabViewItem] identifier] isEqual:@"historySidebarCHIconTabViewItem"]) {
|
||||
[mHistoryDataSource ensureDataSourceLoaded];
|
||||
[mHistoryDataSource loadLazily];
|
||||
[mHistoryDataSource enableObserver];
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Ben Goodger <ben@netscape.com> (Original Author)
|
||||
* Simon Woodside <sbwoodside@yahoo.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -41,73 +42,37 @@
|
|||
class nsIRDFDataSource;
|
||||
class nsIRDFContainer;
|
||||
class nsIRDFContainerUtils;
|
||||
class nsIRDFResource;
|
||||
class nsIRDFService;
|
||||
|
||||
@class ExtendedOutlineView;
|
||||
|
||||
|
||||
// RDF Resource Wrapper to make the Outline View happy
|
||||
@interface RDFOutlineViewItem : NSObject
|
||||
{
|
||||
nsIRDFResource* mResource;
|
||||
unsigned int mCacheVersion; // if matches the cache version in the data source,
|
||||
// cached values are valid
|
||||
BOOL mExpandable;
|
||||
int mNumChildren;
|
||||
NSArray* mChildNodes; // array of |RDFOutlineViewItem|'s
|
||||
}
|
||||
|
||||
- (nsIRDFResource*)resource; // addRefs the result
|
||||
- (void)setResource:(nsIRDFResource*) aResource;
|
||||
|
||||
@end
|
||||
|
||||
@class RDFItem;
|
||||
|
||||
@interface RDFOutlineViewDataSource : NSObject
|
||||
{
|
||||
nsIRDFDataSource* mDataSource;
|
||||
nsIRDFContainer* mContainer;
|
||||
nsIRDFContainerUtils* mContainerUtils;
|
||||
nsIRDFResource* mRootResource;
|
||||
nsIRDFService* mRDFService;
|
||||
RDFItem * mRootRDFItem;
|
||||
IBOutlet ExtendedOutlineView* mOutlineView;
|
||||
|
||||
IBOutlet ExtendedOutlineView* mOutlineView;
|
||||
|
||||
NSMutableDictionary* mDictionary;
|
||||
unsigned int mCacheVersion;
|
||||
nsIRDFDataSource* mRDFDataSource;
|
||||
nsIRDFContainer* mRDFContainer;
|
||||
nsIRDFContainerUtils* mRDFContainerUtils;
|
||||
nsIRDFService* mRDFService;
|
||||
}
|
||||
|
||||
- (RDFItem *)rootRDFItem;
|
||||
- (void)setRootRDFItem:(RDFItem*)item;
|
||||
|
||||
// Initialization Methods
|
||||
- (void) ensureDataSourceLoaded;
|
||||
- (void) loadLazily;
|
||||
- (void) cleanupDataSource;
|
||||
|
||||
- (nsIRDFDataSource*) dataSource;
|
||||
- (nsIRDFResource*) rootResource;
|
||||
- (void) setDataSource: (nsIRDFDataSource*) aDataSource;
|
||||
- (void) setRootResource: (nsIRDFResource*) aResource;
|
||||
- (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren;
|
||||
- (void)invalidateCachedItems;
|
||||
|
||||
// Outline View Data Source methods
|
||||
// Outline View Data Source methods
|
||||
- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item;
|
||||
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item;
|
||||
- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item;
|
||||
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
|
||||
|
||||
// tooltip support from the ExtendedOutlineView. Override to provide a tooltip
|
||||
// other than the Name property for each item in the view.
|
||||
- (NSString *)outlineView:(NSOutlineView *)outlineView tooltipStringForItem:(id)inItem;
|
||||
|
||||
- (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren;
|
||||
|
||||
// Implementation Methods
|
||||
- (id)getWrapperFor:(nsIRDFResource*) aRDFResource;
|
||||
- (void)invalidateCachedItems;
|
||||
|
||||
// override to do something different with the cell data rather than just
|
||||
// return a string (add an icon in an attributed string, for example).
|
||||
- (id)createCellContents:(NSString*)inValue withColumn:(NSString*)inColumn byItem:(id)inItem;
|
||||
|
||||
- (NSString*)getPropertyString:(NSString*)inPropertyURI forItem:(RDFOutlineViewItem*)inItem;
|
||||
- (NSString *)outlineView:(NSOutlineView *)outlineView tooltipStringForItem:(id)anItem;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Ben Goodger <ben@netscape.com> (Original Author)
|
||||
* Simon Woodside <sbwoodside@yahoo.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -41,6 +42,7 @@
|
|||
#import "RDFOutlineViewDataSource.h"
|
||||
#import "CHBrowserService.h"
|
||||
#import "ExtendedOutlineView.h"
|
||||
#import "RDFItem.h"
|
||||
|
||||
#include "nsCRT.h"
|
||||
#include "nsIRDFDataSource.h"
|
||||
|
@ -58,123 +60,20 @@
|
|||
#include "nsString.h"
|
||||
|
||||
|
||||
@interface RDFOutlineViewItem(Private)
|
||||
|
||||
- (unsigned int)cacheVersion;
|
||||
- (void)setNumChildren:(int)numChildren isExpandable:(BOOL)expandable cacheVersion:(unsigned int)version;
|
||||
- (void)setChildren:(NSArray*)childArray;
|
||||
- (BOOL)cacheValid:(unsigned int)version needChildren:(BOOL)needChildren;
|
||||
- (BOOL)cachedChildren;
|
||||
|
||||
- (BOOL)isExpandable;
|
||||
- (int)numChildren;
|
||||
- (id)childAtIndex:(int)index;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation RDFOutlineViewItem
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
mCacheVersion = 0;
|
||||
mExpandable = NO;
|
||||
mNumChildren = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[mChildNodes release];
|
||||
NS_IF_RELEASE(mResource);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (nsIRDFResource*)resource
|
||||
{
|
||||
NS_IF_ADDREF(mResource);
|
||||
return mResource;
|
||||
}
|
||||
|
||||
- (void)setResource:(nsIRDFResource*) aResource
|
||||
{
|
||||
nsIRDFResource* oldResource = mResource;
|
||||
NS_IF_ADDREF(mResource = aResource);
|
||||
NS_IF_RELEASE(oldResource);
|
||||
}
|
||||
|
||||
- (unsigned int)cacheVersion
|
||||
{
|
||||
return mCacheVersion;
|
||||
}
|
||||
|
||||
- (void)setNumChildren:(int)numChildren isExpandable:(BOOL)expandable cacheVersion:(unsigned int)version;
|
||||
{
|
||||
mNumChildren = numChildren;
|
||||
mExpandable = expandable;
|
||||
mCacheVersion = version;
|
||||
}
|
||||
|
||||
- (void)setChildren:(NSArray*)childArray
|
||||
{
|
||||
// childArray can legally be nil here. If it is, we're clearing the cached children
|
||||
NSArray* oldChildren = mChildNodes;
|
||||
mChildNodes = childArray;
|
||||
[mChildNodes retain];
|
||||
[oldChildren release];
|
||||
}
|
||||
|
||||
- (BOOL)cacheValid:(unsigned int)version needChildren:(BOOL)needChildren;
|
||||
{
|
||||
return (mCacheVersion == version) && (needChildren ? (mChildNodes != nil) : 1);
|
||||
}
|
||||
|
||||
- (BOOL)cachedChildren
|
||||
{
|
||||
return (mChildNodes != nil);
|
||||
}
|
||||
|
||||
- (BOOL)isExpandable
|
||||
{
|
||||
return mExpandable;
|
||||
}
|
||||
|
||||
- (int)numChildren
|
||||
{
|
||||
return mNumChildren;
|
||||
}
|
||||
|
||||
- (id)childAtIndex:(int)index
|
||||
{
|
||||
if (mChildNodes)
|
||||
return [mChildNodes objectAtIndex:index];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@interface RDFOutlineViewDataSource(Private)
|
||||
- (void)cleanup;
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface RDFOutlineViewDataSource(Private)
|
||||
|
||||
- (void)registerForShutdownNotification;
|
||||
- (void)cleanup;
|
||||
- (void)updateItemProperties:(id)item enumerateChildren:(BOOL)doChildren;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RDFOutlineViewDataSource
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
[self registerForShutdownNotification];
|
||||
mCacheVersion = 1;
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(shutdown:)
|
||||
name:XPCOMShutDownNotificationName object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
@ -189,15 +88,11 @@
|
|||
|
||||
- (void)cleanup
|
||||
{
|
||||
NS_IF_RELEASE(mContainer);
|
||||
NS_IF_RELEASE(mContainerUtils);
|
||||
NS_IF_RELEASE(mRDFContainer);
|
||||
NS_IF_RELEASE(mRDFContainerUtils);
|
||||
NS_IF_RELEASE(mRDFService);
|
||||
|
||||
NS_IF_RELEASE(mDataSource);
|
||||
NS_IF_RELEASE(mRootResource);
|
||||
|
||||
[mDictionary release];
|
||||
mDictionary = nil;
|
||||
NS_IF_RELEASE(mRDFDataSource);
|
||||
}
|
||||
|
||||
- (void)cleanupDataSource
|
||||
|
@ -205,270 +100,142 @@
|
|||
[self cleanup];
|
||||
}
|
||||
|
||||
- (RDFItem *)rootRDFItem;
|
||||
{
|
||||
return mRootRDFItem;
|
||||
}
|
||||
|
||||
- (void)setRootRDFItem:(RDFItem*)item;
|
||||
{
|
||||
[mRootRDFItem autorelease];
|
||||
mRootRDFItem = [item retain];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// ensureDataSourceLoaded
|
||||
// loadLazily
|
||||
//
|
||||
// defer loading all this rdf junk until it's requested because it's slow
|
||||
// TODO measure how slow it really is
|
||||
//
|
||||
- (void) ensureDataSourceLoaded
|
||||
- (void) loadLazily
|
||||
{
|
||||
if ( !mContainer ) {
|
||||
if ( !mRDFContainer ) {
|
||||
nsCOMPtr<nsIRDFContainer> ctr = do_CreateInstance("@mozilla.org/rdf/container;1");
|
||||
NS_ADDREF(mContainer = ctr);
|
||||
NS_ADDREF(mRDFContainer = ctr);
|
||||
|
||||
nsCOMPtr<nsIRDFContainerUtils> ctrUtils = do_GetService("@mozilla.org/rdf/container-utils;1");
|
||||
NS_ADDREF(mContainerUtils = ctrUtils);
|
||||
NS_ADDREF(mRDFContainerUtils = ctrUtils);
|
||||
|
||||
nsCOMPtr<nsIRDFService> rdfService = do_GetService("@mozilla.org/rdf/rdf-service;1");
|
||||
NS_ADDREF(mRDFService = rdfService);
|
||||
|
||||
mDictionary = [[NSMutableDictionary alloc] initWithCapacity: 30];
|
||||
|
||||
mDataSource = nsnull;
|
||||
mRootResource = nsnull;
|
||||
mRDFDataSource = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)registerForShutdownNotification
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver: self
|
||||
selector: @selector(shutdown:)
|
||||
name: XPCOMShutDownNotificationName
|
||||
object: nil];
|
||||
}
|
||||
|
||||
- (void)shutdown: (NSNotification*)aNotification
|
||||
- (void)shutdown:(NSNotification*)aNotification
|
||||
{
|
||||
[self cleanupDataSource];
|
||||
}
|
||||
|
||||
- (nsIRDFDataSource*) dataSource
|
||||
{
|
||||
NS_IF_ADDREF(mDataSource);
|
||||
return mDataSource;
|
||||
}
|
||||
|
||||
- (nsIRDFResource*) rootResource
|
||||
{
|
||||
NS_IF_ADDREF(mRootResource);
|
||||
return mRootResource;
|
||||
}
|
||||
#pragma mark -
|
||||
|
||||
- (void) setDataSource: (nsIRDFDataSource*) aDataSource
|
||||
{
|
||||
nsIRDFDataSource* oldDataSource = mDataSource;
|
||||
NS_IF_ADDREF(mDataSource = aDataSource);
|
||||
NS_IF_RELEASE(oldDataSource);
|
||||
}
|
||||
// Implementation of NSOutlineViewDataSource protocol
|
||||
|
||||
- (void) setRootResource: (nsIRDFResource*) aResource
|
||||
{
|
||||
nsIRDFResource* oldResource = mRootResource;
|
||||
NS_IF_ADDREF(mRootResource = aResource);
|
||||
NS_IF_RELEASE(oldResource);
|
||||
}
|
||||
|
||||
//
|
||||
// XXX - For now, we'll just say that none of our items are editable, as we aren't using any
|
||||
// RDF datasources that are mutable.
|
||||
//
|
||||
- (BOOL) outlineView: (NSOutlineView*)aOutlineView shouldEditTableColumn: (NSTableColumn*) aTableColumn
|
||||
item: (id) aItem
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView*)aOutlineView shouldEditTableColumn:(NSTableColumn*)aTableColumn item:(id)aItem
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL) outlineView: (NSOutlineView*)aOutlineView isItemExpandable:(id)aItem
|
||||
- (BOOL)outlineView:(NSOutlineView*)aOutlineView isItemExpandable:(id)aItem
|
||||
{
|
||||
if (!mDataSource)
|
||||
if (!mRDFDataSource)
|
||||
return NO;
|
||||
|
||||
if (!aItem)
|
||||
return YES; // The root is always open
|
||||
|
||||
if (![aItem cacheValid:mCacheVersion needChildren:NO])
|
||||
[self updateItemProperties:aItem enumerateChildren:NO];
|
||||
|
||||
return [aItem isExpandable];
|
||||
if( [aItem isKindOfClass:[RDFItem class]] ) {
|
||||
RDFItem * rdfItem = aItem;
|
||||
return [rdfItem isExpandable];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (id)outlineView:(NSOutlineView*)aOutlineView child:(int)aIndex ofItem:(id)aItem
|
||||
{
|
||||
if (!mDataSource)
|
||||
if (!mRDFDataSource)
|
||||
return nil;
|
||||
|
||||
if (!aItem)
|
||||
{
|
||||
nsCOMPtr<nsIRDFResource> rootResource = dont_AddRef([self rootResource]);
|
||||
aItem = [self getWrapperFor:rootResource];
|
||||
if (!aItem) {
|
||||
aItem = [self rootRDFItem];
|
||||
}
|
||||
|
||||
if (![aItem cacheValid:mCacheVersion needChildren:YES])
|
||||
[self updateItemProperties:aItem enumerateChildren:YES];
|
||||
|
||||
return [aItem childAtIndex:aIndex];
|
||||
if( [aItem isKindOfClass:[RDFItem class]] ) {
|
||||
RDFItem * rdfItem = aItem;
|
||||
return [rdfItem childAtIndex:aIndex];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (int)outlineView:(NSOutlineView*)aOutlineView numberOfChildrenOfItem:(id) aItem;
|
||||
- (int)outlineView:(NSOutlineView*)aOutlineView numberOfChildrenOfItem:(id)aItem;
|
||||
{
|
||||
if (!mDataSource)
|
||||
if (!mRDFDataSource)
|
||||
return 0;
|
||||
|
||||
if (!aItem)
|
||||
{
|
||||
nsCOMPtr<nsIRDFResource> rootResource = dont_AddRef([self rootResource]);
|
||||
aItem = [self getWrapperFor:rootResource];
|
||||
if (!aItem) {
|
||||
aItem = [self rootRDFItem];
|
||||
}
|
||||
|
||||
if (![aItem cacheValid:mCacheVersion needChildren:YES])
|
||||
[self updateItemProperties:aItem enumerateChildren:YES];
|
||||
|
||||
return [aItem numChildren];
|
||||
if( [aItem isKindOfClass:[RDFItem class]] ) {
|
||||
RDFItem * rdfItem = aItem;
|
||||
return [rdfItem numChildren];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (id)outlineView:(NSOutlineView*)aOutlineView objectValueForTableColumn:(NSTableColumn*)aTableColumn
|
||||
byItem:(id)aItem
|
||||
// TODO move to subclass
|
||||
- (id)outlineView:(NSOutlineView*)aOutlineView objectValueForTableColumn:(NSTableColumn*)aTableColumn byItem:(id)aItem
|
||||
{
|
||||
if (!mDataSource || !aItem)
|
||||
if (!mRDFDataSource || !aItem)
|
||||
return nil;
|
||||
|
||||
// The table column's identifier is the last part of the RDF Resource URI of the property
|
||||
// being displayed in that column, e.g. "http://home.netscape.com/NC-rdf#Name"
|
||||
// little hack inserted until history moves to new bookmark format
|
||||
NSString *identifier = [aTableColumn identifier];
|
||||
if ([identifier isEqualToString:@"title"])
|
||||
identifier = [NSString stringWithString:@"Name"];
|
||||
NSString* columnPropertyURI = [NSString stringWithFormat:@"http://home.netscape.com/NC-rdf#%@",
|
||||
identifier];
|
||||
NSString* propString = [self getPropertyString:columnPropertyURI forItem:aItem];
|
||||
|
||||
return [self createCellContents:propString withColumn:columnPropertyURI byItem:aItem];
|
||||
NSString *resourceName;
|
||||
if( [[aTableColumn identifier] isEqualToString:@"title"] )
|
||||
resourceName = @"Name";
|
||||
else if( [[aTableColumn identifier] isEqualToString:@"url"] )
|
||||
resourceName = @"URL";
|
||||
else
|
||||
return nil;
|
||||
NSString * RDFURI = @"http://home.netscape.com/NC-rdf#";
|
||||
NSString * RDFpropertyURI = [RDFURI stringByAppendingString:resourceName];
|
||||
NSString * propertyString = [aItem getStringForRDFPropertyURI:RDFpropertyURI];
|
||||
return propertyString;
|
||||
}
|
||||
|
||||
//
|
||||
// createCellContents:withColumn:byItem
|
||||
//
|
||||
// Constructs a NSString from the given string data for this item in the given column.
|
||||
// This should be overridden to do more fancy things, such as add an icon, etc.
|
||||
//
|
||||
- (id)createCellContents:(NSString*)inValue withColumn:(NSString*)inColumn byItem:(id)inItem
|
||||
{
|
||||
return inValue;
|
||||
}
|
||||
|
||||
//
|
||||
// outlineView:tooltipForString
|
||||
//
|
||||
// returns the value of the Name property as the tooltip for the given item. Override to do
|
||||
// returns the value of the Name property as the tooltip for the given item. Override to do
|
||||
// anything more complicated
|
||||
//
|
||||
- (NSString *)outlineView:(NSOutlineView *)outlineView tooltipStringForItem:(id)inItem
|
||||
- (NSString *)outlineView:(NSOutlineView *)outlineView tooltipStringForItem:(id)anItem
|
||||
{
|
||||
return [self getPropertyString:@"http://home.netscape.com/NC-rdf#Name" forItem:inItem];
|
||||
return [anItem getStringForRDFPropertyURI:@"http://home.netscape.com/NC-rdf#Name"];
|
||||
}
|
||||
|
||||
- (void) reloadDataForItem: (id) aItem reloadChildren: (BOOL) aReloadChildren
|
||||
|
||||
|
||||
#pragma mark -
|
||||
|
||||
|
||||
- (void)reloadDataForItem:(id)aItem reloadChildren:(BOOL)aReloadChildren
|
||||
{
|
||||
if (!aItem)
|
||||
[mOutlineView reloadData];
|
||||
else
|
||||
[mOutlineView reloadItem: aItem reloadChildren: aReloadChildren];
|
||||
}
|
||||
|
||||
- (id)getWrapperFor:(nsIRDFResource*) aRDFResource
|
||||
{
|
||||
const char* k;
|
||||
aRDFResource->GetValueConst(&k);
|
||||
NSString* key = [NSString stringWithCString:k];
|
||||
|
||||
// see if we've created a wrapper already, if not, create a new wrapper object
|
||||
// and stash it in our dictionary
|
||||
RDFOutlineViewItem* item = [mDictionary objectForKey:key];
|
||||
if (!item)
|
||||
{
|
||||
item = [[[RDFOutlineViewItem alloc] init] autorelease];
|
||||
[item setResource: aRDFResource];
|
||||
[mDictionary setObject:item forKey:key]; // retains |item|
|
||||
}
|
||||
|
||||
return item;
|
||||
[mOutlineView reloadItem:aItem reloadChildren:aReloadChildren];
|
||||
}
|
||||
|
||||
- (void)invalidateCachedItems
|
||||
{
|
||||
mCacheVersion++;
|
||||
[[self rootRDFItem] invalidateCache];
|
||||
}
|
||||
|
||||
- (void)updateItemProperties:(id)item enumerateChildren:(BOOL)doChildren
|
||||
{
|
||||
BOOL isExpandable = NO;
|
||||
NSMutableArray* itemChildren = doChildren ? [[[NSMutableArray alloc] initWithCapacity:10] autorelease] : nil;
|
||||
|
||||
nsCOMPtr<nsIRDFResource> itemResource = dont_AddRef([item resource]);
|
||||
|
||||
PRBool isSeq = PR_FALSE;
|
||||
mContainerUtils->IsSeq(mDataSource, itemResource, &isSeq);
|
||||
if (isSeq)
|
||||
isExpandable = YES;
|
||||
|
||||
nsCOMPtr<nsIRDFResource> childProperty;
|
||||
mRDFService->GetResource(nsDependentCString("http://home.netscape.com/NC-rdf#child"), getter_AddRefs(childProperty));
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> childNodes;
|
||||
mDataSource->GetTargets(itemResource, childProperty, PR_TRUE, getter_AddRefs(childNodes));
|
||||
|
||||
PRBool hasMore = PR_FALSE;
|
||||
while (NS_SUCCEEDED(childNodes->HasMoreElements(&hasMore)) && hasMore)
|
||||
{
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
childNodes->GetNext(getter_AddRefs(supp));
|
||||
|
||||
nsCOMPtr<nsIRDFResource> childResource = do_QueryInterface(supp);
|
||||
if (childResource)
|
||||
{
|
||||
id childItem = [self getWrapperFor:childResource];
|
||||
if (childItem)
|
||||
{
|
||||
isExpandable = YES;
|
||||
if (!itemChildren) break; // know enough already
|
||||
[itemChildren addObject:childItem];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// itemChildren will be nil here if we don't care about children, but that's OK.
|
||||
// the setChildren call will clear the cached child list.
|
||||
[item setNumChildren:[itemChildren count] isExpandable:isExpandable cacheVersion:mCacheVersion];
|
||||
[item setChildren:itemChildren];
|
||||
}
|
||||
|
||||
- (NSString*)getPropertyString:(NSString*)inPropertyURI forItem:(RDFOutlineViewItem*)inItem
|
||||
{
|
||||
nsCOMPtr<nsIRDFResource> propertyResource;
|
||||
mRDFService->GetResource(nsDependentCString([inPropertyURI UTF8String]), getter_AddRefs(propertyResource));
|
||||
|
||||
nsCOMPtr<nsIRDFResource> resource = dont_AddRef([inItem resource]);
|
||||
|
||||
nsCOMPtr<nsIRDFNode> valueNode;
|
||||
mDataSource->GetTarget(resource, propertyResource, PR_TRUE, getter_AddRefs(valueNode));
|
||||
if (!valueNode) {
|
||||
#if DEBUG
|
||||
NSLog(@"ValueNode is null in RDF objectValueForTableColumn");
|
||||
#endif
|
||||
return @"";
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRDFLiteral> valueLiteral(do_QueryInterface(valueNode));
|
||||
if (!valueLiteral)
|
||||
return @"";
|
||||
|
||||
const PRUnichar* value = NULL;
|
||||
valueLiteral->GetValueConst(&value);
|
||||
if (value)
|
||||
return [NSString stringWithCharacters:value length:nsCRT::strlen(value)];
|
||||
|
||||
return @"";
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Ben Goodger <ben@netscape.com> (Original Author)
|
||||
* Simon Woodside <sbwoodside@yahoo.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -39,23 +40,24 @@
|
|||
#import "RDFOutlineViewDataSource.h"
|
||||
|
||||
class nsAString;
|
||||
class HistoryDataSourceObserver;
|
||||
class HistoryRDFObserver;
|
||||
|
||||
@class BrowserWindowController;
|
||||
@class HistoryItem;
|
||||
|
||||
@interface HistoryDataSource : RDFOutlineViewDataSource
|
||||
{
|
||||
HistoryDataSourceObserver* mObserver; // STRONG ref, should be nsCOMPtr but can't
|
||||
HistoryRDFObserver* mObserver; // STRONG ref, should be nsCOMPtr but can't
|
||||
IBOutlet BrowserWindowController* mBrowserWindowController;
|
||||
BOOL mUpdatesEnabled;
|
||||
BOOL mNeedsRefresh;
|
||||
BOOL mUpdatesEnabled;
|
||||
BOOL mNeedsRefresh;
|
||||
bool mLoaded;
|
||||
|
||||
HistoryItem * mRootHistoryItem;
|
||||
}
|
||||
|
||||
// overridden to create a attributed string with icon
|
||||
- (id)createCellContents:(NSString*)inValue withColumn:(NSString*)inColumn byItem:(id) inItem;
|
||||
|
||||
- (NSString *)outlineView:(NSOutlineView *)outlineView tooltipStringForItem:(id)inItem;
|
||||
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(NSCell *)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item;
|
||||
- (HistoryItem *)rootRDFItem;
|
||||
- (void)setRootRDFItem:(HistoryItem *)item;
|
||||
|
||||
- (void)enableObserver;
|
||||
- (void)disableObserver;
|
||||
|
@ -69,5 +71,11 @@ class HistoryDataSourceObserver;
|
|||
- (IBAction)openHistoryItemInNewWindow:(id)aSender;
|
||||
- (IBAction)openHistoryItemInNewTab:(id)aSender;
|
||||
|
||||
// NSOutlineViewDataSource protocol
|
||||
- (BOOL)outlineView:(NSOutlineView *)ov writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard;
|
||||
- (NSString *)outlineView:(NSOutlineView *)outlineView tooltipStringForItem:(id)anItem;
|
||||
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(NSCell *)inCell forTableColumn:(NSTableColumn *)tableColumn item:(id)item;
|
||||
- (NSMenu *)outlineView:(NSOutlineView *)outlineView contextMenuForItem:(id)item;
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Simon Woodside <sbwoodside@yahoo.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -43,6 +44,7 @@
|
|||
#import "CHBrowserView.h"
|
||||
#import "ExtendedOutlineView.h"
|
||||
#import "PreferenceManager.h"
|
||||
#import "HistoryItem.h"
|
||||
|
||||
#include "nsIRDFService.h"
|
||||
#include "nsIRDFDataSource.h"
|
||||
|
@ -56,21 +58,19 @@
|
|||
#include "nsComponentManagerUtils.h"
|
||||
|
||||
//
|
||||
// class HistoryDataSourceObserver
|
||||
//
|
||||
// An observer, enabled whenver the history panel in the drawer is selected. Tracks
|
||||
// changes to the RDF data source and pokes the history outline view
|
||||
// Uses the Gecko RDF data source for history,
|
||||
// and presents a Cocoa API through the NSOutlineViewDataSource protocol
|
||||
//
|
||||
|
||||
class HistoryDataSourceObserver : public nsIRDFObserver
|
||||
class HistoryRDFObserver : public nsIRDFObserver
|
||||
{
|
||||
public:
|
||||
HistoryDataSourceObserver(HistoryDataSource* dataSource)
|
||||
HistoryRDFObserver(HistoryDataSource* dataSource)
|
||||
: mHistoryDataSource(dataSource)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
}
|
||||
virtual ~HistoryDataSourceObserver() { }
|
||||
virtual ~HistoryRDFObserver() { }
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
|
@ -90,7 +90,7 @@ private:
|
|||
HistoryDataSource* mHistoryDataSource;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(HistoryDataSourceObserver, nsIRDFObserver)
|
||||
NS_IMPL_ISUPPORTS1(HistoryRDFObserver, nsIRDFObserver)
|
||||
|
||||
|
||||
//
|
||||
|
@ -100,8 +100,8 @@ NS_IMPL_ISUPPORTS1(HistoryDataSourceObserver, nsIRDFObserver)
|
|||
// open.
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
HistoryDataSourceObserver::OnAssert(nsIRDFDataSource*, nsIRDFResource*,
|
||||
nsIRDFResource* aProperty, nsIRDFNode*)
|
||||
HistoryRDFObserver::OnAssert(nsIRDFDataSource*, nsIRDFResource*,
|
||||
nsIRDFResource* aProperty, nsIRDFNode*)
|
||||
{
|
||||
const char* p;
|
||||
aProperty->GetValueConst(&p);
|
||||
|
@ -117,8 +117,8 @@ HistoryDataSourceObserver::OnAssert(nsIRDFDataSource*, nsIRDFResource*,
|
|||
// This gets called on redirects, when nsGlobalHistory::RemovePage is called.
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
HistoryDataSourceObserver::OnUnassert(nsIRDFDataSource*, nsIRDFResource*,
|
||||
nsIRDFResource* aProperty, nsIRDFNode*)
|
||||
HistoryRDFObserver::OnUnassert(nsIRDFDataSource*, nsIRDFResource*,
|
||||
nsIRDFResource* aProperty, nsIRDFNode*)
|
||||
{
|
||||
const char* p;
|
||||
aProperty->GetValueConst(&p);
|
||||
|
@ -135,27 +135,33 @@ HistoryDataSourceObserver::OnUnassert(nsIRDFDataSource*, nsIRDFResource*,
|
|||
// visiting them and they change date
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*,
|
||||
HistoryRDFObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*,
|
||||
nsIRDFResource* aProperty, nsIRDFNode*, nsIRDFNode*)
|
||||
{
|
||||
const char* p;
|
||||
aProperty->GetValueConst(&p);
|
||||
|
||||
if (strcmp("http://home.netscape.com/NC-rdf#Date", p) == 0)
|
||||
[mHistoryDataSource setNeedsRefresh:YES];
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface HistoryDataSource(Private)
|
||||
|
||||
- (void)cleanupHistory;
|
||||
- (void)removeItemFromHistory:(id)inItem withService:(nsIBrowserHistory*)inHistService;
|
||||
- (void)cleanupDataSource;
|
||||
- (void)removeItemFromGeckoHistory:(id)anItem withService:(nsIBrowserHistory*)inHistService;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation HistoryDataSource
|
||||
|
||||
- (void) dealloc
|
||||
|
@ -167,49 +173,69 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*,
|
|||
// "non-virtual" cleanup method -- safe to call from dealloc.
|
||||
- (void)cleanupHistory
|
||||
{
|
||||
if (mDataSource && mObserver)
|
||||
{
|
||||
mDataSource->RemoveObserver(mObserver);
|
||||
if (mRDFDataSource && mObserver) {
|
||||
mRDFDataSource->RemoveObserver(mObserver);
|
||||
NS_RELEASE(mObserver); // nulls it
|
||||
}
|
||||
}
|
||||
|
||||
// "virtual" method; called from superclass
|
||||
- (void)cleanupDataSource
|
||||
- (void)cleanupDataSource;
|
||||
{
|
||||
[self cleanupHistory];
|
||||
[self cleanupHistory];
|
||||
[super cleanupDataSource];
|
||||
}
|
||||
|
||||
-(bool) loaded;
|
||||
{
|
||||
return mLoaded;
|
||||
}
|
||||
|
||||
- (HistoryItem *)rootRDFItem;
|
||||
{
|
||||
return mRootHistoryItem;
|
||||
}
|
||||
|
||||
- (void)setRootRDFItem:(HistoryItem *)item;
|
||||
{
|
||||
[mRootHistoryItem autorelease];
|
||||
mRootHistoryItem = [item retain];
|
||||
}
|
||||
|
||||
//
|
||||
// ensureDataSourceLoaded
|
||||
// loadLazily
|
||||
//
|
||||
// Called when the history panel is selected or brought into view. Inits all
|
||||
// the RDF-fu to make history go. We defer loading everything because it's
|
||||
// sorta slow and we don't want to take the hit when the user creates new windows
|
||||
// or just opens the bookmarks panel.
|
||||
//
|
||||
- (void) ensureDataSourceLoaded
|
||||
// in addition currently we don't get any gecko updates after we load so this
|
||||
// will make sure it's up-to-date
|
||||
//
|
||||
- (void) loadLazily;
|
||||
{
|
||||
[super ensureDataSourceLoaded];
|
||||
[super loadLazily];
|
||||
|
||||
NS_ASSERTION(mRDFService, "Uh oh, RDF service not loaded in parent class");
|
||||
|
||||
if ( !mDataSource )
|
||||
{
|
||||
if( !mRDFDataSource ) {
|
||||
// Get the Global History DataSource
|
||||
mRDFService->GetDataSource("rdf:history", &mDataSource);
|
||||
mRDFService->GetDataSource("rdf:history", &mRDFDataSource);
|
||||
// Get the Date Folder Root
|
||||
mRDFService->GetResource(nsDependentCString("NC:HistoryByDate"), &mRootResource);
|
||||
nsIRDFResource* aRDFRootResource;
|
||||
mRDFService->GetResource(nsDependentCString("NC:HistoryByDate"), &aRDFRootResource);
|
||||
HistoryItem * newRoot = [HistoryItem alloc];
|
||||
[newRoot initWithRDFResource:aRDFRootResource RDFDataSource:mRDFDataSource parent:nil];
|
||||
[self setRootRDFItem:newRoot];
|
||||
|
||||
|
||||
// identifiers: title url description keyword
|
||||
|
||||
[mOutlineView setTarget: self];
|
||||
[mOutlineView setDoubleAction: @selector(openHistoryItem:)];
|
||||
[mOutlineView setDeleteAction: @selector(deleteHistoryItems:)];
|
||||
|
||||
mObserver = new HistoryDataSourceObserver(self);
|
||||
mObserver = new HistoryRDFObserver(self);
|
||||
if ( mObserver ) {
|
||||
NS_ADDREF(mObserver);
|
||||
mDataSource->AddObserver(mObserver);
|
||||
mRDFDataSource->AddObserver(mObserver);
|
||||
}
|
||||
[mOutlineView reloadData];
|
||||
}
|
||||
|
@ -220,7 +246,7 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*,
|
|||
[mOutlineView reloadData];
|
||||
}
|
||||
|
||||
NS_ASSERTION(mDataSource, "Uh oh, History RDF Data source not created");
|
||||
NS_ASSERTION(mRDFDataSource, "Uh oh, History RDF Data source not created");
|
||||
}
|
||||
|
||||
- (void)enableObserver
|
||||
|
@ -250,82 +276,14 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*,
|
|||
[self invalidateCachedItems];
|
||||
if (mUpdatesEnabled)
|
||||
{
|
||||
// this can be very slow! See bug 180109.
|
||||
//NSLog(@"history reload started");
|
||||
[self reloadDataForItem:nil reloadChildren:NO];
|
||||
//NSLog(@"history reload done");
|
||||
}
|
||||
mNeedsRefresh = NO;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// createCellContents:withColumn:byItem
|
||||
//
|
||||
// override to look up the URL if the name is empty. We'll obviously always have a
|
||||
// name.
|
||||
//
|
||||
-(id) createCellContents:(NSString*)inValue withColumn:(NSString*)inColumn byItem:(id) inItem
|
||||
{
|
||||
NSString *fragment = [[NSURL URLWithString:inColumn] fragment];
|
||||
if (([inValue length] == 0) && [fragment isEqualToString:@"Name"])
|
||||
inValue = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:inItem];
|
||||
return inValue;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// filterDragItems:
|
||||
//
|
||||
// Walk the list of items, filtering out any folder. Returns a new list
|
||||
// that has been autoreleased.
|
||||
//
|
||||
- (NSArray*)filterDragItems:(NSArray*)inItems
|
||||
{
|
||||
NSMutableArray* outItems = [[[NSMutableArray alloc] init] autorelease];
|
||||
|
||||
NSEnumerator *enumerator = [inItems objectEnumerator];
|
||||
id obj;
|
||||
while ( (obj = [enumerator nextObject]) ) {
|
||||
if ( ! [mOutlineView isExpandable: obj] ) // if it's not a folder, we can drag it
|
||||
[outItems addObject:obj];
|
||||
}
|
||||
|
||||
return outItems;
|
||||
}
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView *)ov writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard
|
||||
{
|
||||
//Need to filter out folders from the list, only allow the urls to be dragged
|
||||
NSArray *toDrag = [self filterDragItems:items];
|
||||
|
||||
int count = [toDrag count];
|
||||
if (count > 0) {
|
||||
if (count == 1) {
|
||||
id item = [toDrag objectAtIndex: 0];
|
||||
|
||||
// if we have just one item, we add some more flavours
|
||||
NSString* url = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:item];
|
||||
NSString* title = [self getPropertyString:@"http://home.netscape.com/NC-rdf#Name" forItem:item];
|
||||
NSString *cleanedTitle = [title stringByReplacingCharactersInSet:[NSCharacterSet controlCharacterSet] withString:@" "];
|
||||
|
||||
[pboard declareURLPasteboardWithAdditionalTypes:[NSArray array] owner:self];
|
||||
[pboard setDataForURL:url title:cleanedTitle];
|
||||
}
|
||||
else {
|
||||
// not sure what to do here. canceling the drag for now.
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
//
|
||||
// this better be coming from a context menu
|
||||
//
|
||||
// this should only come from a context menu
|
||||
// ... because we use [aSender representedObject] apparently...
|
||||
-(IBAction)openHistoryItemInNewTab:(id)aSender
|
||||
{
|
||||
NSString *url = [aSender representedObject];
|
||||
|
@ -335,10 +293,8 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*,
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// this better be coming from a context menu
|
||||
//
|
||||
|
||||
// this should only come from a context menu
|
||||
// ... because we use [aSender representedObject] apparently...
|
||||
-(IBAction)openHistoryItemInNewWindow:(id)aSender
|
||||
{
|
||||
NSString *url = [aSender representedObject];
|
||||
|
@ -348,150 +304,150 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
-(IBAction)openHistoryItem: (id)aSender
|
||||
- (IBAction)openHistoryItem:(id)aSender
|
||||
{
|
||||
int index = [mOutlineView selectedRow];
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
id item = [mOutlineView itemAtRow: index];
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
// expand if collapsed and double click
|
||||
if ([mOutlineView isExpandable: item]) {
|
||||
if ([mOutlineView isItemExpanded: item])
|
||||
[mOutlineView collapseItem: item];
|
||||
else
|
||||
[mOutlineView expandItem: item];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// get uri
|
||||
NSString* url = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:item];
|
||||
[[mBrowserWindowController getBrowserWrapper] loadURI: url referrer: nil flags: NSLoadFlagsNone activate:YES];
|
||||
int index = [mOutlineView selectedRow];
|
||||
if (index == -1)
|
||||
return;
|
||||
id item = [mOutlineView itemAtRow: index];
|
||||
if (!item)
|
||||
return;
|
||||
if ([mOutlineView isExpandable: item]) { //TODO [item class]
|
||||
if ([mOutlineView isItemExpanded: item])
|
||||
[mOutlineView collapseItem: item];
|
||||
else
|
||||
[mOutlineView expandItem: item];
|
||||
} else {
|
||||
[[mBrowserWindowController getBrowserWrapper] loadURI:[item url] referrer:nil flags:NSLoadFlagsNone activate:YES];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// deleteHistoryItems:
|
||||
//
|
||||
// Called when user hits backspace with the history view selected. Walks the selection
|
||||
// removing the selected items from the global history in batch-mode, then reloads
|
||||
// the outline.
|
||||
//
|
||||
-(IBAction)deleteHistoryItems: (id)aSender
|
||||
// Walks the selection removing the selected items from the global history
|
||||
// in batch-mode, then reload the outline.
|
||||
- (IBAction)deleteHistoryItems:(id)aSender
|
||||
{
|
||||
int index = [mOutlineView selectedRow];
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
// if the user selected a bunch of rows, we want to clear the selection since when
|
||||
// those rows are deleted, the tree will try to keep the same # of rows selected and
|
||||
// it will look really odd. If just 1 row was selected, we keep it around so the user
|
||||
// can keep quickly deleting one row at a time.
|
||||
BOOL clearSelectionWhenDone = [mOutlineView numberOfSelectedRows] > 1;
|
||||
// If just 1 row was selected, keep it so the user can delete again immediately
|
||||
BOOL clearSelectionWhenDone = ([mOutlineView numberOfSelectedRows] > 1);
|
||||
|
||||
nsCOMPtr<nsIBrowserHistory> history = do_GetService("@mozilla.org/browser/global-history;1");
|
||||
if ( history ) {
|
||||
// Even though it looks like relying on row numbers as we delete will get us in trouble
|
||||
// and out of sync, until we actually invalidate the table, the rows keep their prior values.
|
||||
// If children are selected as well as the parent, we'll just end up trying to remove the
|
||||
// host string from history which will silently fail. It's extra work, but harmless.
|
||||
nsCOMPtr<nsIRDFDataSource> ds = do_QueryInterface(history);
|
||||
ds->BeginUpdateBatch();
|
||||
NSEnumerator* rowEnum = [mOutlineView selectedRowEnumerator];
|
||||
for ( NSNumber* currIndex = [rowEnum nextObject]; currIndex; currIndex = [rowEnum nextObject]) {
|
||||
index = [currIndex intValue];
|
||||
RDFOutlineViewItem* item = [mOutlineView itemAtRow: index];
|
||||
if ([mOutlineView isExpandable: item]) {
|
||||
// delete a folder by iterating over each of its children and deleting them. There
|
||||
// should be a better way, but the history api's don't really support them. Expand
|
||||
// the folder before we delete it otherwise we don't get any child nodes to delete.
|
||||
[mOutlineView expandItem:item];
|
||||
NSEnumerator* childEnum = [item->mChildNodes objectEnumerator];
|
||||
RDFOutlineViewItem* currChild = nil;
|
||||
while ( (currChild = [childEnum nextObject]) )
|
||||
[self removeItemFromHistory:currChild withService:history];
|
||||
}
|
||||
else
|
||||
[self removeItemFromHistory:item withService:history];
|
||||
// row numbers will stay in sync until table is invalidated
|
||||
// removing children of removed items will fail silently (harmless)
|
||||
NSEnumerator* rowEnum = [mOutlineView selectedRowEnumerator];
|
||||
int currentRow;
|
||||
while( (currentRow = [[rowEnum nextObject] intValue]) ) {
|
||||
HistoryItem * item = [mOutlineView itemAtRow:currentRow];
|
||||
if( [item isKindOfClass:[RDFItem class]] ) {
|
||||
[(HistoryItem*)item deleteFromGecko];
|
||||
[[item parent] deleteChildFromCache:item];
|
||||
}
|
||||
ds->EndUpdateBatch();
|
||||
if ( clearSelectionWhenDone )
|
||||
[mOutlineView deselectAll:self];
|
||||
|
||||
[self invalidateCachedItems];
|
||||
[mOutlineView reloadData]; // necessary or the outline is really horked
|
||||
}
|
||||
}
|
||||
|
||||
-(void)removeItemFromHistory:(id)inItem withService:(nsIBrowserHistory*)inHistService;
|
||||
{
|
||||
NSString* urlString = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:inItem];
|
||||
inHistService->RemovePage([urlString UTF8String]);
|
||||
if ( clearSelectionWhenDone )
|
||||
[mOutlineView deselectAll:self];
|
||||
[mOutlineView reloadData]; // tell outline view the data source has changed
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// outlineView:tooltipForString
|
||||
//
|
||||
// Only show a tooltip if we're not a folder. For urls, use title\nurl as the format.
|
||||
// We can re-use the base-class impl to get the title of the page and then just add on
|
||||
// to that.
|
||||
//
|
||||
- (NSString *)outlineView:(NSOutlineView *)outlineView tooltipStringForItem:(id)inItem
|
||||
#pragma mark -
|
||||
|
||||
// Implementation of NSOutlineViewDataSource protocol
|
||||
|
||||
// identifiers: title url description keyword
|
||||
- (id)outlineView:(NSOutlineView*)aOutlineView objectValueForTableColumn:(NSTableColumn*)aTableColumn byItem:(id)aItem
|
||||
{
|
||||
if ( ! [mOutlineView isExpandable: inItem] ) {
|
||||
// use baseclass to get title of page
|
||||
NSString* pageTitle = [super outlineView:outlineView tooltipStringForItem:inItem];
|
||||
if (!mRDFDataSource || !aItem)
|
||||
return nil;
|
||||
// use the table column identifier as a key
|
||||
if( [[aTableColumn identifier] isEqualToString:@"title"] )
|
||||
return [aItem name];
|
||||
else if( [[aTableColumn identifier] isEqualToString:@"url"] )
|
||||
return [aItem url];
|
||||
// else if( [[aTableColumn identifier] isEqualToString:@"description"] )
|
||||
// return [aItem date];
|
||||
return nil;
|
||||
// TODO truncate string
|
||||
// - (void)truncateToWidth:(float)maxWidth at:kTruncateAtMiddle withAttributes:(NSDictionary *)attributes
|
||||
}
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView *)ov writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard;
|
||||
{
|
||||
//Need to filter out folders from the list, only allow the urls to be dragged
|
||||
NSMutableArray* toDrag = [[[NSMutableArray alloc] init] autorelease];
|
||||
NSEnumerator *enumerator = [items objectEnumerator];
|
||||
id obj;
|
||||
while( (obj = [enumerator nextObject]) ) {
|
||||
if( ![obj isExpandable] )
|
||||
[toDrag addObject:obj];
|
||||
}
|
||||
|
||||
// append url
|
||||
NSString* url = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:inItem];
|
||||
int count = [toDrag count];
|
||||
if (count == 1) {
|
||||
id item = [toDrag objectAtIndex: 0];
|
||||
// if we have just one item, we add some more flavours
|
||||
NSString* title = [item name];
|
||||
NSString *cleanedTitle
|
||||
= [title stringByReplacingCharactersInSet:[NSCharacterSet controlCharacterSet] withString:@" "];
|
||||
[pboard declareURLPasteboardWithAdditionalTypes:[NSArray array] owner:self];
|
||||
[pboard setDataForURL:[item url] title:cleanedTitle];
|
||||
return YES;
|
||||
}
|
||||
if( count > 1 ) {
|
||||
// not sure what to do for multiple drag. just cancel for now.
|
||||
return NO;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Only show a tooltip if we're not a folder. For items, use name\nurl as the format.
|
||||
- (NSString *)outlineView:(NSOutlineView *)outlineView tooltipStringForItem:(id)anItem;
|
||||
{
|
||||
if( ![anItem isExpandable] ) {
|
||||
NSString* pageTitle = [anItem name];
|
||||
NSString* url = [anItem url];
|
||||
return [NSString stringWithFormat:@"%@\n%@", pageTitle, [url stringByTruncatingTo:80 at:kTruncateAtEnd]];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(NSCell *)inCell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
|
||||
// TODO site icons
|
||||
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(NSCell *)inCell forTableColumn:(NSTableColumn *)tableColumn item:(id)item;
|
||||
{
|
||||
// set the image on the name column. the url column doesn't have an image.
|
||||
if ([[tableColumn identifier] isEqualToString: @"title"]) {
|
||||
if ( [outlineView isExpandable: item] )
|
||||
if ([[tableColumn identifier] isEqualToString:@"title"]) {
|
||||
if ( [outlineView isExpandable:item] )
|
||||
[inCell setImage:[NSImage imageNamed:@"folder"]];
|
||||
else
|
||||
[inCell setImage:[NSImage imageNamed:@"smallbookmark"]];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSMenu *)outlineView:(NSOutlineView *)outlineView contextMenuForItem:(id)item
|
||||
- (NSMenu *)outlineView:(NSOutlineView *)outlineView contextMenuForItem:(id)item;
|
||||
{
|
||||
if (nil == item || [mOutlineView isExpandable: item])
|
||||
return nil;
|
||||
|
||||
// get item's URL, prep context menu
|
||||
NSString* url = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:item];
|
||||
NSString *nulString = [NSString string];
|
||||
NSMenu *contextMenu = [[[NSMenu alloc] initWithTitle:@"snookums"] autorelease];
|
||||
|
||||
// open in new window
|
||||
NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Open in New Window",@"Open in New Window") action:@selector(openHistoryItemInNewWindow:) keyEquivalent:nulString];
|
||||
NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Open in New Window",@"") action:@selector(openHistoryItemInNewWindow:) keyEquivalent:nulString];
|
||||
[menuItem setTarget:self];
|
||||
[menuItem setRepresentedObject:url];
|
||||
[menuItem setRepresentedObject:[item url]];
|
||||
[contextMenu addItem:menuItem];
|
||||
[menuItem release];
|
||||
|
||||
// open in new tab
|
||||
menuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Open in New Tab",@"Open in New Tab") action:@selector(openHistoryItemInNewTab:) keyEquivalent:nulString];
|
||||
menuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Open in New Tab",@"") action:@selector(openHistoryItemInNewTab:) keyEquivalent:nulString];
|
||||
[menuItem setTarget:self];
|
||||
[menuItem setRepresentedObject:url];
|
||||
[menuItem setRepresentedObject:[item url]];
|
||||
[contextMenu addItem:menuItem];
|
||||
[menuItem release];
|
||||
|
||||
// delete
|
||||
menuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Delete",@"Delete") action:@selector(deleteHistoryItems:) keyEquivalent:nulString];
|
||||
menuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Delete",@"") action:@selector(deleteHistoryItems:) keyEquivalent:nulString];
|
||||
[menuItem setTarget:self];
|
||||
[contextMenu addItem:menuItem];
|
||||
[menuItem release];
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Ben Goodger <ben@netscape.com> (Original Author)
|
||||
* Simon Woodside <sbwoodside@yahoo.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the NPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#import <Appkit/Appkit.h>
|
||||
|
||||
#import "RDFItem.h"
|
||||
|
||||
// YES if you want to have history flattened
|
||||
// eliminates the per-site folders that nsGlobalHistory returns
|
||||
// and also sorts the resulting flat list by date
|
||||
const bool kFlattenHistory = YES;
|
||||
|
||||
// URIs for RDF properties
|
||||
#define NC_NAME_KEY @"http://home.netscape.com/NC-rdf#Name"
|
||||
#define NC_URL_KEY @"http://home.netscape.com/NC-rdf#URL"
|
||||
#define NC_DATE_KEY @"http://home.netscape.com/NC-rdf#Date"
|
||||
|
||||
// HistoryItem's are the rows of the history outline view
|
||||
// extends RDFItem to support flattened history list
|
||||
@interface HistoryItem : RDFItem
|
||||
{
|
||||
NSArray * mGrandChildNodes;
|
||||
}
|
||||
|
||||
- (void)deleteFromGecko;
|
||||
|
||||
- (void)buildGrandChildCache;
|
||||
|
||||
- (HistoryItem*)childAtIndex:(int)index;
|
||||
|
||||
// RDF properties
|
||||
- (NSString*)name;
|
||||
- (NSString*)url;
|
||||
- (NSString*)date;
|
||||
|
||||
@end
|
|
@ -0,0 +1,233 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Ben Goodger <ben@netscape.com> (Original Author)
|
||||
* Simon Woodside <sbwoodside@yahoo.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the NPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
// these objects add an additional grand child cache
|
||||
// why? because we flatten the list by skipping the children RDFItems
|
||||
// and just returning the full list of grandchildren as our children
|
||||
|
||||
#import "HistoryItem.h"
|
||||
|
||||
#include "nsIRDFService.h"
|
||||
#include "nsIRDFDataSource.h"
|
||||
#include "nsIRDFResource.h"
|
||||
#include "nsIBrowserHistory.h"
|
||||
#include "nsIServiceManager.h"
|
||||
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
||||
|
||||
@interface HistoryItem (Private)
|
||||
- (HistoryItem*)newChild;
|
||||
- (void)invalidateGrandChildCache;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation HistoryItem
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if( (self = [super init]) ) {
|
||||
mGrandChildNodes = nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[mGrandChildNodes autorelease];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (HistoryItem*)newChild;
|
||||
{
|
||||
return [HistoryItem alloc];
|
||||
}
|
||||
|
||||
|
||||
- (void)deleteFromGecko;
|
||||
{
|
||||
nsCOMPtr<nsIBrowserHistory> historyService = do_GetService("@mozilla.org/browser/global-history;1");
|
||||
if( !historyService )
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIRDFDataSource> histDataSource = do_QueryInterface(historyService);
|
||||
if( !histDataSource )
|
||||
return;
|
||||
|
||||
histDataSource->BeginUpdateBatch();
|
||||
if( ![self isExpandable] ) {
|
||||
NSString* urlString = [self url];
|
||||
historyService->RemovePage([urlString UTF8String]);
|
||||
}
|
||||
else {
|
||||
// delete a folder by iterating over each of its children and deleting them. There
|
||||
// should be a better way, but the history api's don't really support them. Expand
|
||||
// the folder before we delete it otherwise we don't get any child nodes to delete.
|
||||
//TODO what if the children have children?
|
||||
int numChilds = [self numChildren];
|
||||
for( int i = 0; i < numChilds; i++ ) {
|
||||
HistoryItem * deleteChild = [self childAtIndex:i];
|
||||
[deleteChild deleteFromGecko];
|
||||
}
|
||||
}
|
||||
histDataSource->EndUpdateBatch();
|
||||
}
|
||||
|
||||
// Explicitly call to superclass
|
||||
// to avoid recursive loops
|
||||
- (bool)nativeIsExpandable;
|
||||
{ return [super isExpandable]; }
|
||||
- (int)nativeNumChildren;
|
||||
{ return [super numChildren]; }
|
||||
- (id)nativeChildAtIndex:(int)index;
|
||||
{ return [super childAtIndex:index]; }
|
||||
- (void)nativeBuildChildCache;
|
||||
{ [super buildChildCache]; }
|
||||
|
||||
// should we return grandchildren nodes instead of the children nodes?
|
||||
// this determines if we flatten the RDF at this "level"
|
||||
- (bool)shouldUseGrandChildNodes;
|
||||
{
|
||||
if( !kFlattenHistory )
|
||||
return NO;
|
||||
if( ![self nativeIsExpandable] )
|
||||
return NO;
|
||||
|
||||
if( !mChildNodes ) [self nativeBuildChildCache];
|
||||
|
||||
HistoryItem * firstChild = [mChildNodes objectAtIndex:0];
|
||||
if( [firstChild nativeIsExpandable] ) {
|
||||
HistoryItem * grandChild = [firstChild nativeChildAtIndex:0];
|
||||
//is it a leaf node?
|
||||
if( ![grandChild nativeIsExpandable] )
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (HistoryItem*)childAtIndex:(int)index;
|
||||
{
|
||||
if( !kFlattenHistory )
|
||||
return [super childAtIndex:index];
|
||||
if( ![self shouldUseGrandChildNodes] )
|
||||
return [super childAtIndex:index];
|
||||
if( !mGrandChildNodes )
|
||||
[self buildGrandChildCache];
|
||||
return [mGrandChildNodes objectAtIndex:index];
|
||||
}
|
||||
|
||||
- (int)numChildren;
|
||||
{
|
||||
if( !kFlattenHistory )
|
||||
return [super numChildren];
|
||||
if( ![self shouldUseGrandChildNodes] )
|
||||
return [super numChildren];
|
||||
if( !mGrandChildNodes )
|
||||
[self buildGrandChildCache];
|
||||
int result = [mGrandChildNodes count];
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSComparisonResult)historyItemDateCompare:(HistoryItem *)aItem;
|
||||
{
|
||||
//backwards for reverse order
|
||||
NSComparisonResult result = [[aItem date] caseInsensitiveCompare:[self date]];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
- (void)buildGrandChildCache;
|
||||
{
|
||||
if( !kFlattenHistory )
|
||||
return;
|
||||
if( ![self shouldUseGrandChildNodes] )
|
||||
return;
|
||||
// NSLog(@"Building grandChildNodes list for name=%@", [self name]);
|
||||
NSMutableArray * grandChildNodes = [[NSMutableArray alloc] init];
|
||||
int childCount = [mChildNodes count];
|
||||
for( int i=0; i < childCount; i++ ) {
|
||||
HistoryItem * curChild = [mChildNodes objectAtIndex:i];
|
||||
int grandChildCount = [curChild nativeNumChildren];
|
||||
for( int j=0; j < grandChildCount; j++ ) {
|
||||
HistoryItem * curGrandChild = [curChild nativeChildAtIndex:j];
|
||||
[grandChildNodes addObject:curGrandChild];
|
||||
}
|
||||
}
|
||||
NSArray * sorted = [grandChildNodes sortedArrayUsingSelector:@selector(historyItemDateCompare:)];
|
||||
mGrandChildNodes = [sorted retain];
|
||||
}
|
||||
|
||||
- (void)invalidateGrandChildCache;
|
||||
{
|
||||
[mGrandChildNodes autorelease];
|
||||
mGrandChildNodes = nil;
|
||||
}
|
||||
|
||||
// override superclass, because we need to also invalidate the
|
||||
// grandchildren cache of our parent (the caller's grandparent)
|
||||
- (void)deleteChildFromCache:(HistoryItem*)child;
|
||||
{
|
||||
[super deleteChildFromCache:child];
|
||||
if( [self parent] )
|
||||
[(HistoryItem*)[self parent] invalidateGrandChildCache];
|
||||
}
|
||||
|
||||
|
||||
// RDF Properties
|
||||
- (NSString*)name;
|
||||
{
|
||||
return [self getStringForRDFPropertyURI:NC_NAME_KEY];
|
||||
}
|
||||
|
||||
- (NSString*)url;
|
||||
{
|
||||
return [self getStringForRDFPropertyURI:NC_URL_KEY];
|
||||
}
|
||||
|
||||
- (NSString*)date;
|
||||
{
|
||||
return [self getStringForRDFPropertyURI:NC_DATE_KEY];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,75 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Ben Goodger <ben@netscape.com> (Original Author)
|
||||
* Simon Woodside <sbwoodside@yahoo.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the NPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#import <Appkit/Appkit.h>
|
||||
|
||||
class nsIRDFDataSource;
|
||||
class nsIRDFContainer;
|
||||
class nsIRDFContainerUtils;
|
||||
class nsIRDFResource;
|
||||
class nsIRDFService;
|
||||
|
||||
|
||||
// RDFItems make up rows of an RDF outline view
|
||||
@interface RDFItem : NSObject
|
||||
{
|
||||
NSMutableArray* mChildNodes; // array of RDFItem
|
||||
RDFItem* mParent;
|
||||
NSMutableDictionary * mPropertyCache;
|
||||
|
||||
nsIRDFResource* mRDFResource;
|
||||
nsIRDFDataSource* mRDFDataSource;
|
||||
nsIRDFContainer* mRDFContainer;
|
||||
nsIRDFContainerUtils* mRDFContainerUtils;
|
||||
nsIRDFService* mRDFService;
|
||||
}
|
||||
|
||||
- (id)initWithRDFResource:(nsIRDFResource*)aRDFResource RDFDataSource:(nsIRDFDataSource*)aRDFDataSource parent:(RDFItem*)newparent;
|
||||
- (NSString*)getStringForRDFPropertyURI:(NSString*)aPropertyURI;
|
||||
- (BOOL)isExpandable;
|
||||
- (RDFItem*)childAtIndex:(int)index;
|
||||
- (int)numChildren;
|
||||
- (RDFItem*)parent;
|
||||
|
||||
- (void)deleteChildFromCache:(RDFItem*)child;
|
||||
|
||||
- (void)buildChildCache;
|
||||
- (void)invalidateCache;
|
||||
|
||||
@end
|
|
@ -0,0 +1,311 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Ben Goodger <ben@netscape.com> (Original Author)
|
||||
* Simon Woodside <sbwoodside@yahoo.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the NPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
// These objects cache their children to avoid excessive lookups through
|
||||
// the gecko API, which can be slow
|
||||
|
||||
#import "RDFItem.h"
|
||||
|
||||
#import "NSString+Utils.h"
|
||||
|
||||
#include "nsCRT.h"
|
||||
#include "nsIRDFDataSource.h"
|
||||
#include "nsIRDFService.h"
|
||||
#include "nsIRDFLiteral.h"
|
||||
#include "nsIRDFResource.h"
|
||||
#include "nsIRDFContainer.h"
|
||||
#include "nsIRDFContainerUtils.h"
|
||||
#include "nsRDFCID.h"
|
||||
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIServiceManagerUtils.h"
|
||||
|
||||
#include "nsString.h"
|
||||
|
||||
|
||||
@interface RDFItem (Private)
|
||||
- (unsigned int)cacheVersion;
|
||||
- (BOOL)cachedChildren;
|
||||
- (void)buildChildCache;
|
||||
- (NSString*)getTextForNode:(nsIRDFNode *)aNode;
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation RDFItem
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
nsCOMPtr<nsIRDFContainer> ctr = do_CreateInstance("@mozilla.org/rdf/container;1");
|
||||
NS_ADDREF(mRDFContainer = ctr);
|
||||
|
||||
nsCOMPtr<nsIRDFContainerUtils> ctrUtils = do_GetService("@mozilla.org/rdf/container-utils;1");
|
||||
NS_ADDREF(mRDFContainerUtils = ctrUtils);
|
||||
|
||||
nsCOMPtr<nsIRDFService> rdfService = do_GetService("@mozilla.org/rdf/rdf-service;1");
|
||||
NS_ADDREF(mRDFService = rdfService);
|
||||
|
||||
mRDFDataSource = nsnull;
|
||||
mRDFResource = nsnull;
|
||||
|
||||
mPropertyCache = [[[NSMutableDictionary alloc] init] retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithRDFResource:(nsIRDFResource*)aRDFResource RDFDataSource:(nsIRDFDataSource*)aRDFDataSource parent:(RDFItem*)newparent;
|
||||
{
|
||||
if( (self = [self init]) ) {
|
||||
NS_IF_ADDREF(mRDFResource = aRDFResource);
|
||||
mRDFDataSource = aRDFDataSource;
|
||||
mParent = newparent;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[mChildNodes autorelease];
|
||||
[mPropertyCache autorelease];
|
||||
NS_IF_RELEASE(mRDFResource);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (RDFItem*)newChild;
|
||||
{
|
||||
return [RDFItem alloc];
|
||||
}
|
||||
|
||||
- (void)invalidateCache;
|
||||
{
|
||||
if( mChildNodes ) {
|
||||
//invalidate children first (in case they have children)
|
||||
[mChildNodes makeObjectsPerformSelector:@selector(invalidateCache)];
|
||||
[mChildNodes autorelease];
|
||||
mChildNodes = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)cachedChildren
|
||||
{
|
||||
return (mChildNodes != nil);
|
||||
}
|
||||
|
||||
- (BOOL)isExpandable
|
||||
{
|
||||
if( mChildNodes )
|
||||
return YES; // cached already
|
||||
|
||||
// Query gecko for the answer
|
||||
PRBool isSeq = PR_FALSE;
|
||||
mRDFContainerUtils->IsSeq(mRDFDataSource, mRDFResource, &isSeq);
|
||||
if (isSeq)
|
||||
return YES;
|
||||
|
||||
nsCOMPtr<nsIRDFResource> childRDFProperty;
|
||||
mRDFService->GetResource(nsDependentCString("http://home.netscape.com/NC-rdf#child"),
|
||||
getter_AddRefs(childRDFProperty));
|
||||
nsCOMPtr<nsISimpleEnumerator> childNodesEnum;
|
||||
mRDFDataSource->GetTargets(mRDFResource, childRDFProperty, PR_TRUE, getter_AddRefs(childNodesEnum));
|
||||
|
||||
PRBool hasMore = PR_FALSE;
|
||||
if( NS_SUCCEEDED(childNodesEnum->HasMoreElements(&hasMore)) && hasMore ) {
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
childNodesEnum->GetNext(getter_AddRefs(supp));
|
||||
nsCOMPtr<nsIRDFResource> childResource = do_QueryInterface(supp);
|
||||
if (childResource)
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
- (int)numChildren;
|
||||
{
|
||||
if( mChildNodes )
|
||||
return [mChildNodes count];
|
||||
|
||||
// Since gecko RDF enumerator->HasMoreElements
|
||||
// is so slow, we may as well build the cache now
|
||||
// because the extra time it takes is tiny
|
||||
[self buildChildCache];
|
||||
int numChilds = [mChildNodes count];
|
||||
return numChilds;
|
||||
}
|
||||
|
||||
// 0- based
|
||||
- (RDFItem*)childAtIndex:(int)index;
|
||||
{
|
||||
if( !mChildNodes )
|
||||
[self buildChildCache];
|
||||
return [mChildNodes objectAtIndex:index];
|
||||
}
|
||||
|
||||
- (void)buildChildCache;
|
||||
{
|
||||
NSMutableArray * childNodes = [[[NSMutableArray alloc] init] retain];
|
||||
|
||||
[self invalidateCache];
|
||||
|
||||
nsCOMPtr<nsIRDFResource> childRDFProperty;
|
||||
mRDFService->GetResource(nsDependentCString("http://home.netscape.com/NC-rdf#child"),
|
||||
getter_AddRefs(childRDFProperty));
|
||||
nsCOMPtr<nsISimpleEnumerator> childNodesEnum;
|
||||
mRDFDataSource->GetTargets(mRDFResource, childRDFProperty, PR_TRUE, getter_AddRefs(childNodesEnum));
|
||||
|
||||
PRBool hasMore = PR_FALSE;
|
||||
// this call to HasMoreElements can take more than 10 ms !!
|
||||
// maybe not any more though
|
||||
while( NS_SUCCEEDED(childNodesEnum->HasMoreElements(&hasMore)) && hasMore ) {
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
childNodesEnum->GetNext(getter_AddRefs(supp));
|
||||
nsCOMPtr<nsIRDFResource> childResource = do_QueryInterface(supp);
|
||||
if (childResource) {
|
||||
RDFItem * childItem = [self newChild];
|
||||
[childItem initWithRDFResource:childResource RDFDataSource:mRDFDataSource parent:self];
|
||||
if (childItem)
|
||||
[childNodes addObject:childItem];
|
||||
}
|
||||
}
|
||||
mChildNodes = [childNodes retain];
|
||||
}
|
||||
|
||||
- (void)deleteChildFromCache:(RDFItem*)child;
|
||||
{
|
||||
[mChildNodes removeObject:child];
|
||||
}
|
||||
|
||||
- (RDFItem*)parent;
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (NSString*)getStringForRDFPropertyURI:(NSString*)aPropertyURI;
|
||||
{
|
||||
NSString * cached = [mPropertyCache objectForKey:aPropertyURI];
|
||||
if( cached )
|
||||
return cached;
|
||||
|
||||
nsCOMPtr<nsIRDFResource> myRDFProperty;
|
||||
mRDFService->GetResource(nsDependentCString([aPropertyURI UTF8String]),
|
||||
getter_AddRefs(myRDFProperty));
|
||||
nsCOMPtr<nsIRDFNode> resultNode;
|
||||
nsresult rv;
|
||||
rv = mRDFDataSource->GetTarget(mRDFResource, myRDFProperty, PR_TRUE, getter_AddRefs(resultNode));
|
||||
if( NS_FAILED(rv) )
|
||||
return @"mRDFDataSource->GetTarget NS_FAILED";
|
||||
if (!resultNode) {
|
||||
// NSLog(@"resultNode is null in getStringForRDFPropertyURI, aPropertyURI= %@", aPropertyURI);
|
||||
return @"";
|
||||
}
|
||||
NSString * result = [self getTextForNode:resultNode];
|
||||
[mPropertyCache setObject:result forKey:aPropertyURI];
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSString *)description;
|
||||
{
|
||||
return [self getStringForRDFPropertyURI:@"http://home.netscape.com/NC-rdf#Name"];
|
||||
}
|
||||
|
||||
- (NSString*)getTextForNode:(nsIRDFNode *)aNode;
|
||||
{
|
||||
nsString aResult;
|
||||
NSString * resultString = nil;
|
||||
|
||||
nsresult rv;
|
||||
nsIRDFResource *resource;
|
||||
nsIRDFLiteral *literal;
|
||||
nsIRDFDate *dateLiteral;
|
||||
nsIRDFInt *intLiteral;
|
||||
if (! aNode) {
|
||||
aResult.Truncate();
|
||||
rv = NS_OK;
|
||||
}
|
||||
else if (NS_SUCCEEDED(rv = aNode->QueryInterface(NS_GET_IID(nsIRDFResource), (void**) &resource))) {
|
||||
const char *p = nsnull;
|
||||
if (NS_SUCCEEDED(rv = resource->GetValueConst( &p )) && (p)) {
|
||||
aResult.AssignWithConversion(p);
|
||||
}
|
||||
NS_RELEASE(resource);
|
||||
}
|
||||
else if (NS_SUCCEEDED(rv = aNode->QueryInterface(NS_GET_IID(nsIRDFDate), (void**) &dateLiteral))) {
|
||||
PRInt64 theDate, million;
|
||||
if (NS_SUCCEEDED(rv = dateLiteral->GetValue( &theDate ))) {
|
||||
LL_I2L(million, PR_USEC_PER_SEC);
|
||||
LL_DIV(theDate, theDate, million); // convert from microseconds (PRTime) to seconds
|
||||
PRInt32 now32;
|
||||
LL_L2I(now32, theDate);
|
||||
double interval = (double)now32;
|
||||
NSDate * date = [NSDate dateWithTimeIntervalSince1970:interval];
|
||||
resultString = [date description];
|
||||
}
|
||||
NS_RELEASE(dateLiteral);
|
||||
}
|
||||
else if (NS_SUCCEEDED(rv = aNode->QueryInterface(NS_GET_IID(nsIRDFInt), (void**) &intLiteral)))
|
||||
{
|
||||
PRInt32 theInt;
|
||||
aResult.Truncate();
|
||||
if (NS_SUCCEEDED(rv = intLiteral->GetValue( &theInt ))) {
|
||||
aResult.AppendInt(theInt, 10);
|
||||
}
|
||||
NS_RELEASE(intLiteral);
|
||||
}
|
||||
else if (NS_SUCCEEDED(rv = aNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), (void**) &literal))) {
|
||||
const PRUnichar *p = nsnull;
|
||||
if (NS_SUCCEEDED(rv = literal->GetValueConst( &p )) && (p)) {
|
||||
aResult = p;
|
||||
}
|
||||
NS_RELEASE(literal);
|
||||
}
|
||||
else {
|
||||
NS_ERROR("not a resource or a literal");
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
return @"Not a resource or a literal";
|
||||
}
|
||||
if( !resultString )
|
||||
resultString = [NSString stringWith_nsAString:aResult];
|
||||
return resultString;
|
||||
}
|
||||
|
||||
@end
|
Загрузка…
Ссылка в новой задаче