From 8b8d0528839bf6bd67696b9859332ecdb9347973 Mon Sep 17 00:00:00 2001 From: "sfraser%netscape.com" Date: Tue, 20 Aug 2002 01:10:56 +0000 Subject: [PATCH] Fix bug 162776: prevent the toolbar root bookmarks folder from being deleted by a drag to the trash. --- camino/BookmarksService.mm | 1434 --------------------- camino/src/bookmarks/BookmarksService.mm | 2 +- chimera/BookmarksService.mm | 1434 --------------------- chimera/src/bookmarks/BookmarksService.mm | 2 +- 4 files changed, 2 insertions(+), 2870 deletions(-) diff --git a/camino/BookmarksService.mm b/camino/BookmarksService.mm index 82e41be1c36..e69de29bb2d 100644 --- a/camino/BookmarksService.mm +++ b/camino/BookmarksService.mm @@ -1,1434 +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 "CHPreferenceManager.h" -#import "CHBrowserView.h" -#import "BookmarksService.h" -#import "BookmarksDataSource.h" -#import "BookmarkInfoController.h" -#import "BrowserTabView.h" -#import "SiteIconProvider.h" - -#include "nsCRT.h" -#include "nsString.h" -#include "nsIDocument.h" -#include "nsIContent.h" -#include "nsIAtom.h" -#include "nsITextContent.h" -#include "nsIDOMWindow.h" -#include "nsIDOMHTMLDocument.h" -#include "nsIDOMElement.h" -#include "nsIDOMCharacterData.h" -#include "nsIDOMParser.h" -#include "nsIDOMDocumentFragment.h" -#include "nsIPrefBranch.h" -#include "nsIFile.h" -#include "nsAppDirectoryServiceDefs.h" -#include "nsIXMLHttpRequest.h" -#include "nsIDOMSerializer.h" -#include "nsIDocumentEncoder.h" -#include "nsNetUtil.h" -#include "nsINamespaceManager.h" -#include "nsIXBLService.h" -#include "nsIWebBrowser.h" - - -// Helper for stripping whitespace -static void -StripWhitespaceNodes(nsIContent* aElement) -{ - PRInt32 childCount = 0; - 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 = PR_FALSE; - 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); - } -} - -// the tag of the separator after which to insert bookmarks menu items -// this tag must not conflict with content IDs (which are all >=0) -// and match the tab in the .nib -static const int kBookmarksDividerTag = -1; - - -PRUint32 BookmarksService::gRefCnt = 0; -nsIDocument* BookmarksService::gBookmarks = nsnull; -NSMutableDictionary* BookmarksService::gDictionary = nil; -MainController* BookmarksService::gMainController = nil; -NSMenu* BookmarksService::gBookmarksMenu = nil; -nsIDOMElement* BookmarksService::gToolbarRoot = nsnull; - -nsIAtom* BookmarksService::gBookmarkAtom = nsnull; -nsIAtom* BookmarksService::gDescriptionAtom = nsnull; -nsIAtom* BookmarksService::gFolderAtom = nsnull; -nsIAtom* BookmarksService::gGroupAtom = nsnull; -nsIAtom* BookmarksService::gHrefAtom = nsnull; -nsIAtom* BookmarksService::gKeywordAtom = nsnull; -nsIAtom* BookmarksService::gNameAtom = nsnull; -nsIAtom* BookmarksService::gOpenAtom = nsnull; - -nsVoidArray* BookmarksService::gInstances = nsnull; - -BOOL BookmarksService::gBookmarksFileReadOK = NO; - -int BookmarksService::CHInsertNone = 0; -int BookmarksService::CHInsertInto = 1; -int BookmarksService::CHInsertBefore = 2; -int BookmarksService::CHInsertAfter = 3; - -BookmarksService::BookmarksService(BookmarksDataSource* aDataSource) -{ - mDataSource = aDataSource; - mToolbar = nil; -} - -BookmarksService::BookmarksService(CHBookmarksToolbar* aToolbar) -{ - mDataSource = nil; - mToolbar = aToolbar; -} - -BookmarksService::~BookmarksService() -{ -} - -void -BookmarksService::AddObserver() -{ - gRefCnt++; - if (gRefCnt == 1) { - gBookmarkAtom = NS_NewAtom("bookmark"); - gFolderAtom = NS_NewAtom("folder"); - gNameAtom = NS_NewAtom("name"); - gHrefAtom = NS_NewAtom("href"); - gOpenAtom = NS_NewAtom("open"); - gKeywordAtom = NS_NewAtom("id"); - gDescriptionAtom = NS_NewAtom("description"); - gGroupAtom = NS_NewAtom("group"); - gInstances = new nsVoidArray(); - - ReadBookmarks(); - } - - gInstances->AppendElement(this); -} - -void -BookmarksService::RemoveObserver() -{ - if (gRefCnt == 0) - return; - - gInstances->RemoveElement(this); - - gRefCnt--; - if (gRefCnt == 0) { - // Flush Bookmarks before shutting down as some changes are not flushed when - // they are performed (folder open/closed) as writing a whole bookmark file for - // that type of operation seems excessive. - FlushBookmarks(); - - NS_IF_RELEASE(gBookmarks); - NS_RELEASE(gBookmarkAtom); - NS_RELEASE(gFolderAtom); - NS_RELEASE(gNameAtom); - NS_RELEASE(gHrefAtom); - NS_RELEASE(gOpenAtom); - [gDictionary release]; - } -} - -#pragma mark - - -void -BookmarksService::GetRootContent(nsIContent** aResult) -{ - *aResult = nsnull; - if (gBookmarks) { - nsCOMPtr domDoc(do_QueryInterface(gBookmarks)); - if (!domDoc) return; - - nsCOMPtr elt; - domDoc->GetDocumentElement(getter_AddRefs(elt)); - if (elt) - elt->QueryInterface(NS_GET_IID(nsIContent), (void**)aResult); // Addref happens here. - } -} - -BookmarkItem* -BookmarksService::GetRootItem() -{ - nsCOMPtr rootContent; - BookmarksService::GetRootContent(getter_AddRefs(rootContent)); - BookmarkItem* rootItem = BookmarksService::GetWrapperFor(rootContent); - return rootItem; -} - -BookmarkItem* -BookmarksService::GetWrapperFor(nsIContent* aContent) -{ - if ( !aContent ) - return nil; - - if (!gDictionary) - gDictionary = [[NSMutableDictionary alloc] initWithCapacity: 30]; - - PRUint32 contentID = 0; - aContent->GetContentID(&contentID); - - BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: contentID]]; - if (item) - return item; - - // Create an item. - item = [[BookmarkItem alloc] init]; // The dictionary retains us. - [item setContentNode: aContent]; - [gDictionary setObject: item forKey: [NSNumber numberWithInt: contentID]]; - [item release]; - return item; -} - -BookmarkItem* -BookmarksService::GetWrapperFor(PRUint32 contentID) -{ - BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithUnsignedInt: contentID]]; - return item; -} - -NSMenu* -BookmarksService::LocateMenu(nsIContent* aContent) -{ - nsCOMPtr parent; - aContent->GetParent(*getter_AddRefs(parent)); - if (!parent) { - return BookmarksService::gBookmarksMenu; - } - - NSMenu* parentMenu = LocateMenu(parent); - - PRUint32 contentID; - aContent->GetContentID(&contentID); - - NSMenuItem* childMenu = [parentMenu itemWithTag: contentID]; - return [childMenu submenu]; -} - -void -BookmarksService::BookmarkAdded(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush) -{ - if (!gInstances || !gDictionary) - return; - - PRInt32 count = gInstances->Count(); - for (PRInt32 i = 0; i < count; i++) { - BookmarksService* instance = (BookmarksService*)gInstances->ElementAt(i); - - if (instance->mDataSource) { - // We're a tree view. - nsCOMPtr parent; - aContainer->GetParent(*getter_AddRefs(parent)); - - BookmarkItem* item = nil; - if (parent) - // We're not the root. - item = GetWrapperFor(aContainer); - - [(instance->mDataSource) reloadDataForItem: item reloadChildren: YES]; - } - else if (instance->mToolbar) { - // We're a personal toolbar. - nsCOMPtr parentElt(do_QueryInterface(aContainer)); - if (parentElt == gToolbarRoot) { - // We only care about changes that occur to the personal toolbar's immediate - // children. - PRInt32 index = -1; - aContainer->IndexOf(aChild, index); - nsCOMPtr elt(do_QueryInterface(aChild)); - [(instance->mToolbar) addButton: elt atIndex: index]; - } - } - else { - // We're the menu. - PRInt32 index = -1; - aContainer->IndexOf(aChild, index); - NSMenu* menu = LocateMenu(aContainer); - AddMenuBookmark(menu, aContainer, aChild, index); - } - } - - if (shouldFlush) - FlushBookmarks(); -} - -void -BookmarksService::BookmarkChanged(nsIContent* aItem, bool shouldFlush) -{ - if (!gInstances || !gDictionary) - return; - - PRInt32 count = gInstances->Count(); - for (PRInt32 i = 0; i < count; i++) { - BookmarksService* instance = (BookmarksService*)gInstances->ElementAt(i); - - if (instance->mDataSource) { - // We're a tree view - BookmarkItem* item = GetWrapperFor(aItem); - [(instance->mDataSource) reloadDataForItem: item reloadChildren: NO]; - } - else if (instance->mToolbar) { - // We're a personal toolbar. It'll figure out what to do. - nsCOMPtr elt(do_QueryInterface(aItem)); - [(instance->mToolbar) editButton: elt]; - } - else { - // We're the menu. Reset the title, in case it's changed. - nsCOMPtr parent; - aItem->GetParent(*getter_AddRefs(parent)); - NSMenu* menu = LocateMenu(parent); - PRUint32 contentID = 0; - aItem->GetContentID(&contentID); - NSMenuItem* childItem = [menu itemWithTag: contentID]; - nsAutoString name; - aItem->GetAttr(kNameSpaceID_None, gNameAtom, name); - NSString* bookmarkTitle = [[NSString stringWith_nsAString: name] stringByTruncatingTo:80 at:kTruncateAtMiddle]; - [childItem setTitle: bookmarkTitle]; - - // and reset the image - BookmarkItem* item = GetWrapperFor(aItem); - [childItem setImage: [item siteIcon]]; - } - - } - - if (shouldFlush) - FlushBookmarks(); -} - -void -BookmarksService::BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush) -{ - if (!gInstances) - return; - - PRInt32 count = gInstances->Count(); - for (PRInt32 i = 0; i < count; i++) { - BookmarksService* instance = (BookmarksService*)gInstances->ElementAt(i); - - if (instance->mDataSource) { - // We're a tree view. - nsCOMPtr parent; - aContainer->GetParent(*getter_AddRefs(parent)); - - BookmarkItem* item = nil; - if (parent) - // We're not the root. - item = GetWrapperFor(aContainer); - - [(instance->mDataSource) reloadDataForItem: item reloadChildren: YES]; - } - else if (instance->mToolbar) { - // We're a personal toolbar. - nsCOMPtr parentElt(do_QueryInterface(aContainer)); - if (parentElt == gToolbarRoot) { - // We only care about changes that occur to the personal toolbar's immediate - // children. - nsCOMPtr childElt(do_QueryInterface(aChild)); - [(instance->mToolbar) removeButton: childElt]; - } - } - else { - // We're the menu. - NSMenu* menu = LocateMenu(aContainer); - PRUint32 contentID = 0; - aChild->GetContentID(&contentID); - NSMenuItem* childItem = [menu itemWithTag: contentID]; - [menu removeItem: childItem]; - } - } - - if (shouldFlush) - FlushBookmarks(); -} - - -void -BookmarksService::AddBookmarkToFolder(nsString& aURL, nsString& aTitle, nsIDOMElement* aFolder, nsIDOMElement* aBeforeElt) -{ - // XXX if no folder provided, default to root folder - if (!aFolder) return; - - nsCOMPtr domDoc(do_QueryInterface(gBookmarks)); - nsCOMPtr elt; - domDoc->CreateElementNS(NS_LITERAL_STRING("http://chimera.mozdev.org/bookmarks/"), - NS_LITERAL_STRING("bookmark"), - getter_AddRefs(elt)); - - elt->SetAttribute(NS_LITERAL_STRING("name"), aTitle); - elt->SetAttribute(NS_LITERAL_STRING("href"), aURL); - - MoveBookmarkToFolder(elt, aFolder, aBeforeElt); -} - -void -BookmarksService::MoveBookmarkToFolder(nsIDOMElement* aBookmark, nsIDOMElement* aFolder, nsIDOMElement* aBeforeElt) -{ - if (!aBookmark || !aFolder) return; - - nsCOMPtr oldParent; - aBookmark->GetParentNode(getter_AddRefs(oldParent)); - - nsCOMPtr dummy; - if (oldParent) { - nsCOMPtr bookmarkNode = do_QueryInterface(aBookmark); - oldParent->RemoveChild(bookmarkNode, getter_AddRefs(dummy)); - } - - if (aBeforeElt) { - aFolder->InsertBefore(aBookmark, aBeforeElt, getter_AddRefs(dummy)); - } else { - aFolder->AppendChild(aBookmark, getter_AddRefs(dummy)); - } - - nsCOMPtr childContent(do_QueryInterface(aBookmark)); - nsCOMPtr parentContent(do_QueryInterface(aFolder)); - - if (oldParent) { - nsCOMPtr oldParentContent(do_QueryInterface(oldParent)); - BookmarkRemoved(oldParentContent, childContent); - } - - BookmarkAdded(parentContent, childContent); -} - -void -BookmarksService::DeleteBookmark(nsIDOMElement* aBookmark) -{ - if (!aBookmark) return; - - nsCOMPtr oldParent; - aBookmark->GetParentNode(getter_AddRefs(oldParent)); - - if (oldParent) { - nsCOMPtr dummy; - nsCOMPtr bookmarkNode = do_QueryInterface(aBookmark); - oldParent->RemoveChild(bookmarkNode, getter_AddRefs(dummy)); - - nsCOMPtr childContent(do_QueryInterface(aBookmark)); - nsCOMPtr oldParentContent(do_QueryInterface(oldParent)); - BookmarkRemoved(oldParentContent, childContent); - } -} - -static PRBool -CheckXMLDocumentParseSuccessful(nsIDOMDocument* inDOMDoc) -{ - nsCOMPtr docElement; - inDOMDoc->GetDocumentElement(getter_AddRefs(docElement)); - if (!docElement) - return PR_FALSE; - - nsCOMPtr tagName; - nsCOMPtr docContent = do_QueryInterface(docElement); - docContent->GetTag(*getter_AddRefs(tagName)); - - nsCOMPtr parserErrorAtom = do_GetAtom("parsererror"); - if (parserErrorAtom != tagName) - return PR_TRUE; - - return PR_FALSE; -} - -static PRBool -ValidateXMLDocument(nsIDOMDocument* inDOMDoc) -{ - if (!inDOMDoc) - return PR_FALSE; - - nsCOMPtr elt; - inDOMDoc->GetDocumentElement(getter_AddRefs(elt)); - if (!elt) - return PR_FALSE; - - nsCOMPtr domSerializer = do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID); - if (!domSerializer) - return PR_FALSE; - - nsXPIDLString encodedDocStr; - nsresult rv = domSerializer->SerializeToString(inDOMDoc, getter_Copies(encodedDocStr)); - if (NS_FAILED(rv)) - return PR_FALSE; - - nsCOMPtr domParser = do_CreateInstance(NS_DOMPARSER_CONTRACTID); - if (!domParser) - return PR_FALSE; - - nsCOMPtr newDomDoc; - domParser->ParseFromString(encodedDocStr.get(), "text/xml", getter_AddRefs(newDomDoc)); - if (newDomDoc) - return CheckXMLDocumentParseSuccessful(newDomDoc); - - return PR_FALSE; -} - -void -BookmarksService::ReadBookmarks() -{ - nsCOMPtr profileDirBookmarks; - NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profileDirBookmarks)); - profileDirBookmarks->Append(NS_LITERAL_STRING("bookmarks.xml")); - - PRBool fileExists = PR_FALSE; - profileDirBookmarks->Exists(&fileExists); - - // If the bookmarks file does not exist, copy from the defaults so we don't - // crash or anything dumb like that. - if (!fileExists) { - nsCOMPtr defaultBookmarksFile; - NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_50_DIR, getter_AddRefs(defaultBookmarksFile)); - defaultBookmarksFile->Append(NS_LITERAL_STRING("bookmarks.xml")); - - // XXX for some reason unknown to me, leaving this code in causes the program to crash - // with 'cannot dereference null COMPtr.' -#if I_WANT_TO_CRASH - PRBool defaultFileExists; - defaultBookmarksFile->Exists(&defaultFileExists); - if (defaultFileExists) - return; -#endif - - nsCOMPtr profileDirectory; - NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profileDirectory)); - - defaultBookmarksFile->CopyToNative(profileDirectory, NS_LITERAL_CSTRING("bookmarks.xml")); - } - - nsCAutoString bookmarksFileURL; - NS_GetURLSpecFromFile(profileDirBookmarks, bookmarksFileURL); - - nsCOMPtr uri; - NS_NewURI(getter_AddRefs(uri), bookmarksFileURL.get()); - - // XXX this is somewhat lame. we have no way of knowing whether or not the parse succeeded - // or failed. sigh. - // Actually, we do. We check for a root node. This relies on the XMLContentSink - // behaviour. - nsCOMPtr xblService(do_GetService("@mozilla.org/xbl;1")); - xblService->FetchSyncXMLDocument(uri, &gBookmarks); // addref here - - // test for a parser error. The XML parser replaces the document with one - // that has a node as the root. - nsCOMPtr bookmarksDOMDoc = do_QueryInterface(gBookmarks); - BOOL validPrefsFile = CheckXMLDocumentParseSuccessful(bookmarksDOMDoc); - - if (!validPrefsFile) { - // uh oh, parser error. Throw some UI - NSString *alert = NSLocalizedString(@"CorruptedBookmarksAlert",@""); - NSString *message = NSLocalizedString(@"CorruptedBookmarksMsg",@""); - NSString *okButton = NSLocalizedString(@"OKButtonText",@""); - NSRunAlertPanel(alert, message, okButton, nil, nil); - - // maybe we should read the default bookmarks here? - gBookmarksFileReadOK = PR_FALSE; - return; - } - - gBookmarksFileReadOK = PR_TRUE; - - nsCOMPtr rootNode; - GetRootContent(getter_AddRefs(rootNode)); - StripWhitespaceNodes(rootNode); -} - -void -BookmarksService::FlushBookmarks() -{ - // XXX we need to insert a mechanism here to ensure that we don't write corrupt - // bookmarks files (e.g. full disk, program crash, whatever), because our - // error handling in the parse stage is NON-EXISTENT. - // This is now partially handled by looking for a node at read time. - if (!gBookmarksFileReadOK) - return; - - nsCOMPtr bookmarksFile; - NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(bookmarksFile)); - bookmarksFile->Append(NS_LITERAL_STRING("bookmarks.xml")); - - nsCOMPtr outputStream; - NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), bookmarksFile); - - nsCOMPtr domDoc(do_QueryInterface(gBookmarks)); - - nsCOMPtr domSerializer(do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID)); - if (domSerializer) - domSerializer->SerializeToStream(domDoc, outputStream, nsnull); -} - -NSImage* -BookmarksService::CreateIconForBookmark(nsIDOMElement* aElement) -{ - nsCOMPtr tagName; - nsCOMPtr content = do_QueryInterface(aElement); - content->GetTag(*getter_AddRefs(tagName)); - - nsAutoString group; - content->GetAttr(kNameSpaceID_None, gGroupAtom, group); - if (!group.IsEmpty()) - return [NSImage imageNamed:@"groupbookmark"]; - - if (tagName == BookmarksService::gFolderAtom) - return [NSImage imageNamed:@"folder"]; - - // fire off a proxy icon load - if ([[CHPreferenceManager sharedInstance] getBooleanPref:"browser.chrome.site_icons" withSuccess:NULL]) - { - nsAutoString href; - content->GetAttr(kNameSpaceID_None, gHrefAtom, href); - if (href.Length() > 0) - { - BookmarkItem* contentItem = BookmarksService::GetWrapperFor(content); - if ([contentItem siteIcon]) - return [contentItem siteIcon]; - - if (contentItem && ![contentItem siteIcon]) - [[BookmarksManager sharedBookmarksManager] loadProxyImageFor:contentItem withURI:[NSString stringWith_nsAString:href]]; - } - } - - return [NSImage imageNamed:@"smallbookmark"]; -} - -void BookmarksService::EnsureToolbarRoot() -{ - if (gToolbarRoot) - return; - - nsCOMPtr domDoc(do_QueryInterface(gBookmarks)); - nsCOMPtr rootElt; - domDoc->GetDocumentElement(getter_AddRefs(rootElt)); - - nsCOMPtr child; - rootElt->GetFirstChild(getter_AddRefs(child)); - nsAutoString typeValue; - while (child) { - nsCOMPtr childElt(do_QueryInterface(child)); - if (childElt) { - childElt->GetAttribute(NS_LITERAL_STRING("type"), typeValue); - if (typeValue.Equals(NS_LITERAL_STRING("toolbar"))) - gToolbarRoot = childElt; - } - - nsCOMPtr temp; - child->GetNextSibling(getter_AddRefs(temp)); - child = temp; - } - - if (!gToolbarRoot) { - NSLog(@"Repairing personal toolbar"); - nsCOMPtr elt; - domDoc->CreateElementNS(NS_LITERAL_STRING("http://chimera.mozdev.org/bookmarks/"), - NS_LITERAL_STRING("folder"), - getter_AddRefs(elt)); - - elt->SetAttribute(NS_LITERAL_STRING("name"), NS_LITERAL_STRING("Toolbar Bookmarks")); - elt->SetAttribute(NS_LITERAL_STRING("type"), NS_LITERAL_STRING("toolbar")); - - nsCOMPtr dummy; - rootElt->AppendChild(elt, getter_AddRefs(dummy)); - gToolbarRoot = elt; - } -} - -static -void RecursiveAddBookmarkConstruct(NSPopUpButton* aPopup, NSMenu* aMenu, int aTagToMatch, int depth = 0) -{ - // Get the menu item children. - NSArray* children = [aMenu itemArray]; - int startPosition = 0; - if (aMenu == BookmarksService::gBookmarksMenu) - startPosition = 3; - - int count = [children count]; - for (int i = startPosition; i < count; ++i) { - NSMenuItem* menuItem = [children objectAtIndex: i]; - NSMenu* submenu = [menuItem submenu]; - if (submenu) { - // This is a folder. Add it to our list and then recur. Indent it - // the apropriate depth for readability in the menu. - NSMutableString *title = [NSMutableString stringWithString:[menuItem title]]; - for (int j = 0; j <= depth; ++j) - [title insertString:@" " atIndex: 0]; - - [aPopup addItemWithTitle: title]; - NSMenuItem* lastItem = [aPopup lastItem]; - if ([menuItem tag] == aTagToMatch) - [aPopup selectItem: lastItem]; - - [lastItem setTag: [menuItem tag]]; - RecursiveAddBookmarkConstruct(aPopup, submenu, aTagToMatch, depth+1); - } - } -} - -void -BookmarksService::ConstructAddBookmarkFolderList(NSPopUpButton* aPopup, BookmarkItem* aItem) -{ - [aPopup removeAllItems]; - [aPopup addItemWithTitle: [gBookmarksMenu title]]; - NSMenuItem* lastItem = [aPopup lastItem]; - [lastItem setTag: -1]; - int tag = -1; - if (aItem) { - nsIContent* content = [aItem contentNode]; - PRUint32 utag; - content->GetContentID(&utag); - tag = (int)utag; - } - RecursiveAddBookmarkConstruct(aPopup, gBookmarksMenu, tag); -} - -void -BookmarksService::GetTitleAndHrefForBrowserView(id aBrowserView, nsString& aTitle, nsString& aHref) -{ - nsCOMPtr webBrowser = getter_AddRefs([aBrowserView getWebBrowser]); - nsCOMPtr window; - webBrowser->GetContentDOMWindow(getter_AddRefs(window)); - nsCOMPtr htmlDoc; - window->GetDocument(getter_AddRefs(htmlDoc)); - nsCOMPtr pageDoc(do_QueryInterface(htmlDoc)); - - if (pageDoc) { - nsCOMPtr url; - pageDoc->GetDocumentURL(getter_AddRefs(url)); - nsCAutoString spec; - url->GetSpec(spec); - aHref.AssignWithConversion(spec.get()); - } - - nsCOMPtr htmlDocument(do_QueryInterface(htmlDoc)); - if (htmlDocument) - htmlDocument->GetTitle(aTitle); - if (aTitle.IsEmpty()) - aTitle = aHref; -} - -void -BookmarksService::ConstructBookmarksMenu(NSMenu* aMenu, nsIContent* aContent) -{ - nsCOMPtr content = aContent; - if (!content) { - GetRootContent(getter_AddRefs(content)); - GetWrapperFor(content); - gBookmarksMenu = aMenu; - } - - // Now walk our children, and for folders also recur into them. - PRInt32 childCount; - content->ChildCount(childCount); - - for (PRInt32 i = 0; i < childCount; i++) { - nsCOMPtr child; - content->ChildAt(i, *getter_AddRefs(child)); - AddMenuBookmark(aMenu, content, child, -1); - } -} - -void -BookmarksService::AddMenuBookmark(NSMenu* aMenu, nsIContent* aParent, nsIContent* aChild, PRInt32 aIndex) -{ - nsAutoString name; - aChild->GetAttr(kNameSpaceID_None, gNameAtom, name); - NSString* title = [[NSString stringWith_nsAString: name] stringByTruncatingTo:80 at:kTruncateAtMiddle]; - - // Create a menu or menu item for the child. - NSMenuItem* menuItem = [[[NSMenuItem alloc] initWithTitle: title action: NULL keyEquivalent: @""] autorelease]; - GetWrapperFor(aChild); - - if (aIndex == -1) - [aMenu addItem: menuItem]; - else { - PRInt32 insertIndex = aIndex; - if (aMenu == gBookmarksMenu) // take static menu items into account - insertIndex += [aMenu indexOfItemWithTag:kBookmarksDividerTag] + 1; - - [aMenu insertItem: menuItem atIndex: insertIndex]; - } - - nsCOMPtr tagName; - aChild->GetTag(*getter_AddRefs(tagName)); - - nsAutoString group; - aChild->GetAttr(kNameSpaceID_None, gGroupAtom, group); - - nsCOMPtr elt(do_QueryInterface(aChild)); - NSImage* menuItemImage = BookmarksService::CreateIconForBookmark(elt); - - if (group.IsEmpty() && tagName == gFolderAtom) { - NSMenu* menu = [[[NSMenu alloc] initWithTitle: title] autorelease]; - [aMenu setSubmenu: menu forItem: menuItem]; - [menu setAutoenablesItems: NO]; - [menuItem setImage: menuItemImage]; - ConstructBookmarksMenu(menu, aChild); - } - else { - if (group.IsEmpty()) - [menuItem setImage: menuItemImage]; - else - [menuItem setImage: menuItemImage]; - - [menuItem setTarget: gMainController]; - [menuItem setAction: @selector(openMenuBookmark:)]; - } - - PRUint32 contentID; - aChild->GetContentID(&contentID); - [menuItem setTag: contentID]; -} - -void -BookmarksService::OpenMenuBookmark(BrowserWindowController* aController, id aMenuItem) -{ - // Get the corresponding bookmark item. - BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: [aMenuItem tag]]]; - - // Get the content node. - nsIContent* content = [item contentNode]; - nsAutoString group; - content->GetAttr(kNameSpaceID_None, gGroupAtom, group); - if (!group.IsEmpty()) { - nsCOMPtr elt(do_QueryInterface([item contentNode])); - return OpenBookmarkGroup([aController getTabBrowser], elt); - } - - // Get the href attribute. This is the URL we want to load. - nsAutoString href; - content->GetAttr(kNameSpaceID_None, gHrefAtom, href); - if (href.IsEmpty()) - return; - - NSString* url = [NSString stringWith_nsAString: href]; - - // Now load the URL in the window. - [aController loadURL:url referrer:nil activate:YES]; -} - -static void GetImportTitle(nsIDOMElement* aSrc, nsString& aTitle) -{ - aTitle.Truncate(0); - nsCOMPtr curr; - aSrc->GetFirstChild(getter_AddRefs(curr)); - while (curr) { - nsCOMPtr charData(do_QueryInterface(curr)); - if (charData) { - nsAutoString data; - charData->GetData(data); - aTitle += data; - } - else { - // Handle Omniweb's nesting of inside

for its folders. - nsCOMPtr elt(do_QueryInterface(curr)); - if (elt) { - nsAutoString localName; - elt->GetLocalName(localName); - ToLowerCase(localName); - if (localName.Equals(NS_LITERAL_STRING("a"))) { - aTitle = NS_LITERAL_STRING(""); - return GetImportTitle(elt, aTitle); - } - } - } - - nsCOMPtr temp = curr; - temp->GetNextSibling(getter_AddRefs(curr)); - } -} - -// sniff for control chars, which are defined to be in the range U+0000 to U+001F and U+007F to U+009F. -static PRBool ContainsControlChars(const nsString& inString) -{ - PRUint16 *c = (PRUint16*)inString.get(); // be sure to get unsigned - - while (*c) - { - if ((*c <= 0x001F) || (*c >= 0x007F && *c <= 0x009F)) - return PR_TRUE; - c ++; - } - - return PR_FALSE; -} - -static void CleanControlChars(nsString& ioString) -{ - if (ContainsControlChars(ioString)) - { - // strip control chars here. this is inefficient, but does it matter? - NSString* cleanedTitle = [[NSString stringWith_nsAString: ioString] - stringByReplacingCharactersInSet:[NSCharacterSet controlCharacterSet] withString:@""]; - [cleanedTitle assignTo_nsAString:ioString]; - NSLog(@"Removed control characters from bookmark string '%@'", cleanedTitle); - } -} - -static void CreateBookmark(nsIDOMElement* aSrc, nsIDOMElement* aDst, - nsIDOMDocument* aDstDoc, PRBool aIsFolder, - nsIDOMElement** aResult) -{ - nsAutoString tagName(NS_LITERAL_STRING("bookmark")); - if (aIsFolder) - tagName = NS_LITERAL_STRING("folder"); - - aDstDoc->CreateElementNS(NS_LITERAL_STRING("http://chimera.mozdev.org/bookmarks/"), - tagName, - aResult); // Addref happens here. - - nsAutoString title; - GetImportTitle(aSrc, title); - CleanControlChars(title); - - (*aResult)->SetAttribute(NS_LITERAL_STRING("name"), title); - - if (!aIsFolder) { - nsAutoString href; - aSrc->GetAttribute(NS_LITERAL_STRING("href"), href); - CleanControlChars(href); - (*aResult)->SetAttribute(NS_LITERAL_STRING("href"), href); - } - - nsCOMPtr dummy; - aDst->AppendChild(*aResult, getter_AddRefs(dummy)); -} - -static void AddImportedBookmarks(nsIDOMElement* aSrc, nsIDOMElement* aDst, nsIDOMDocument* aDstDoc, - PRInt32& aBookmarksType) -{ - nsAutoString localName; - aSrc->GetLocalName(localName); - ToLowerCase(localName); - nsCOMPtr newBookmark; - if (localName.Equals(NS_LITERAL_STRING("bookmarkinfo"))) - aBookmarksType = 1; // Omniweb. - else if (localName.Equals(NS_LITERAL_STRING("dt"))) { - // We have found either a folder or a leaf. - nsCOMPtr curr; - aSrc->GetFirstChild(getter_AddRefs(curr)); - while (curr) { - nsCOMPtr childElt(do_QueryInterface(curr)); - if (childElt) { - childElt->GetLocalName(localName); - ToLowerCase(localName); - if (localName.Equals(NS_LITERAL_STRING("a"))) { - // Guaranteed to be a bookmark in IE. Could be either in Omniweb. - nsCOMPtr dummy; - CreateBookmark(childElt, aDst, aDstDoc, PR_FALSE, getter_AddRefs(dummy)); - } - // Ignore the H3 we encounter. This will be dealt with later. - } - nsCOMPtr temp = curr; - temp->GetNextSibling(getter_AddRefs(curr)); - } - } - else if (localName.Equals(NS_LITERAL_STRING("dl"))) { - // The children of a folder. Recur inside. - // Locate the parent to create the folder. - nsCOMPtr node; - aSrc->GetPreviousSibling(getter_AddRefs(node)); - nsCOMPtr folderElt(do_QueryInterface(node)); - if (folderElt) { - // Make sure it's an H3 folder in Mozilla and IE. In Mozilla it will probably have an ID. - PRBool hasID; - folderElt->HasAttribute(NS_LITERAL_STRING("ID"), &hasID); - if (aBookmarksType != 1) { - if (hasID) - aBookmarksType = 2; // Mozilla - else - aBookmarksType = 0; // IE - } - nsAutoString localName; - folderElt->GetLocalName(localName); - ToLowerCase(localName); - if (localName.Equals(NS_LITERAL_STRING("h3"))) - CreateBookmark(folderElt, aDst, aDstDoc, PR_TRUE, getter_AddRefs(newBookmark)); - } - if (!newBookmark) - newBookmark = aDst; - // Recur over all our children. - nsCOMPtr curr; - aSrc->GetFirstChild(getter_AddRefs(curr)); - while (curr) { - nsCOMPtr elt(do_QueryInterface(curr)); - if (elt) - AddImportedBookmarks(elt, newBookmark, aDstDoc, aBookmarksType); - nsCOMPtr temp = curr; - temp->GetNextSibling(getter_AddRefs(curr)); - } - } - else { - // Recur over all our children. - nsCOMPtr curr; - aSrc->GetFirstChild(getter_AddRefs(curr)); - while (curr) { - nsCOMPtr elt(do_QueryInterface(curr)); - if (elt) - AddImportedBookmarks(elt, aDst, aDstDoc, aBookmarksType); - nsCOMPtr temp = curr; - temp->GetNextSibling(getter_AddRefs(curr)); - } - } -} - - -void -BookmarksService::ImportBookmarks(nsIDOMHTMLDocument* aHTMLDoc) -{ - nsCOMPtr htmlDocRoot; - aHTMLDoc->GetDocumentElement(getter_AddRefs(htmlDocRoot)); - - nsCOMPtr bookmarksRoot; - nsCOMPtr bookmarksDOMDoc(do_QueryInterface(gBookmarks)); - bookmarksDOMDoc->GetDocumentElement(getter_AddRefs(bookmarksRoot)); - - nsCOMPtr dummy; - - // Create the root of the new bookmarks by hand. - nsCOMPtr importedRootElement; - bookmarksDOMDoc->CreateElementNS( NS_LITERAL_STRING("http://chimera.mozdev.org/bookmarks/"), - NS_LITERAL_STRING("folder"), - getter_AddRefs(importedRootElement)); - - // Now crawl through the file and look for
elements. They signify folders - // or leaves. - PRInt32 bookmarksType = 0; // Assume IE. - AddImportedBookmarks(htmlDocRoot, importedRootElement, bookmarksDOMDoc, bookmarksType); - - if (bookmarksType == 0) - importedRootElement->SetAttribute(NS_LITERAL_STRING("name"), NS_LITERAL_STRING("Internet Explorer Favorites")); - else if (bookmarksType == 1) - importedRootElement->SetAttribute(NS_LITERAL_STRING("name"), NS_LITERAL_STRING("Omniweb Favorites")); - else if (bookmarksType == 2) - importedRootElement->SetAttribute(NS_LITERAL_STRING("name"), NS_LITERAL_STRING("Mozilla/Netscape Favorites")); - - // now put the new child into the doc, and validate it - bookmarksRoot->AppendChild(importedRootElement, getter_AddRefs(dummy)); - - PRBool bookmarksGood = ValidateXMLDocument(bookmarksDOMDoc); - if (!bookmarksGood) { - // uh oh, parser error. Remove the new node, and then throw some UI - bookmarksRoot->RemoveChild(importedRootElement, getter_AddRefs(dummy)); - - NSString *alert = NSLocalizedString(@"ErrorImportingBookmarksAlert",@""); - NSString *message = NSLocalizedString(@"ErrorImportingBookmarksMsg",@""); - NSString *okButton = NSLocalizedString(@"OKButtonText",@""); - NSRunAlertPanel(alert, message, okButton, nil, nil); - return; - } - - // Now do a notification that the root Favorites folder got added. This - // will update all our views. - nsCOMPtr parentContent(do_QueryInterface(bookmarksRoot)); - nsCOMPtr childContent(do_QueryInterface(importedRootElement)); - -#if 0 - // XXX testing - if (gDictionary) - [gDictionary removeAllObjects]; -#endif - - // this will save the file - BookmarkAdded(parentContent, childContent, true /* flush */); -} - -void -BookmarksService::OpenBookmarkGroup(id aTabView, nsIDOMElement* aFolder) -{ - // We might conceivably have to make new tabs in order to load all - // the items in the group. - int currentIndex = 0; - int total = [aTabView numberOfTabViewItems]; - nsCOMPtr child; - aFolder->GetFirstChild(getter_AddRefs(child)); - while (child) { - nsCOMPtr elt(do_QueryInterface(child)); - if (elt) { - nsAutoString href; - elt->GetAttribute(NS_LITERAL_STRING("href"), href); - if (!href.IsEmpty()) { - NSString* url = [NSString stringWith_nsAString: href]; - BrowserTabViewItem* tabViewItem = nil; - if (currentIndex >= total) { - // We need to make a new tab. - // XXX this needs fixing to not max out the number of tabs in a browser window. - // See [BrowserWindowController newTabsAllowed]; - tabViewItem = [BrowserTabView makeNewTabItem]; - CHBrowserWrapper* newView = [[[CHBrowserWrapper alloc] initWithTab: tabViewItem andWindow: [aTabView window]] autorelease]; - [tabViewItem setLabel: NSLocalizedString(@"UntitledPageTitle", @"")]; - [tabViewItem setView: newView]; - [aTabView addTabViewItem: tabViewItem]; - } - else - tabViewItem = [aTabView tabViewItemAtIndex: currentIndex]; - - [[tabViewItem view] loadURI: url referrer:nil - flags: NSLoadFlagsNone activate:(currentIndex == 0)]; - } - } - - nsCOMPtr temp = child; - temp->GetNextSibling(getter_AddRefs(child)); - currentIndex++; - } - - // Select the first tab. - [aTabView selectTabViewItemAtIndex: 0]; -} - -NSString* -BookmarksService::ResolveKeyword(NSString* aKeyword) -{ - nsAutoString keyword; - [aKeyword assignTo_nsAString:keyword]; - - if (keyword.IsEmpty()) - return [NSString string]; - -#if DEBUG - NSLog(@"str = %s", keyword.get()); -#endif - - nsCOMPtr domDoc(do_QueryInterface(gBookmarks)); - nsCOMPtr elt; - domDoc->GetElementById(keyword, getter_AddRefs(elt)); - - nsCOMPtr content(do_QueryInterface(elt)); - nsAutoString url; - if (content) { - content->GetAttr(kNameSpaceID_None, gHrefAtom, url); - return [NSString stringWith_nsAString: url]; - } - return [NSString string]; -} - -// Is searchItem equal to bookmark or bookmark's parent, grandparent, etc? -BOOL -BookmarksService::DoAncestorsIncludeNode(BookmarkItem* bookmark, BookmarkItem* searchItem) -{ - nsCOMPtr search = [searchItem contentNode]; - nsCOMPtr current = [bookmark contentNode]; - nsCOMPtr root; - GetRootContent(getter_AddRefs(root)); - - // If the search item is the root node, return yes immediatly - if (search == root) - return YES; - - // for each ancestor - while (current) { - // If this is the root node we can't search farther, and there was no match - if (current == root) - return NO; - - // If the two nodes match, then the search term is an ancestor of the given bookmark - if (search == current) - return YES; - - // If a match wasn't found, set up the next node to compare - nsCOMPtr oldCurrent = current; - oldCurrent->GetParent(*getter_AddRefs(current)); - } - - return NO; -} - - -#ifdef FILTER_DESCENDANT_ON_DRAG -/* -this has been disabled because it is too slow, and can cause a large -delay when the user is dragging lots of items. this needs to get -fixed someday. - -It should filter out every node whose parent is also being dragged. -*/ - -NSArray* -BookmarksService::FilterOutDescendantsForDrag(NSArray* nodes) -{ - NSMutableArray *toDrag = [NSMutableArray arrayWithArray: nodes]; - unsigned int i = 0; - - while (i < [toDrag count]) { - BookmarkItem* item = [toDrag objectAtIndex: i]; - bool matchFound = false; - - for (unsigned int j = 0; j < [toDrag count] && matchFound == NO; j++) { - if (i != j) // Don't compare to self, will always match - matchFound = BookmarksService::DoAncestorsIncludeNode(item, [toDrag objectAtIndex: j]); - } - - // if a match was found, remove the node from the array - if (matchFound) - [toDrag removeObjectAtIndex: i]; - else - i++; - } - - return toDrag; -} -#endif - -bool -BookmarksService::IsBookmarkDropValid(BookmarkItem* proposedParent, int index, NSArray* draggedIDs) -{ - if ( !draggedIDs ) - return NO; - - NSMutableArray *draggedItems = [NSMutableArray arrayWithCapacity: [draggedIDs count]]; - BOOL toolbarRootMoving = NO; - - for (unsigned int i = 0; i < [draggedIDs count]; i++) { - NSNumber* contentID = [draggedIDs objectAtIndex: i]; - BookmarkItem* bookmarkItem = BookmarksService::GetWrapperFor([contentID unsignedIntValue]); - nsCOMPtr itemContent = [bookmarkItem contentNode]; - nsCOMPtr itemElement(do_QueryInterface(itemContent)); - - if (itemElement == BookmarksService::gToolbarRoot) - toolbarRootMoving = YES; - - if (bookmarkItem) - [draggedItems addObject: bookmarkItem]; - } - - // If we are being dropped into the top level, allow it - if ([proposedParent contentNode] == [BookmarksService::GetRootItem() contentNode]) - return true; - - // If we are not being dropped on the top level, and the toolbar root is being moved, disallow - if (toolbarRootMoving) - return false; - - // Make sure that we are not being dropped into one of our own children - // If the proposed parent, or any of it's ancestors matches one of the nodes being dragged - // then deny the drag. - - for (unsigned int i = 0; i < [draggedItems count]; i++) { - if (BookmarksService::DoAncestorsIncludeNode(proposedParent, [draggedItems objectAtIndex: i])) { - return false; - } - } - - return true; -} - - -bool -BookmarksService::PerformProxyDrop(BookmarkItem* parentItem, BookmarkItem* beforeItem, NSDictionary* data) -{ - if ( !data ) - return NO; - - nsCOMPtr parentElt; - parentElt = do_QueryInterface([parentItem contentNode]); - - nsCOMPtr beforeElt; - beforeElt = do_QueryInterface([beforeItem contentNode]); - - nsAutoString url; [[data objectForKey:@"url"] assignTo_nsAString:url]; - nsAutoString title; [[data objectForKey:@"title"] assignTo_nsAString:title]; - BookmarksService::AddBookmarkToFolder(url, title, parentElt, beforeElt); - return YES; -} - - -bool -BookmarksService::PerformBookmarkDrop(BookmarkItem* parent, int index, NSArray* draggedIDs) -{ - NSEnumerator *enumerator = [draggedIDs reverseObjectEnumerator]; - NSNumber *contentID; - - // for each item being dragged - while ( (contentID = [enumerator nextObject]) ) { - - // get dragged node - nsCOMPtr draggedNode = [GetWrapperFor([contentID unsignedIntValue]) contentNode]; - - // get the dragged nodes parent - nsCOMPtr draggedParent; - if (draggedNode) - draggedNode->GetParent(*getter_AddRefs(draggedParent)); - - // get the proposed parent - nsCOMPtr proposedParent = [parent contentNode]; - - PRInt32 existingIndex = 0; - if (draggedParent) - draggedParent->IndexOf(draggedNode, existingIndex); - - // if the deleted nodes parent and the proposed parents are equal - // and if the deleted point is earlier in the list than the inserted point - if (proposedParent == draggedParent && existingIndex < index) { - index--; // if so, move the inserted point up one to compensate - } - - // remove it from the tree - if (draggedNode != proposedParent) // paranoia. This should never happen - { - if (draggedParent) - draggedParent->RemoveChildAt(existingIndex, PR_TRUE); - BookmarkRemoved(draggedParent, draggedNode, false); - - // insert into new position - if (proposedParent) - proposedParent->InsertChildAt(draggedNode, index, PR_TRUE, PR_TRUE); - BookmarkAdded(proposedParent, draggedNode, false); - } - } - - FlushBookmarks(); - - return true; -} - -bool -BookmarksService::PerformURLDrop(BookmarkItem* parentItem, BookmarkItem* beforeItem, NSString* inTitle, NSString* inUrl) -{ - if ( !inUrl || [inUrl length] == 0 ) - return NO; - - nsCOMPtr parentElt; - parentElt = do_QueryInterface([parentItem contentNode]); - - nsCOMPtr beforeElt; - beforeElt = do_QueryInterface([beforeItem contentNode]); - - nsAutoString url; [inUrl assignTo_nsAString:url]; - nsAutoString title; [inTitle assignTo_nsAString:title]; - if (title.Length() == 0) - [inUrl assignTo_nsAString:title]; - - BookmarksService::AddBookmarkToFolder(url, title, parentElt, beforeElt); - return YES; -} - -#pragma mark - - -@interface BookmarksManager(Private) - -- (void)registerNotificationListener; -- (void)imageLoadedNotification:(NSNotification*)notification; - -@end - - -@implementation BookmarksManager - -+ (BookmarksManager*)sharedBookmarksManager; -{ - static BookmarksManager* sBookmarksManager = nil; - - if (!sBookmarksManager) - sBookmarksManager = [[BookmarksManager alloc] init]; - - return sBookmarksManager; -} - -- (id)init -{ - if ((self = [super init])) - { - [self registerNotificationListener]; - } - return self; -} - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; - [super dealloc]; -} - -- (void)loadProxyImageFor:(id)requestor withURI:(NSString*)inURIString -{ - [[SiteIconProvider sharedFavoriteIconProvider] loadFavoriteIcon:self - forURI:inURIString withUserData:requestor allowNetwork:NO]; -} - - -- (void)registerNotificationListener -{ - [[NSNotificationCenter defaultCenter] addObserver: self - selector: @selector(imageLoadedNotification:) - name: SiteIconLoadNotificationName - object: self]; - -} - -// callback for [[SiteIconProvider sharedFavoriteIconProvider] loadFavoriteIcon] -- (void)imageLoadedNotification:(NSNotification*)notification -{ - //NSLog(@"BookmarksManager imageLoadedNotification"); - NSDictionary* userInfo = [notification userInfo]; - if (userInfo) - { - id requestor = [userInfo objectForKey:SiteIconLoadUserDataKey]; // requestor is a BookmarkItem - NSImage* iconImage = [userInfo objectForKey:SiteIconLoadImageKey]; - - if (iconImage && [requestor isMemberOfClass:[BookmarkItem class]]) - { - [requestor setSiteIcon:iconImage]; - BookmarksService::BookmarkChanged([requestor contentNode], FALSE); - } - - } -} - - -@end - diff --git a/camino/src/bookmarks/BookmarksService.mm b/camino/src/bookmarks/BookmarksService.mm index 82e41be1c36..2f3b7c8d57a 100644 --- a/camino/src/bookmarks/BookmarksService.mm +++ b/camino/src/bookmarks/BookmarksService.mm @@ -453,7 +453,7 @@ BookmarksService::MoveBookmarkToFolder(nsIDOMElement* aBookmark, nsIDOMElement* void BookmarksService::DeleteBookmark(nsIDOMElement* aBookmark) { - if (!aBookmark) return; + if (!aBookmark || aBookmark == gToolbarRoot) return; nsCOMPtr oldParent; aBookmark->GetParentNode(getter_AddRefs(oldParent)); diff --git a/chimera/BookmarksService.mm b/chimera/BookmarksService.mm index 82e41be1c36..e69de29bb2d 100644 --- a/chimera/BookmarksService.mm +++ b/chimera/BookmarksService.mm @@ -1,1434 +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 "CHPreferenceManager.h" -#import "CHBrowserView.h" -#import "BookmarksService.h" -#import "BookmarksDataSource.h" -#import "BookmarkInfoController.h" -#import "BrowserTabView.h" -#import "SiteIconProvider.h" - -#include "nsCRT.h" -#include "nsString.h" -#include "nsIDocument.h" -#include "nsIContent.h" -#include "nsIAtom.h" -#include "nsITextContent.h" -#include "nsIDOMWindow.h" -#include "nsIDOMHTMLDocument.h" -#include "nsIDOMElement.h" -#include "nsIDOMCharacterData.h" -#include "nsIDOMParser.h" -#include "nsIDOMDocumentFragment.h" -#include "nsIPrefBranch.h" -#include "nsIFile.h" -#include "nsAppDirectoryServiceDefs.h" -#include "nsIXMLHttpRequest.h" -#include "nsIDOMSerializer.h" -#include "nsIDocumentEncoder.h" -#include "nsNetUtil.h" -#include "nsINamespaceManager.h" -#include "nsIXBLService.h" -#include "nsIWebBrowser.h" - - -// Helper for stripping whitespace -static void -StripWhitespaceNodes(nsIContent* aElement) -{ - PRInt32 childCount = 0; - 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 = PR_FALSE; - 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); - } -} - -// the tag of the separator after which to insert bookmarks menu items -// this tag must not conflict with content IDs (which are all >=0) -// and match the tab in the .nib -static const int kBookmarksDividerTag = -1; - - -PRUint32 BookmarksService::gRefCnt = 0; -nsIDocument* BookmarksService::gBookmarks = nsnull; -NSMutableDictionary* BookmarksService::gDictionary = nil; -MainController* BookmarksService::gMainController = nil; -NSMenu* BookmarksService::gBookmarksMenu = nil; -nsIDOMElement* BookmarksService::gToolbarRoot = nsnull; - -nsIAtom* BookmarksService::gBookmarkAtom = nsnull; -nsIAtom* BookmarksService::gDescriptionAtom = nsnull; -nsIAtom* BookmarksService::gFolderAtom = nsnull; -nsIAtom* BookmarksService::gGroupAtom = nsnull; -nsIAtom* BookmarksService::gHrefAtom = nsnull; -nsIAtom* BookmarksService::gKeywordAtom = nsnull; -nsIAtom* BookmarksService::gNameAtom = nsnull; -nsIAtom* BookmarksService::gOpenAtom = nsnull; - -nsVoidArray* BookmarksService::gInstances = nsnull; - -BOOL BookmarksService::gBookmarksFileReadOK = NO; - -int BookmarksService::CHInsertNone = 0; -int BookmarksService::CHInsertInto = 1; -int BookmarksService::CHInsertBefore = 2; -int BookmarksService::CHInsertAfter = 3; - -BookmarksService::BookmarksService(BookmarksDataSource* aDataSource) -{ - mDataSource = aDataSource; - mToolbar = nil; -} - -BookmarksService::BookmarksService(CHBookmarksToolbar* aToolbar) -{ - mDataSource = nil; - mToolbar = aToolbar; -} - -BookmarksService::~BookmarksService() -{ -} - -void -BookmarksService::AddObserver() -{ - gRefCnt++; - if (gRefCnt == 1) { - gBookmarkAtom = NS_NewAtom("bookmark"); - gFolderAtom = NS_NewAtom("folder"); - gNameAtom = NS_NewAtom("name"); - gHrefAtom = NS_NewAtom("href"); - gOpenAtom = NS_NewAtom("open"); - gKeywordAtom = NS_NewAtom("id"); - gDescriptionAtom = NS_NewAtom("description"); - gGroupAtom = NS_NewAtom("group"); - gInstances = new nsVoidArray(); - - ReadBookmarks(); - } - - gInstances->AppendElement(this); -} - -void -BookmarksService::RemoveObserver() -{ - if (gRefCnt == 0) - return; - - gInstances->RemoveElement(this); - - gRefCnt--; - if (gRefCnt == 0) { - // Flush Bookmarks before shutting down as some changes are not flushed when - // they are performed (folder open/closed) as writing a whole bookmark file for - // that type of operation seems excessive. - FlushBookmarks(); - - NS_IF_RELEASE(gBookmarks); - NS_RELEASE(gBookmarkAtom); - NS_RELEASE(gFolderAtom); - NS_RELEASE(gNameAtom); - NS_RELEASE(gHrefAtom); - NS_RELEASE(gOpenAtom); - [gDictionary release]; - } -} - -#pragma mark - - -void -BookmarksService::GetRootContent(nsIContent** aResult) -{ - *aResult = nsnull; - if (gBookmarks) { - nsCOMPtr domDoc(do_QueryInterface(gBookmarks)); - if (!domDoc) return; - - nsCOMPtr elt; - domDoc->GetDocumentElement(getter_AddRefs(elt)); - if (elt) - elt->QueryInterface(NS_GET_IID(nsIContent), (void**)aResult); // Addref happens here. - } -} - -BookmarkItem* -BookmarksService::GetRootItem() -{ - nsCOMPtr rootContent; - BookmarksService::GetRootContent(getter_AddRefs(rootContent)); - BookmarkItem* rootItem = BookmarksService::GetWrapperFor(rootContent); - return rootItem; -} - -BookmarkItem* -BookmarksService::GetWrapperFor(nsIContent* aContent) -{ - if ( !aContent ) - return nil; - - if (!gDictionary) - gDictionary = [[NSMutableDictionary alloc] initWithCapacity: 30]; - - PRUint32 contentID = 0; - aContent->GetContentID(&contentID); - - BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: contentID]]; - if (item) - return item; - - // Create an item. - item = [[BookmarkItem alloc] init]; // The dictionary retains us. - [item setContentNode: aContent]; - [gDictionary setObject: item forKey: [NSNumber numberWithInt: contentID]]; - [item release]; - return item; -} - -BookmarkItem* -BookmarksService::GetWrapperFor(PRUint32 contentID) -{ - BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithUnsignedInt: contentID]]; - return item; -} - -NSMenu* -BookmarksService::LocateMenu(nsIContent* aContent) -{ - nsCOMPtr parent; - aContent->GetParent(*getter_AddRefs(parent)); - if (!parent) { - return BookmarksService::gBookmarksMenu; - } - - NSMenu* parentMenu = LocateMenu(parent); - - PRUint32 contentID; - aContent->GetContentID(&contentID); - - NSMenuItem* childMenu = [parentMenu itemWithTag: contentID]; - return [childMenu submenu]; -} - -void -BookmarksService::BookmarkAdded(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush) -{ - if (!gInstances || !gDictionary) - return; - - PRInt32 count = gInstances->Count(); - for (PRInt32 i = 0; i < count; i++) { - BookmarksService* instance = (BookmarksService*)gInstances->ElementAt(i); - - if (instance->mDataSource) { - // We're a tree view. - nsCOMPtr parent; - aContainer->GetParent(*getter_AddRefs(parent)); - - BookmarkItem* item = nil; - if (parent) - // We're not the root. - item = GetWrapperFor(aContainer); - - [(instance->mDataSource) reloadDataForItem: item reloadChildren: YES]; - } - else if (instance->mToolbar) { - // We're a personal toolbar. - nsCOMPtr parentElt(do_QueryInterface(aContainer)); - if (parentElt == gToolbarRoot) { - // We only care about changes that occur to the personal toolbar's immediate - // children. - PRInt32 index = -1; - aContainer->IndexOf(aChild, index); - nsCOMPtr elt(do_QueryInterface(aChild)); - [(instance->mToolbar) addButton: elt atIndex: index]; - } - } - else { - // We're the menu. - PRInt32 index = -1; - aContainer->IndexOf(aChild, index); - NSMenu* menu = LocateMenu(aContainer); - AddMenuBookmark(menu, aContainer, aChild, index); - } - } - - if (shouldFlush) - FlushBookmarks(); -} - -void -BookmarksService::BookmarkChanged(nsIContent* aItem, bool shouldFlush) -{ - if (!gInstances || !gDictionary) - return; - - PRInt32 count = gInstances->Count(); - for (PRInt32 i = 0; i < count; i++) { - BookmarksService* instance = (BookmarksService*)gInstances->ElementAt(i); - - if (instance->mDataSource) { - // We're a tree view - BookmarkItem* item = GetWrapperFor(aItem); - [(instance->mDataSource) reloadDataForItem: item reloadChildren: NO]; - } - else if (instance->mToolbar) { - // We're a personal toolbar. It'll figure out what to do. - nsCOMPtr elt(do_QueryInterface(aItem)); - [(instance->mToolbar) editButton: elt]; - } - else { - // We're the menu. Reset the title, in case it's changed. - nsCOMPtr parent; - aItem->GetParent(*getter_AddRefs(parent)); - NSMenu* menu = LocateMenu(parent); - PRUint32 contentID = 0; - aItem->GetContentID(&contentID); - NSMenuItem* childItem = [menu itemWithTag: contentID]; - nsAutoString name; - aItem->GetAttr(kNameSpaceID_None, gNameAtom, name); - NSString* bookmarkTitle = [[NSString stringWith_nsAString: name] stringByTruncatingTo:80 at:kTruncateAtMiddle]; - [childItem setTitle: bookmarkTitle]; - - // and reset the image - BookmarkItem* item = GetWrapperFor(aItem); - [childItem setImage: [item siteIcon]]; - } - - } - - if (shouldFlush) - FlushBookmarks(); -} - -void -BookmarksService::BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush) -{ - if (!gInstances) - return; - - PRInt32 count = gInstances->Count(); - for (PRInt32 i = 0; i < count; i++) { - BookmarksService* instance = (BookmarksService*)gInstances->ElementAt(i); - - if (instance->mDataSource) { - // We're a tree view. - nsCOMPtr parent; - aContainer->GetParent(*getter_AddRefs(parent)); - - BookmarkItem* item = nil; - if (parent) - // We're not the root. - item = GetWrapperFor(aContainer); - - [(instance->mDataSource) reloadDataForItem: item reloadChildren: YES]; - } - else if (instance->mToolbar) { - // We're a personal toolbar. - nsCOMPtr parentElt(do_QueryInterface(aContainer)); - if (parentElt == gToolbarRoot) { - // We only care about changes that occur to the personal toolbar's immediate - // children. - nsCOMPtr childElt(do_QueryInterface(aChild)); - [(instance->mToolbar) removeButton: childElt]; - } - } - else { - // We're the menu. - NSMenu* menu = LocateMenu(aContainer); - PRUint32 contentID = 0; - aChild->GetContentID(&contentID); - NSMenuItem* childItem = [menu itemWithTag: contentID]; - [menu removeItem: childItem]; - } - } - - if (shouldFlush) - FlushBookmarks(); -} - - -void -BookmarksService::AddBookmarkToFolder(nsString& aURL, nsString& aTitle, nsIDOMElement* aFolder, nsIDOMElement* aBeforeElt) -{ - // XXX if no folder provided, default to root folder - if (!aFolder) return; - - nsCOMPtr domDoc(do_QueryInterface(gBookmarks)); - nsCOMPtr elt; - domDoc->CreateElementNS(NS_LITERAL_STRING("http://chimera.mozdev.org/bookmarks/"), - NS_LITERAL_STRING("bookmark"), - getter_AddRefs(elt)); - - elt->SetAttribute(NS_LITERAL_STRING("name"), aTitle); - elt->SetAttribute(NS_LITERAL_STRING("href"), aURL); - - MoveBookmarkToFolder(elt, aFolder, aBeforeElt); -} - -void -BookmarksService::MoveBookmarkToFolder(nsIDOMElement* aBookmark, nsIDOMElement* aFolder, nsIDOMElement* aBeforeElt) -{ - if (!aBookmark || !aFolder) return; - - nsCOMPtr oldParent; - aBookmark->GetParentNode(getter_AddRefs(oldParent)); - - nsCOMPtr dummy; - if (oldParent) { - nsCOMPtr bookmarkNode = do_QueryInterface(aBookmark); - oldParent->RemoveChild(bookmarkNode, getter_AddRefs(dummy)); - } - - if (aBeforeElt) { - aFolder->InsertBefore(aBookmark, aBeforeElt, getter_AddRefs(dummy)); - } else { - aFolder->AppendChild(aBookmark, getter_AddRefs(dummy)); - } - - nsCOMPtr childContent(do_QueryInterface(aBookmark)); - nsCOMPtr parentContent(do_QueryInterface(aFolder)); - - if (oldParent) { - nsCOMPtr oldParentContent(do_QueryInterface(oldParent)); - BookmarkRemoved(oldParentContent, childContent); - } - - BookmarkAdded(parentContent, childContent); -} - -void -BookmarksService::DeleteBookmark(nsIDOMElement* aBookmark) -{ - if (!aBookmark) return; - - nsCOMPtr oldParent; - aBookmark->GetParentNode(getter_AddRefs(oldParent)); - - if (oldParent) { - nsCOMPtr dummy; - nsCOMPtr bookmarkNode = do_QueryInterface(aBookmark); - oldParent->RemoveChild(bookmarkNode, getter_AddRefs(dummy)); - - nsCOMPtr childContent(do_QueryInterface(aBookmark)); - nsCOMPtr oldParentContent(do_QueryInterface(oldParent)); - BookmarkRemoved(oldParentContent, childContent); - } -} - -static PRBool -CheckXMLDocumentParseSuccessful(nsIDOMDocument* inDOMDoc) -{ - nsCOMPtr docElement; - inDOMDoc->GetDocumentElement(getter_AddRefs(docElement)); - if (!docElement) - return PR_FALSE; - - nsCOMPtr tagName; - nsCOMPtr docContent = do_QueryInterface(docElement); - docContent->GetTag(*getter_AddRefs(tagName)); - - nsCOMPtr parserErrorAtom = do_GetAtom("parsererror"); - if (parserErrorAtom != tagName) - return PR_TRUE; - - return PR_FALSE; -} - -static PRBool -ValidateXMLDocument(nsIDOMDocument* inDOMDoc) -{ - if (!inDOMDoc) - return PR_FALSE; - - nsCOMPtr elt; - inDOMDoc->GetDocumentElement(getter_AddRefs(elt)); - if (!elt) - return PR_FALSE; - - nsCOMPtr domSerializer = do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID); - if (!domSerializer) - return PR_FALSE; - - nsXPIDLString encodedDocStr; - nsresult rv = domSerializer->SerializeToString(inDOMDoc, getter_Copies(encodedDocStr)); - if (NS_FAILED(rv)) - return PR_FALSE; - - nsCOMPtr domParser = do_CreateInstance(NS_DOMPARSER_CONTRACTID); - if (!domParser) - return PR_FALSE; - - nsCOMPtr newDomDoc; - domParser->ParseFromString(encodedDocStr.get(), "text/xml", getter_AddRefs(newDomDoc)); - if (newDomDoc) - return CheckXMLDocumentParseSuccessful(newDomDoc); - - return PR_FALSE; -} - -void -BookmarksService::ReadBookmarks() -{ - nsCOMPtr profileDirBookmarks; - NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profileDirBookmarks)); - profileDirBookmarks->Append(NS_LITERAL_STRING("bookmarks.xml")); - - PRBool fileExists = PR_FALSE; - profileDirBookmarks->Exists(&fileExists); - - // If the bookmarks file does not exist, copy from the defaults so we don't - // crash or anything dumb like that. - if (!fileExists) { - nsCOMPtr defaultBookmarksFile; - NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_50_DIR, getter_AddRefs(defaultBookmarksFile)); - defaultBookmarksFile->Append(NS_LITERAL_STRING("bookmarks.xml")); - - // XXX for some reason unknown to me, leaving this code in causes the program to crash - // with 'cannot dereference null COMPtr.' -#if I_WANT_TO_CRASH - PRBool defaultFileExists; - defaultBookmarksFile->Exists(&defaultFileExists); - if (defaultFileExists) - return; -#endif - - nsCOMPtr profileDirectory; - NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profileDirectory)); - - defaultBookmarksFile->CopyToNative(profileDirectory, NS_LITERAL_CSTRING("bookmarks.xml")); - } - - nsCAutoString bookmarksFileURL; - NS_GetURLSpecFromFile(profileDirBookmarks, bookmarksFileURL); - - nsCOMPtr uri; - NS_NewURI(getter_AddRefs(uri), bookmarksFileURL.get()); - - // XXX this is somewhat lame. we have no way of knowing whether or not the parse succeeded - // or failed. sigh. - // Actually, we do. We check for a root node. This relies on the XMLContentSink - // behaviour. - nsCOMPtr xblService(do_GetService("@mozilla.org/xbl;1")); - xblService->FetchSyncXMLDocument(uri, &gBookmarks); // addref here - - // test for a parser error. The XML parser replaces the document with one - // that has a node as the root. - nsCOMPtr bookmarksDOMDoc = do_QueryInterface(gBookmarks); - BOOL validPrefsFile = CheckXMLDocumentParseSuccessful(bookmarksDOMDoc); - - if (!validPrefsFile) { - // uh oh, parser error. Throw some UI - NSString *alert = NSLocalizedString(@"CorruptedBookmarksAlert",@""); - NSString *message = NSLocalizedString(@"CorruptedBookmarksMsg",@""); - NSString *okButton = NSLocalizedString(@"OKButtonText",@""); - NSRunAlertPanel(alert, message, okButton, nil, nil); - - // maybe we should read the default bookmarks here? - gBookmarksFileReadOK = PR_FALSE; - return; - } - - gBookmarksFileReadOK = PR_TRUE; - - nsCOMPtr rootNode; - GetRootContent(getter_AddRefs(rootNode)); - StripWhitespaceNodes(rootNode); -} - -void -BookmarksService::FlushBookmarks() -{ - // XXX we need to insert a mechanism here to ensure that we don't write corrupt - // bookmarks files (e.g. full disk, program crash, whatever), because our - // error handling in the parse stage is NON-EXISTENT. - // This is now partially handled by looking for a node at read time. - if (!gBookmarksFileReadOK) - return; - - nsCOMPtr bookmarksFile; - NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(bookmarksFile)); - bookmarksFile->Append(NS_LITERAL_STRING("bookmarks.xml")); - - nsCOMPtr outputStream; - NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), bookmarksFile); - - nsCOMPtr domDoc(do_QueryInterface(gBookmarks)); - - nsCOMPtr domSerializer(do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID)); - if (domSerializer) - domSerializer->SerializeToStream(domDoc, outputStream, nsnull); -} - -NSImage* -BookmarksService::CreateIconForBookmark(nsIDOMElement* aElement) -{ - nsCOMPtr tagName; - nsCOMPtr content = do_QueryInterface(aElement); - content->GetTag(*getter_AddRefs(tagName)); - - nsAutoString group; - content->GetAttr(kNameSpaceID_None, gGroupAtom, group); - if (!group.IsEmpty()) - return [NSImage imageNamed:@"groupbookmark"]; - - if (tagName == BookmarksService::gFolderAtom) - return [NSImage imageNamed:@"folder"]; - - // fire off a proxy icon load - if ([[CHPreferenceManager sharedInstance] getBooleanPref:"browser.chrome.site_icons" withSuccess:NULL]) - { - nsAutoString href; - content->GetAttr(kNameSpaceID_None, gHrefAtom, href); - if (href.Length() > 0) - { - BookmarkItem* contentItem = BookmarksService::GetWrapperFor(content); - if ([contentItem siteIcon]) - return [contentItem siteIcon]; - - if (contentItem && ![contentItem siteIcon]) - [[BookmarksManager sharedBookmarksManager] loadProxyImageFor:contentItem withURI:[NSString stringWith_nsAString:href]]; - } - } - - return [NSImage imageNamed:@"smallbookmark"]; -} - -void BookmarksService::EnsureToolbarRoot() -{ - if (gToolbarRoot) - return; - - nsCOMPtr domDoc(do_QueryInterface(gBookmarks)); - nsCOMPtr rootElt; - domDoc->GetDocumentElement(getter_AddRefs(rootElt)); - - nsCOMPtr child; - rootElt->GetFirstChild(getter_AddRefs(child)); - nsAutoString typeValue; - while (child) { - nsCOMPtr childElt(do_QueryInterface(child)); - if (childElt) { - childElt->GetAttribute(NS_LITERAL_STRING("type"), typeValue); - if (typeValue.Equals(NS_LITERAL_STRING("toolbar"))) - gToolbarRoot = childElt; - } - - nsCOMPtr temp; - child->GetNextSibling(getter_AddRefs(temp)); - child = temp; - } - - if (!gToolbarRoot) { - NSLog(@"Repairing personal toolbar"); - nsCOMPtr elt; - domDoc->CreateElementNS(NS_LITERAL_STRING("http://chimera.mozdev.org/bookmarks/"), - NS_LITERAL_STRING("folder"), - getter_AddRefs(elt)); - - elt->SetAttribute(NS_LITERAL_STRING("name"), NS_LITERAL_STRING("Toolbar Bookmarks")); - elt->SetAttribute(NS_LITERAL_STRING("type"), NS_LITERAL_STRING("toolbar")); - - nsCOMPtr dummy; - rootElt->AppendChild(elt, getter_AddRefs(dummy)); - gToolbarRoot = elt; - } -} - -static -void RecursiveAddBookmarkConstruct(NSPopUpButton* aPopup, NSMenu* aMenu, int aTagToMatch, int depth = 0) -{ - // Get the menu item children. - NSArray* children = [aMenu itemArray]; - int startPosition = 0; - if (aMenu == BookmarksService::gBookmarksMenu) - startPosition = 3; - - int count = [children count]; - for (int i = startPosition; i < count; ++i) { - NSMenuItem* menuItem = [children objectAtIndex: i]; - NSMenu* submenu = [menuItem submenu]; - if (submenu) { - // This is a folder. Add it to our list and then recur. Indent it - // the apropriate depth for readability in the menu. - NSMutableString *title = [NSMutableString stringWithString:[menuItem title]]; - for (int j = 0; j <= depth; ++j) - [title insertString:@" " atIndex: 0]; - - [aPopup addItemWithTitle: title]; - NSMenuItem* lastItem = [aPopup lastItem]; - if ([menuItem tag] == aTagToMatch) - [aPopup selectItem: lastItem]; - - [lastItem setTag: [menuItem tag]]; - RecursiveAddBookmarkConstruct(aPopup, submenu, aTagToMatch, depth+1); - } - } -} - -void -BookmarksService::ConstructAddBookmarkFolderList(NSPopUpButton* aPopup, BookmarkItem* aItem) -{ - [aPopup removeAllItems]; - [aPopup addItemWithTitle: [gBookmarksMenu title]]; - NSMenuItem* lastItem = [aPopup lastItem]; - [lastItem setTag: -1]; - int tag = -1; - if (aItem) { - nsIContent* content = [aItem contentNode]; - PRUint32 utag; - content->GetContentID(&utag); - tag = (int)utag; - } - RecursiveAddBookmarkConstruct(aPopup, gBookmarksMenu, tag); -} - -void -BookmarksService::GetTitleAndHrefForBrowserView(id aBrowserView, nsString& aTitle, nsString& aHref) -{ - nsCOMPtr webBrowser = getter_AddRefs([aBrowserView getWebBrowser]); - nsCOMPtr window; - webBrowser->GetContentDOMWindow(getter_AddRefs(window)); - nsCOMPtr htmlDoc; - window->GetDocument(getter_AddRefs(htmlDoc)); - nsCOMPtr pageDoc(do_QueryInterface(htmlDoc)); - - if (pageDoc) { - nsCOMPtr url; - pageDoc->GetDocumentURL(getter_AddRefs(url)); - nsCAutoString spec; - url->GetSpec(spec); - aHref.AssignWithConversion(spec.get()); - } - - nsCOMPtr htmlDocument(do_QueryInterface(htmlDoc)); - if (htmlDocument) - htmlDocument->GetTitle(aTitle); - if (aTitle.IsEmpty()) - aTitle = aHref; -} - -void -BookmarksService::ConstructBookmarksMenu(NSMenu* aMenu, nsIContent* aContent) -{ - nsCOMPtr content = aContent; - if (!content) { - GetRootContent(getter_AddRefs(content)); - GetWrapperFor(content); - gBookmarksMenu = aMenu; - } - - // Now walk our children, and for folders also recur into them. - PRInt32 childCount; - content->ChildCount(childCount); - - for (PRInt32 i = 0; i < childCount; i++) { - nsCOMPtr child; - content->ChildAt(i, *getter_AddRefs(child)); - AddMenuBookmark(aMenu, content, child, -1); - } -} - -void -BookmarksService::AddMenuBookmark(NSMenu* aMenu, nsIContent* aParent, nsIContent* aChild, PRInt32 aIndex) -{ - nsAutoString name; - aChild->GetAttr(kNameSpaceID_None, gNameAtom, name); - NSString* title = [[NSString stringWith_nsAString: name] stringByTruncatingTo:80 at:kTruncateAtMiddle]; - - // Create a menu or menu item for the child. - NSMenuItem* menuItem = [[[NSMenuItem alloc] initWithTitle: title action: NULL keyEquivalent: @""] autorelease]; - GetWrapperFor(aChild); - - if (aIndex == -1) - [aMenu addItem: menuItem]; - else { - PRInt32 insertIndex = aIndex; - if (aMenu == gBookmarksMenu) // take static menu items into account - insertIndex += [aMenu indexOfItemWithTag:kBookmarksDividerTag] + 1; - - [aMenu insertItem: menuItem atIndex: insertIndex]; - } - - nsCOMPtr tagName; - aChild->GetTag(*getter_AddRefs(tagName)); - - nsAutoString group; - aChild->GetAttr(kNameSpaceID_None, gGroupAtom, group); - - nsCOMPtr elt(do_QueryInterface(aChild)); - NSImage* menuItemImage = BookmarksService::CreateIconForBookmark(elt); - - if (group.IsEmpty() && tagName == gFolderAtom) { - NSMenu* menu = [[[NSMenu alloc] initWithTitle: title] autorelease]; - [aMenu setSubmenu: menu forItem: menuItem]; - [menu setAutoenablesItems: NO]; - [menuItem setImage: menuItemImage]; - ConstructBookmarksMenu(menu, aChild); - } - else { - if (group.IsEmpty()) - [menuItem setImage: menuItemImage]; - else - [menuItem setImage: menuItemImage]; - - [menuItem setTarget: gMainController]; - [menuItem setAction: @selector(openMenuBookmark:)]; - } - - PRUint32 contentID; - aChild->GetContentID(&contentID); - [menuItem setTag: contentID]; -} - -void -BookmarksService::OpenMenuBookmark(BrowserWindowController* aController, id aMenuItem) -{ - // Get the corresponding bookmark item. - BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: [aMenuItem tag]]]; - - // Get the content node. - nsIContent* content = [item contentNode]; - nsAutoString group; - content->GetAttr(kNameSpaceID_None, gGroupAtom, group); - if (!group.IsEmpty()) { - nsCOMPtr elt(do_QueryInterface([item contentNode])); - return OpenBookmarkGroup([aController getTabBrowser], elt); - } - - // Get the href attribute. This is the URL we want to load. - nsAutoString href; - content->GetAttr(kNameSpaceID_None, gHrefAtom, href); - if (href.IsEmpty()) - return; - - NSString* url = [NSString stringWith_nsAString: href]; - - // Now load the URL in the window. - [aController loadURL:url referrer:nil activate:YES]; -} - -static void GetImportTitle(nsIDOMElement* aSrc, nsString& aTitle) -{ - aTitle.Truncate(0); - nsCOMPtr curr; - aSrc->GetFirstChild(getter_AddRefs(curr)); - while (curr) { - nsCOMPtr charData(do_QueryInterface(curr)); - if (charData) { - nsAutoString data; - charData->GetData(data); - aTitle += data; - } - else { - // Handle Omniweb's nesting of inside

for its folders. - nsCOMPtr elt(do_QueryInterface(curr)); - if (elt) { - nsAutoString localName; - elt->GetLocalName(localName); - ToLowerCase(localName); - if (localName.Equals(NS_LITERAL_STRING("a"))) { - aTitle = NS_LITERAL_STRING(""); - return GetImportTitle(elt, aTitle); - } - } - } - - nsCOMPtr temp = curr; - temp->GetNextSibling(getter_AddRefs(curr)); - } -} - -// sniff for control chars, which are defined to be in the range U+0000 to U+001F and U+007F to U+009F. -static PRBool ContainsControlChars(const nsString& inString) -{ - PRUint16 *c = (PRUint16*)inString.get(); // be sure to get unsigned - - while (*c) - { - if ((*c <= 0x001F) || (*c >= 0x007F && *c <= 0x009F)) - return PR_TRUE; - c ++; - } - - return PR_FALSE; -} - -static void CleanControlChars(nsString& ioString) -{ - if (ContainsControlChars(ioString)) - { - // strip control chars here. this is inefficient, but does it matter? - NSString* cleanedTitle = [[NSString stringWith_nsAString: ioString] - stringByReplacingCharactersInSet:[NSCharacterSet controlCharacterSet] withString:@""]; - [cleanedTitle assignTo_nsAString:ioString]; - NSLog(@"Removed control characters from bookmark string '%@'", cleanedTitle); - } -} - -static void CreateBookmark(nsIDOMElement* aSrc, nsIDOMElement* aDst, - nsIDOMDocument* aDstDoc, PRBool aIsFolder, - nsIDOMElement** aResult) -{ - nsAutoString tagName(NS_LITERAL_STRING("bookmark")); - if (aIsFolder) - tagName = NS_LITERAL_STRING("folder"); - - aDstDoc->CreateElementNS(NS_LITERAL_STRING("http://chimera.mozdev.org/bookmarks/"), - tagName, - aResult); // Addref happens here. - - nsAutoString title; - GetImportTitle(aSrc, title); - CleanControlChars(title); - - (*aResult)->SetAttribute(NS_LITERAL_STRING("name"), title); - - if (!aIsFolder) { - nsAutoString href; - aSrc->GetAttribute(NS_LITERAL_STRING("href"), href); - CleanControlChars(href); - (*aResult)->SetAttribute(NS_LITERAL_STRING("href"), href); - } - - nsCOMPtr dummy; - aDst->AppendChild(*aResult, getter_AddRefs(dummy)); -} - -static void AddImportedBookmarks(nsIDOMElement* aSrc, nsIDOMElement* aDst, nsIDOMDocument* aDstDoc, - PRInt32& aBookmarksType) -{ - nsAutoString localName; - aSrc->GetLocalName(localName); - ToLowerCase(localName); - nsCOMPtr newBookmark; - if (localName.Equals(NS_LITERAL_STRING("bookmarkinfo"))) - aBookmarksType = 1; // Omniweb. - else if (localName.Equals(NS_LITERAL_STRING("dt"))) { - // We have found either a folder or a leaf. - nsCOMPtr curr; - aSrc->GetFirstChild(getter_AddRefs(curr)); - while (curr) { - nsCOMPtr childElt(do_QueryInterface(curr)); - if (childElt) { - childElt->GetLocalName(localName); - ToLowerCase(localName); - if (localName.Equals(NS_LITERAL_STRING("a"))) { - // Guaranteed to be a bookmark in IE. Could be either in Omniweb. - nsCOMPtr dummy; - CreateBookmark(childElt, aDst, aDstDoc, PR_FALSE, getter_AddRefs(dummy)); - } - // Ignore the H3 we encounter. This will be dealt with later. - } - nsCOMPtr temp = curr; - temp->GetNextSibling(getter_AddRefs(curr)); - } - } - else if (localName.Equals(NS_LITERAL_STRING("dl"))) { - // The children of a folder. Recur inside. - // Locate the parent to create the folder. - nsCOMPtr node; - aSrc->GetPreviousSibling(getter_AddRefs(node)); - nsCOMPtr folderElt(do_QueryInterface(node)); - if (folderElt) { - // Make sure it's an H3 folder in Mozilla and IE. In Mozilla it will probably have an ID. - PRBool hasID; - folderElt->HasAttribute(NS_LITERAL_STRING("ID"), &hasID); - if (aBookmarksType != 1) { - if (hasID) - aBookmarksType = 2; // Mozilla - else - aBookmarksType = 0; // IE - } - nsAutoString localName; - folderElt->GetLocalName(localName); - ToLowerCase(localName); - if (localName.Equals(NS_LITERAL_STRING("h3"))) - CreateBookmark(folderElt, aDst, aDstDoc, PR_TRUE, getter_AddRefs(newBookmark)); - } - if (!newBookmark) - newBookmark = aDst; - // Recur over all our children. - nsCOMPtr curr; - aSrc->GetFirstChild(getter_AddRefs(curr)); - while (curr) { - nsCOMPtr elt(do_QueryInterface(curr)); - if (elt) - AddImportedBookmarks(elt, newBookmark, aDstDoc, aBookmarksType); - nsCOMPtr temp = curr; - temp->GetNextSibling(getter_AddRefs(curr)); - } - } - else { - // Recur over all our children. - nsCOMPtr curr; - aSrc->GetFirstChild(getter_AddRefs(curr)); - while (curr) { - nsCOMPtr elt(do_QueryInterface(curr)); - if (elt) - AddImportedBookmarks(elt, aDst, aDstDoc, aBookmarksType); - nsCOMPtr temp = curr; - temp->GetNextSibling(getter_AddRefs(curr)); - } - } -} - - -void -BookmarksService::ImportBookmarks(nsIDOMHTMLDocument* aHTMLDoc) -{ - nsCOMPtr htmlDocRoot; - aHTMLDoc->GetDocumentElement(getter_AddRefs(htmlDocRoot)); - - nsCOMPtr bookmarksRoot; - nsCOMPtr bookmarksDOMDoc(do_QueryInterface(gBookmarks)); - bookmarksDOMDoc->GetDocumentElement(getter_AddRefs(bookmarksRoot)); - - nsCOMPtr dummy; - - // Create the root of the new bookmarks by hand. - nsCOMPtr importedRootElement; - bookmarksDOMDoc->CreateElementNS( NS_LITERAL_STRING("http://chimera.mozdev.org/bookmarks/"), - NS_LITERAL_STRING("folder"), - getter_AddRefs(importedRootElement)); - - // Now crawl through the file and look for
elements. They signify folders - // or leaves. - PRInt32 bookmarksType = 0; // Assume IE. - AddImportedBookmarks(htmlDocRoot, importedRootElement, bookmarksDOMDoc, bookmarksType); - - if (bookmarksType == 0) - importedRootElement->SetAttribute(NS_LITERAL_STRING("name"), NS_LITERAL_STRING("Internet Explorer Favorites")); - else if (bookmarksType == 1) - importedRootElement->SetAttribute(NS_LITERAL_STRING("name"), NS_LITERAL_STRING("Omniweb Favorites")); - else if (bookmarksType == 2) - importedRootElement->SetAttribute(NS_LITERAL_STRING("name"), NS_LITERAL_STRING("Mozilla/Netscape Favorites")); - - // now put the new child into the doc, and validate it - bookmarksRoot->AppendChild(importedRootElement, getter_AddRefs(dummy)); - - PRBool bookmarksGood = ValidateXMLDocument(bookmarksDOMDoc); - if (!bookmarksGood) { - // uh oh, parser error. Remove the new node, and then throw some UI - bookmarksRoot->RemoveChild(importedRootElement, getter_AddRefs(dummy)); - - NSString *alert = NSLocalizedString(@"ErrorImportingBookmarksAlert",@""); - NSString *message = NSLocalizedString(@"ErrorImportingBookmarksMsg",@""); - NSString *okButton = NSLocalizedString(@"OKButtonText",@""); - NSRunAlertPanel(alert, message, okButton, nil, nil); - return; - } - - // Now do a notification that the root Favorites folder got added. This - // will update all our views. - nsCOMPtr parentContent(do_QueryInterface(bookmarksRoot)); - nsCOMPtr childContent(do_QueryInterface(importedRootElement)); - -#if 0 - // XXX testing - if (gDictionary) - [gDictionary removeAllObjects]; -#endif - - // this will save the file - BookmarkAdded(parentContent, childContent, true /* flush */); -} - -void -BookmarksService::OpenBookmarkGroup(id aTabView, nsIDOMElement* aFolder) -{ - // We might conceivably have to make new tabs in order to load all - // the items in the group. - int currentIndex = 0; - int total = [aTabView numberOfTabViewItems]; - nsCOMPtr child; - aFolder->GetFirstChild(getter_AddRefs(child)); - while (child) { - nsCOMPtr elt(do_QueryInterface(child)); - if (elt) { - nsAutoString href; - elt->GetAttribute(NS_LITERAL_STRING("href"), href); - if (!href.IsEmpty()) { - NSString* url = [NSString stringWith_nsAString: href]; - BrowserTabViewItem* tabViewItem = nil; - if (currentIndex >= total) { - // We need to make a new tab. - // XXX this needs fixing to not max out the number of tabs in a browser window. - // See [BrowserWindowController newTabsAllowed]; - tabViewItem = [BrowserTabView makeNewTabItem]; - CHBrowserWrapper* newView = [[[CHBrowserWrapper alloc] initWithTab: tabViewItem andWindow: [aTabView window]] autorelease]; - [tabViewItem setLabel: NSLocalizedString(@"UntitledPageTitle", @"")]; - [tabViewItem setView: newView]; - [aTabView addTabViewItem: tabViewItem]; - } - else - tabViewItem = [aTabView tabViewItemAtIndex: currentIndex]; - - [[tabViewItem view] loadURI: url referrer:nil - flags: NSLoadFlagsNone activate:(currentIndex == 0)]; - } - } - - nsCOMPtr temp = child; - temp->GetNextSibling(getter_AddRefs(child)); - currentIndex++; - } - - // Select the first tab. - [aTabView selectTabViewItemAtIndex: 0]; -} - -NSString* -BookmarksService::ResolveKeyword(NSString* aKeyword) -{ - nsAutoString keyword; - [aKeyword assignTo_nsAString:keyword]; - - if (keyword.IsEmpty()) - return [NSString string]; - -#if DEBUG - NSLog(@"str = %s", keyword.get()); -#endif - - nsCOMPtr domDoc(do_QueryInterface(gBookmarks)); - nsCOMPtr elt; - domDoc->GetElementById(keyword, getter_AddRefs(elt)); - - nsCOMPtr content(do_QueryInterface(elt)); - nsAutoString url; - if (content) { - content->GetAttr(kNameSpaceID_None, gHrefAtom, url); - return [NSString stringWith_nsAString: url]; - } - return [NSString string]; -} - -// Is searchItem equal to bookmark or bookmark's parent, grandparent, etc? -BOOL -BookmarksService::DoAncestorsIncludeNode(BookmarkItem* bookmark, BookmarkItem* searchItem) -{ - nsCOMPtr search = [searchItem contentNode]; - nsCOMPtr current = [bookmark contentNode]; - nsCOMPtr root; - GetRootContent(getter_AddRefs(root)); - - // If the search item is the root node, return yes immediatly - if (search == root) - return YES; - - // for each ancestor - while (current) { - // If this is the root node we can't search farther, and there was no match - if (current == root) - return NO; - - // If the two nodes match, then the search term is an ancestor of the given bookmark - if (search == current) - return YES; - - // If a match wasn't found, set up the next node to compare - nsCOMPtr oldCurrent = current; - oldCurrent->GetParent(*getter_AddRefs(current)); - } - - return NO; -} - - -#ifdef FILTER_DESCENDANT_ON_DRAG -/* -this has been disabled because it is too slow, and can cause a large -delay when the user is dragging lots of items. this needs to get -fixed someday. - -It should filter out every node whose parent is also being dragged. -*/ - -NSArray* -BookmarksService::FilterOutDescendantsForDrag(NSArray* nodes) -{ - NSMutableArray *toDrag = [NSMutableArray arrayWithArray: nodes]; - unsigned int i = 0; - - while (i < [toDrag count]) { - BookmarkItem* item = [toDrag objectAtIndex: i]; - bool matchFound = false; - - for (unsigned int j = 0; j < [toDrag count] && matchFound == NO; j++) { - if (i != j) // Don't compare to self, will always match - matchFound = BookmarksService::DoAncestorsIncludeNode(item, [toDrag objectAtIndex: j]); - } - - // if a match was found, remove the node from the array - if (matchFound) - [toDrag removeObjectAtIndex: i]; - else - i++; - } - - return toDrag; -} -#endif - -bool -BookmarksService::IsBookmarkDropValid(BookmarkItem* proposedParent, int index, NSArray* draggedIDs) -{ - if ( !draggedIDs ) - return NO; - - NSMutableArray *draggedItems = [NSMutableArray arrayWithCapacity: [draggedIDs count]]; - BOOL toolbarRootMoving = NO; - - for (unsigned int i = 0; i < [draggedIDs count]; i++) { - NSNumber* contentID = [draggedIDs objectAtIndex: i]; - BookmarkItem* bookmarkItem = BookmarksService::GetWrapperFor([contentID unsignedIntValue]); - nsCOMPtr itemContent = [bookmarkItem contentNode]; - nsCOMPtr itemElement(do_QueryInterface(itemContent)); - - if (itemElement == BookmarksService::gToolbarRoot) - toolbarRootMoving = YES; - - if (bookmarkItem) - [draggedItems addObject: bookmarkItem]; - } - - // If we are being dropped into the top level, allow it - if ([proposedParent contentNode] == [BookmarksService::GetRootItem() contentNode]) - return true; - - // If we are not being dropped on the top level, and the toolbar root is being moved, disallow - if (toolbarRootMoving) - return false; - - // Make sure that we are not being dropped into one of our own children - // If the proposed parent, or any of it's ancestors matches one of the nodes being dragged - // then deny the drag. - - for (unsigned int i = 0; i < [draggedItems count]; i++) { - if (BookmarksService::DoAncestorsIncludeNode(proposedParent, [draggedItems objectAtIndex: i])) { - return false; - } - } - - return true; -} - - -bool -BookmarksService::PerformProxyDrop(BookmarkItem* parentItem, BookmarkItem* beforeItem, NSDictionary* data) -{ - if ( !data ) - return NO; - - nsCOMPtr parentElt; - parentElt = do_QueryInterface([parentItem contentNode]); - - nsCOMPtr beforeElt; - beforeElt = do_QueryInterface([beforeItem contentNode]); - - nsAutoString url; [[data objectForKey:@"url"] assignTo_nsAString:url]; - nsAutoString title; [[data objectForKey:@"title"] assignTo_nsAString:title]; - BookmarksService::AddBookmarkToFolder(url, title, parentElt, beforeElt); - return YES; -} - - -bool -BookmarksService::PerformBookmarkDrop(BookmarkItem* parent, int index, NSArray* draggedIDs) -{ - NSEnumerator *enumerator = [draggedIDs reverseObjectEnumerator]; - NSNumber *contentID; - - // for each item being dragged - while ( (contentID = [enumerator nextObject]) ) { - - // get dragged node - nsCOMPtr draggedNode = [GetWrapperFor([contentID unsignedIntValue]) contentNode]; - - // get the dragged nodes parent - nsCOMPtr draggedParent; - if (draggedNode) - draggedNode->GetParent(*getter_AddRefs(draggedParent)); - - // get the proposed parent - nsCOMPtr proposedParent = [parent contentNode]; - - PRInt32 existingIndex = 0; - if (draggedParent) - draggedParent->IndexOf(draggedNode, existingIndex); - - // if the deleted nodes parent and the proposed parents are equal - // and if the deleted point is earlier in the list than the inserted point - if (proposedParent == draggedParent && existingIndex < index) { - index--; // if so, move the inserted point up one to compensate - } - - // remove it from the tree - if (draggedNode != proposedParent) // paranoia. This should never happen - { - if (draggedParent) - draggedParent->RemoveChildAt(existingIndex, PR_TRUE); - BookmarkRemoved(draggedParent, draggedNode, false); - - // insert into new position - if (proposedParent) - proposedParent->InsertChildAt(draggedNode, index, PR_TRUE, PR_TRUE); - BookmarkAdded(proposedParent, draggedNode, false); - } - } - - FlushBookmarks(); - - return true; -} - -bool -BookmarksService::PerformURLDrop(BookmarkItem* parentItem, BookmarkItem* beforeItem, NSString* inTitle, NSString* inUrl) -{ - if ( !inUrl || [inUrl length] == 0 ) - return NO; - - nsCOMPtr parentElt; - parentElt = do_QueryInterface([parentItem contentNode]); - - nsCOMPtr beforeElt; - beforeElt = do_QueryInterface([beforeItem contentNode]); - - nsAutoString url; [inUrl assignTo_nsAString:url]; - nsAutoString title; [inTitle assignTo_nsAString:title]; - if (title.Length() == 0) - [inUrl assignTo_nsAString:title]; - - BookmarksService::AddBookmarkToFolder(url, title, parentElt, beforeElt); - return YES; -} - -#pragma mark - - -@interface BookmarksManager(Private) - -- (void)registerNotificationListener; -- (void)imageLoadedNotification:(NSNotification*)notification; - -@end - - -@implementation BookmarksManager - -+ (BookmarksManager*)sharedBookmarksManager; -{ - static BookmarksManager* sBookmarksManager = nil; - - if (!sBookmarksManager) - sBookmarksManager = [[BookmarksManager alloc] init]; - - return sBookmarksManager; -} - -- (id)init -{ - if ((self = [super init])) - { - [self registerNotificationListener]; - } - return self; -} - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; - [super dealloc]; -} - -- (void)loadProxyImageFor:(id)requestor withURI:(NSString*)inURIString -{ - [[SiteIconProvider sharedFavoriteIconProvider] loadFavoriteIcon:self - forURI:inURIString withUserData:requestor allowNetwork:NO]; -} - - -- (void)registerNotificationListener -{ - [[NSNotificationCenter defaultCenter] addObserver: self - selector: @selector(imageLoadedNotification:) - name: SiteIconLoadNotificationName - object: self]; - -} - -// callback for [[SiteIconProvider sharedFavoriteIconProvider] loadFavoriteIcon] -- (void)imageLoadedNotification:(NSNotification*)notification -{ - //NSLog(@"BookmarksManager imageLoadedNotification"); - NSDictionary* userInfo = [notification userInfo]; - if (userInfo) - { - id requestor = [userInfo objectForKey:SiteIconLoadUserDataKey]; // requestor is a BookmarkItem - NSImage* iconImage = [userInfo objectForKey:SiteIconLoadImageKey]; - - if (iconImage && [requestor isMemberOfClass:[BookmarkItem class]]) - { - [requestor setSiteIcon:iconImage]; - BookmarksService::BookmarkChanged([requestor contentNode], FALSE); - } - - } -} - - -@end - diff --git a/chimera/src/bookmarks/BookmarksService.mm b/chimera/src/bookmarks/BookmarksService.mm index 82e41be1c36..2f3b7c8d57a 100644 --- a/chimera/src/bookmarks/BookmarksService.mm +++ b/chimera/src/bookmarks/BookmarksService.mm @@ -453,7 +453,7 @@ BookmarksService::MoveBookmarkToFolder(nsIDOMElement* aBookmark, nsIDOMElement* void BookmarksService::DeleteBookmark(nsIDOMElement* aBookmark) { - if (!aBookmark) return; + if (!aBookmark || aBookmark == gToolbarRoot) return; nsCOMPtr oldParent; aBookmark->GetParentNode(getter_AddRefs(oldParent));