/* * BookmarksService.cpp * Chimera * * Created by David Hyatt on Thu Feb 07 2002. * Copyright (c) 2001 __MyCompanyName__. All rights reserved. * */ #import "NSBrowserView.h" #include "BookmarksService.h" #include "nsIDocument.h" #include "nsIContent.h" #include "nsIAtom.h" #include "nsITextContent.h" #include "nsIDOMDocument.h" #include "nsIDOMElement.h" #include "nsString.h" #include "nsIFile.h" #include "nsAppDirectoryServiceDefs.h" #include "nsIXMLHttpRequest.h" #include "nsNetUtil.h" #include "nsINamespaceManager.h" #include "nsIXBLService.h" @implementation BookmarksDataSource -(id) init { [super init]; mBookmarks = nsnull; return self; } -(void) dealloc { [super dealloc]; if (mBookmarks) BookmarksService::RemoveObserver(nsnull); } -(void) ensureBookmarks { if (mBookmarks) return; mBookmarks = BookmarksService::AddObserver(nsnull); [mOutlineView setTarget: self]; [mOutlineView setDoubleAction: @selector(openBookmark:)]; [mOutlineView reloadData]; } -(IBAction)addBookmark:(id)aSender { if (!mBookmarks) return; nsCOMPtr content; int index = [mOutlineView selectedRow]; if (index > 0) { BookmarkItem* item = [mOutlineView itemAtRow: index]; if (![mOutlineView isExpandable: item]) content = [item contentNode]; } if (!content) mBookmarks->GetRootContent(getter_AddRefs(content)); nsCOMPtr doc; content->GetDocument(*getter_AddRefs(doc)); nsCOMPtr domDoc(do_QueryInterface(doc)); nsCOMPtr elt; domDoc->CreateElementNS(NS_LITERAL_STRING("http://chimera.mozdev.org/bookmarks"), NS_LITERAL_STRING("bookmark"), getter_AddRefs(elt)); elt->SetAttribute(NS_LITERAL_STRING("title"), NS_LITERAL_STRING("MozillaZine")); elt->SetAttribute(NS_LITERAL_STRING("href"), NS_LITERAL_STRING("http://www.mozillazine.org/")); nsCOMPtr parent(do_QueryInterface(content)); nsCOMPtr dummy; parent->AppendChild(elt, getter_AddRefs(dummy)); } -(IBAction)deleteBookmark: (id)aSender { } -(IBAction)openBookmark: (id)aSender { int index = [mOutlineView selectedRow]; if (index == -1) return; id item = [mOutlineView itemAtRow: index]; if (!item) return; if ([mOutlineView isExpandable: item]) { if ([mOutlineView isItemExpanded: item]) [mOutlineView collapseItem: item]; else [mOutlineView expandItem: item]; } else { nsIContent* content = [item contentNode]; nsAutoString href; content->GetAttr(kNameSpaceID_None, BookmarksService::gHrefAtom, href); if (!href.IsEmpty()) { nsCAutoString cstr; cstr.AssignWithConversion(href); NSString* url = [NSString stringWithCString: cstr.get()]; [[mBrowserView getBrowserView] loadURI:[NSURL URLWithString: url] flags:NSLoadFlagsNone]; } } } - (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item { if (!mBookmarks) return nil; nsCOMPtr content; if (!item) mBookmarks->GetRootContent(getter_AddRefs(content)); else content = [item contentNode]; nsCOMPtr child; content->ChildAt(index, *getter_AddRefs(child)); return mBookmarks->GetWrapperFor(child); } - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item { if (!mBookmarks) return NO; if (!item) return YES; // The root node is always open. nsCOMPtr tagName; nsIContent* content = [item contentNode]; content->GetTag(*getter_AddRefs(tagName)); return (tagName == BookmarksService::gFolderAtom); } - (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item { if (!mBookmarks) return 0; nsCOMPtr content; if (!item) mBookmarks->GetRootContent(getter_AddRefs(content)); else content = [item contentNode]; PRInt32 childCount; content->ChildCount(childCount); return childCount; } - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item { if (!item) return nil; NSString* columnName = [tableColumn identifier]; if ([columnName isEqualToString: @"name"]) { nsIContent* content = [item contentNode]; nsAutoString nameAttr; content->GetAttr(kNameSpaceID_None, BookmarksService::gNameAtom, nameAttr); nsCAutoString cStr; cStr.AssignWithConversion(nameAttr); return [NSString stringWithCString: cStr.get()]; } return nil; } - (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item { } @end @implementation BookmarkItem -(nsIContent*)contentNode { return mContentNode; } -(void)setContentNode: (nsIContent*)aContentNode { mContentNode = aContentNode; } @end // Helper for stripping whitespace static void StripWhitespaceNodes(nsIContent* aElement) { PRInt32 childCount; aElement->ChildCount(childCount); for (PRInt32 i = 0; i < childCount; i++) { nsCOMPtr child; aElement->ChildAt(i, *getter_AddRefs(child)); nsCOMPtr text = do_QueryInterface(child); if (text) { PRBool isEmpty; text->IsOnlyWhitespace(&isEmpty); if (isEmpty) { // This node contained nothing but whitespace. // Remove it from the content model. aElement->RemoveChildAt(i, PR_TRUE); i--; // Decrement our count, since we just removed this child. childCount--; // Also decrement our total count. } } else StripWhitespaceNodes(child); } } PRUint32 BookmarksService::gRefCnt = 0; BookmarksService* BookmarksService::gSingleton = nsnull; nsIAtom* BookmarksService::gFolderAtom = nsnull; nsIAtom* BookmarksService::gBookmarkAtom = nsnull; nsIAtom* BookmarksService::gHrefAtom = nsnull; nsIAtom* BookmarksService::gNameAtom = nsnull; BookmarksService::BookmarksService() { mDictionary = nil; nsCOMPtr profileDir; NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profileDir)); profileDir->Append("bookmarks.xml"); nsXPIDLCString bookmarksFileURL; NS_GetURLSpecFromFile(profileDir, getter_Copies(bookmarksFileURL)); nsCOMPtr uri; NS_NewURI(getter_AddRefs(uri), bookmarksFileURL.get()); nsCOMPtr xblService(do_GetService("@mozilla.org/xbl;1")); xblService->FetchSyncXMLDocument(uri, getter_AddRefs(mBookmarks)); nsCOMPtr rootNode; GetRootContent(getter_AddRefs(rootNode)); StripWhitespaceNodes(rootNode); } BookmarksService::~BookmarksService() { [mDictionary release]; } void BookmarksService::GetRootContent(nsIContent** aResult) { *aResult = nsnull; if (mBookmarks) { nsCOMPtr elt; nsCOMPtr domDoc(do_QueryInterface(mBookmarks)); domDoc->GetDocumentElement(getter_AddRefs(elt)); elt->QueryInterface(NS_GET_IID(nsIContent), (void**)aResult); // Addref happens here. } } BookmarkItem* BookmarksService::GetWrapperFor(nsIContent* aContent) { if (!mDictionary) mDictionary = [[NSMutableDictionary alloc] initWithCapacity: 30]; PRUint32 contentID; aContent->GetContentID(&contentID); BookmarkItem* item = [mDictionary objectForKey: [NSNumber numberWithInt: contentID]]; if (item) return item; else { // Create an item. item = [[[BookmarkItem alloc] init] autorelease]; // The dictionary retains us. [item setContentNode: aContent]; [mDictionary setObject: item forKey: [NSNumber numberWithInt: contentID]]; } return item; } BookmarksService* BookmarksService::AddObserver(nsIDocumentObserver* aObserver) { gRefCnt++; if (gRefCnt == 1) { gSingleton = new BookmarksService(); gBookmarkAtom = NS_NewAtom("bookmark"); gFolderAtom = NS_NewAtom("folder"); gNameAtom = NS_NewAtom("name"); gHrefAtom = NS_NewAtom("href"); } return gSingleton; } void BookmarksService::RemoveObserver(nsIDocumentObserver* aObserver) { if (gRefCnt == 0) return; gRefCnt--; if (gRefCnt == 0) { delete gSingleton; NS_RELEASE(gBookmarkAtom); NS_RELEASE(gFolderAtom); NS_RELEASE(gNameAtom); NS_RELEASE(gHrefAtom); } }