Try to fix trunk bustage, sync with RDF API changes.

This commit is contained in:
sfraser%netscape.com 2003-03-01 01:22:42 +00:00
Родитель 7d6c58b9b3
Коммит c0e3081817
4 изменённых файлов: 3 добавлений и 931 удалений

Просмотреть файл

@ -406,7 +406,7 @@
isExpandable = YES;
nsCOMPtr<nsIRDFResource> childProperty;
mRDFService->GetResource("http://home.netscape.com/NC-rdf#child", getter_AddRefs(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));
@ -439,7 +439,7 @@
- (NSString*)getPropertyString:(NSString*)inPropertyURI forItem:(RDFOutlineViewItem*)inItem
{
nsCOMPtr<nsIRDFResource> propertyResource;
mRDFService->GetResource([inPropertyURI UTF8String], getter_AddRefs(propertyResource));
mRDFService->GetResource(nsDependentCString([inPropertyURI UTF8String]), getter_AddRefs(propertyResource));
nsCOMPtr<nsIRDFResource> resource = dont_AddRef([inItem resource]);

Просмотреть файл

@ -198,7 +198,7 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*,
// Get the Global History DataSource
mRDFService->GetDataSource("rdf:history", &mDataSource);
// Get the Date Folder Root
mRDFService->GetResource("NC:HistoryByDate", &mRootResource);
mRDFService->GetResource(nsDependentCString("NC:HistoryByDate"), &mRootResource);
[mOutlineView setTarget: self];
[mOutlineView setDoubleAction: @selector(openHistoryItem:)];

Просмотреть файл

@ -1,468 +0,0 @@
/* -*- 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)
*
* 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 "NSString+Utils.h"
#import "RDFOutlineViewDataSource.h"
#import "CHBrowserService.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 "nsXPIDLString.h"
#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;
}
@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;
}
return self;
}
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self cleanup];
[super dealloc];
}
- (void)cleanup
{
NS_IF_RELEASE(mContainer);
NS_IF_RELEASE(mContainerUtils);
NS_IF_RELEASE(mRDFService);
NS_IF_RELEASE(mDataSource);
NS_IF_RELEASE(mRootResource);
[mDictionary release];
mDictionary = nil;
}
- (void)cleanupDataSource
{
[self cleanup];
}
//
// ensureDataSourceLoaded
//
// defer loading all this rdf junk until it's requested because it's slow
//
- (void) ensureDataSourceLoaded
{
if ( !mContainer ) {
nsCOMPtr<nsIRDFContainer> ctr = do_CreateInstance("@mozilla.org/rdf/container;1");
NS_ADDREF(mContainer = ctr);
nsCOMPtr<nsIRDFContainerUtils> ctrUtils = do_GetService("@mozilla.org/rdf/container-utils;1");
NS_ADDREF(mContainerUtils = 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;
}
}
- (void)registerForShutdownNotification
{
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(shutdown:)
name: XPCOMShutDownNotificationName
object: nil];
}
- (void)shutdown: (NSNotification*)aNotification
{
[self cleanupDataSource];
}
- (nsIRDFDataSource*) dataSource
{
NS_IF_ADDREF(mDataSource);
return mDataSource;
}
- (nsIRDFResource*) rootResource
{
NS_IF_ADDREF(mRootResource);
return mRootResource;
}
- (void) setDataSource: (nsIRDFDataSource*) aDataSource
{
nsIRDFDataSource* oldDataSource = mDataSource;
NS_IF_ADDREF(mDataSource = aDataSource);
NS_IF_RELEASE(oldDataSource);
}
- (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
{
return NO;
}
- (BOOL) outlineView: (NSOutlineView*)aOutlineView isItemExpandable:(id)aItem
{
if (!mDataSource)
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];
}
- (id)outlineView:(NSOutlineView*)aOutlineView child:(int)aIndex ofItem:(id)aItem
{
if (!mDataSource)
return nil;
if (!aItem)
{
nsCOMPtr<nsIRDFResource> rootResource = dont_AddRef([self rootResource]);
aItem = [self getWrapperFor:rootResource];
}
if (![aItem cacheValid:mCacheVersion needChildren:YES])
[self updateItemProperties:aItem enumerateChildren:YES];
return [aItem childAtIndex:aIndex];
}
- (int)outlineView:(NSOutlineView*)aOutlineView numberOfChildrenOfItem:(id) aItem;
{
if (!mDataSource)
return 0;
if (!aItem)
{
nsCOMPtr<nsIRDFResource> rootResource = dont_AddRef([self rootResource]);
aItem = [self getWrapperFor:rootResource];
}
if (![aItem cacheValid:mCacheVersion needChildren:YES])
[self updateItemProperties:aItem enumerateChildren:YES];
return [aItem numChildren];
}
- (id)outlineView:(NSOutlineView*)aOutlineView objectValueForTableColumn:(NSTableColumn*)aTableColumn
byItem:(id)aItem
{
if (!mDataSource || !aItem)
return nil;
// The table column's identifier is the RDF Resource URI of the property being displayed in
// that column, e.g. "http://home.netscape.com/NC-rdf#Name"
NSString* columnPropertyURI = [aTableColumn identifier];
NSString* propString = [self getPropertyString:columnPropertyURI forItem:aItem];
return [self createCellContents:propString withColumn:columnPropertyURI byItem:aItem];
}
//
// 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
// anything more complicated
//
- (NSString *)outlineView:(NSOutlineView *)outlineView tooltipStringForItem:(id)inItem
{
return [self getPropertyString:@"http://home.netscape.com/NC-rdf#Name" forItem:inItem];
}
- (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;
}
- (void)invalidateCachedItems
{
mCacheVersion++;
}
- (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("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([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

Просмотреть файл

@ -1,460 +0,0 @@
/* -*- 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):
*
* 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 "NSString+Utils.h"
#import "NSPasteboard+Utils.h"
#import "BrowserWindowController.h"
#import "HistoryDataSource.h"
#import "CHBrowserView.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"
//
// 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
//
class HistoryDataSourceObserver : public nsIRDFObserver
{
public:
HistoryDataSourceObserver(HistoryDataSource* dataSource)
: mHistoryDataSource(dataSource)
{
NS_INIT_ISUPPORTS();
}
virtual ~HistoryDataSourceObserver() { }
NS_DECL_ISUPPORTS
NS_IMETHOD OnAssert(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*);
NS_IMETHOD OnUnassert(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*);
NS_IMETHOD OnMove(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*)
{ return NS_OK; }
NS_IMETHOD OnChange(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*, nsIRDFNode*);
NS_IMETHOD BeginUpdateBatch(nsIRDFDataSource*) { return NS_OK; }
NS_IMETHOD EndUpdateBatch(nsIRDFDataSource*) { return NS_OK; }
private:
HistoryDataSource* mHistoryDataSource;
};
NS_IMPL_ISUPPORTS1(HistoryDataSourceObserver, nsIRDFObserver)
//
// OnAssert
//
// Catches newly added items to the history, for surfing while the drawer is
// open.
//
NS_IMETHODIMP
HistoryDataSourceObserver::OnAssert(nsIRDFDataSource*, nsIRDFResource*,
nsIRDFResource* aProperty, nsIRDFNode*)
{
const char* p;
aProperty->GetValueConst(&p);
if (strcmp("http://home.netscape.com/NC-rdf#Date", p) == 0)
[mHistoryDataSource setNeedsRefresh:YES];
return NS_OK;
}
//
// OnUnassert
//
// This gets called on redirects, when nsGlobalHistory::RemovePage is called.
//
NS_IMETHODIMP
HistoryDataSourceObserver::OnUnassert(nsIRDFDataSource*, nsIRDFResource*,
nsIRDFResource* aProperty, nsIRDFNode*)
{
const char* p;
aProperty->GetValueConst(&p);
if (strcmp("http://home.netscape.com/NC-rdf#Date", p) == 0)
[mHistoryDataSource setNeedsRefresh:YES];
return NS_OK;
}
//
// OnChange
//
// Catches items that are already in history, but need to be moved because you're
// visiting them and they change date
//
NS_IMETHODIMP
HistoryDataSourceObserver::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;
@end
@implementation HistoryDataSource
- (void) dealloc
{
[self cleanupHistory];
[super dealloc];
}
// "non-virtual" cleanup method -- safe to call from dealloc.
- (void)cleanupHistory
{
if (mDataSource && mObserver)
{
mDataSource->RemoveObserver(mObserver);
NS_RELEASE(mObserver); // nulls it
}
}
// "virtual" method; called from superclass
- (void)cleanupDataSource
{
[self cleanupHistory];
[super cleanupDataSource];
}
//
// ensureDataSourceLoaded
//
// 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
{
[super ensureDataSourceLoaded];
NS_ASSERTION(mRDFService, "Uh oh, RDF service not loaded in parent class");
if ( !mDataSource )
{
// Get the Global History DataSource
mRDFService->GetDataSource("rdf:history", &mDataSource);
// Get the Date Folder Root
mRDFService->GetResource("NC:HistoryByDate", &mRootResource);
[mOutlineView setTarget: self];
[mOutlineView setDoubleAction: @selector(openHistoryItem:)];
[mOutlineView setDeleteAction: @selector(deleteHistoryItems:)];
mObserver = new HistoryDataSourceObserver(self);
if ( mObserver ) {
NS_ADDREF(mObserver);
mDataSource->AddObserver(mObserver);
}
[mOutlineView reloadData];
}
else
{
// everything is loaded, but we have to refresh our tree otherwise
// changes that took place while the drawer was closed won't be noticed
[mOutlineView reloadData];
}
NS_ASSERTION(mDataSource, "Uh oh, History RDF Data source not created");
}
- (void)enableObserver
{
mUpdatesEnabled = YES;
}
-(void)disableObserver
{
mUpdatesEnabled = NO;
}
- (void)setNeedsRefresh:(BOOL)needsRefresh
{
mNeedsRefresh = needsRefresh;
}
- (BOOL)needsRefresh
{
return mNeedsRefresh;
}
- (void)refresh
{
if (mNeedsRefresh)
{
[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 create an NSAttributedString instead of just the string with the
// given text. We add an icon and adjust the positioning of the text w/in the cell
//
-(id) createCellContents:(NSString*)inValue withColumn:(NSString*)inColumn byItem:(id) inItem
{
if ([inValue length] == 0)
inValue = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:inItem];
NSMutableAttributedString *cellValue = [[[NSMutableAttributedString alloc] initWithString:inValue] autorelease];
if ([inColumn isEqualToString:@"http://home.netscape.com/NC-rdf#Name"])
{
NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:nil];
NSTextAttachment *textAttachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper];
// Create an attributed string to hold the empty attachment, then release the components.
NSMutableAttributedString *attachmentAttrString = [NSMutableAttributedString attributedStringWithAttachment:textAttachment];
[textAttachment release];
[fileWrapper release];
//Get the cell of the text attachment.
NSCell* attachmentAttrStringCell = (NSCell *)[(NSTextAttachment *)[attachmentAttrString attribute:
NSAttachmentAttributeName atIndex:0 effectiveRange:nil] attachmentCell];
if ([self outlineView:mOutlineView isItemExpandable:inItem])
[attachmentAttrStringCell setImage:[NSImage imageNamed:@"folder"]];
else
[attachmentAttrStringCell setImage:[NSImage imageNamed:@"smallbookmark"]];
//Insert the image
[cellValue replaceCharactersInRange:NSMakeRange(0, 0) withAttributedString:attachmentAttrString];
//Tweak the baseline to vertically center the text.
[cellValue addAttribute:NSBaselineOffsetAttributeName
value:[NSNumber numberWithFloat:-5.0]
range:NSMakeRange(0, 1)];
}
return cellValue;
}
//
// 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;
}
-(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];
}
//
// 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
{
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;
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.
history->StartBatchUpdate();
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];
}
history->EndBatchUpdate();
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]);
}
//
// 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
{
if ( ! [mOutlineView isExpandable: inItem] ) {
// use baseclass to get title of page
NSString* pageTitle = [super outlineView:outlineView tooltipStringForItem:inItem];
// append url
NSString* url = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:inItem];
return [NSString stringWithFormat:@"%@\n%@", pageTitle, [url stringByTruncatingTo:80 at:kTruncateAtEnd]];
}
return nil;
}
@end