File:  [mozdev] / chimera / BookmarksService.mm
Revision 1.21: download - view: text, annotated - select for diffs - revision graph
Wed Apr 17 07:38:31 2002 UTC (17 years, 7 months ago) by hyatt
Branches: MAIN
CVS tags: HEAD
New bookmark icon.  WOrking on the personal toolbar.

    1: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
    2: /* ***** BEGIN LICENSE BLOCK *****
    3:  * Version: NPL 1.1/GPL 2.0/LGPL 2.1
    4:  *
    5:  * The contents of this file are subject to the Netscape Public License
    6:  * Version 1.1 (the "License"); you may not use this file except in
    7:  * compliance with the License. You may obtain a copy of the License at
    8:  * http://www.mozilla.org/NPL/
    9:  *
   10:  * Software distributed under the License is distributed on an "AS IS" basis,
   11:  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
   12:  * for the specific language governing rights and limitations under the
   13:  * License.
   14:  *
   15:  * The Original Code is mozilla.org code.
   16:  *
   17:  * The Initial Developer of the Original Code is 
   18:  * Netscape Communications Corporation.
   19:  * Portions created by the Initial Developer are Copyright (C) 2002
   20:  * the Initial Developer. All Rights Reserved.
   21:  *
   22:  * Contributor(s):
   23:  *
   24:  * Alternatively, the contents of this file may be used under the terms of
   25:  * either the GNU General Public License Version 2 or later (the "GPL"), or 
   26:  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
   27:  * in which case the provisions of the GPL or the LGPL are applicable instead
   28:  * of those above. If you wish to allow use of your version of this file only
   29:  * under the terms of either the GPL or the LGPL, and not to allow others to
   30:  * use your version of this file under the terms of the NPL, indicate your
   31:  * decision by deleting the provisions above and replace them with the notice
   32:  * and other provisions required by the GPL or the LGPL. If you do not delete
   33:  * the provisions above, a recipient may use your version of this file under
   34:  * the terms of any one of the NPL, the GPL or the LGPL.
   35:  *
   36:  * ***** END LICENSE BLOCK ***** */
   37: 
   38: #import "NSBrowserView.h"
   39: #include "BookmarksService.h"
   40: #include "nsIDocument.h"
   41: #include "nsIContent.h"
   42: #include "nsIAtom.h"
   43: #include "nsITextContent.h"
   44: #include "nsIDOMWindow.h"
   45: #include "nsIDOMHTMLDocument.h"
   46: #include "nsIDOMElement.h"
   47: #include "nsString.h"
   48: #include "nsIFile.h"
   49: #include "nsAppDirectoryServiceDefs.h"
   50: #include "nsIXMLHttpRequest.h"
   51: #include "nsIDOMSerializer.h"
   52: #include "nsNetUtil.h"
   53: #include "nsINamespaceManager.h"
   54: #include "nsIXBLService.h"
   55: #include "nsIWebBrowser.h"
   56: 
   57: @implementation BookmarksDataSource
   58: 
   59: -(id) init
   60: {
   61:     [super init];
   62:     mBookmarks = nsnull;
   63:     mCachedParent = nsnull;
   64:     mCachedHref = nil;
   65:     return self;
   66: }
   67: 
   68: -(void) dealloc
   69: {
   70:   [super dealloc];
   71: }
   72: 
   73: -(void) windowClosing
   74: {
   75:   if (mBookmarks) {
   76:     mBookmarks->RemoveObserver();
   77:     delete mBookmarks;
   78:   }
   79: }
   80: 
   81: -(void) ensureBookmarks
   82: {
   83:     if (mBookmarks)
   84:         return;
   85:     
   86:     mBookmarks = new BookmarksService(self);
   87:     mBookmarks->AddObserver();
   88:     
   89:     [mOutlineView setTarget: self];
   90:     [mOutlineView setDoubleAction: @selector(openBookmark:)];
   91:     [mOutlineView reloadData];
   92: }
   93: 
   94: -(IBAction)addBookmark:(id)aSender
   95: {
   96:   [self addBookmark: aSender useSelection: YES];
   97: }
   98: 
   99: -(void)addBookmark:(id)aSender useSelection:(BOOL)aUseSel
  100: {
  101:   if (!mBookmarks)
  102:     return;
  103: 
  104:   nsCOMPtr<nsIContent> content;
  105:   if (aUseSel) {
  106:     int index = [mOutlineView selectedRow];
  107: 
  108:     if (index >= 0) {
  109:       BookmarkItem* item = [mOutlineView itemAtRow: index];
  110:       if ([mOutlineView isExpandable: item])
  111:         content = [item contentNode];
  112:     }
  113:   }
  114: 
  115:   if (!content)
  116:     mBookmarks->GetRootContent(getter_AddRefs(content));
  117: 
  118:   nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(mBookmarks->gBookmarks));
  119:   
  120:   // Fetch the title of the current page and the URL.
  121:   nsCOMPtr<nsIWebBrowser> webBrowser = getter_AddRefs([[[mBrowserWindowController getMyBrowserView] getBrowserView] getWebBrowser]);
  122:   nsCOMPtr<nsIDOMWindow> window;
  123:   webBrowser->GetContentDOMWindow(getter_AddRefs(window));
  124:   nsCOMPtr<nsIDOMDocument> htmlDoc;
  125:   window->GetDocument(getter_AddRefs(htmlDoc));
  126:   nsCOMPtr<nsIDocument> pageDoc(do_QueryInterface(htmlDoc));
  127: 
  128:   nsAutoString href;
  129:   if (pageDoc) {
  130:     nsCOMPtr<nsIURI> url;
  131:     pageDoc->GetDocumentURL(getter_AddRefs(url));
  132:     nsCAutoString spec;
  133:     url->GetSpec(spec);
  134:     href.AssignWithConversion(spec.get());
  135:   }
  136: 
  137:   mCachedHref = [NSString stringWithCharacters: href.get() length: nsCRT::strlen(href.get())];
  138:   [mCachedHref retain];
  139:   
  140:   mCachedParent = content;
  141:   
  142:   nsAutoString title;
  143:   nsCOMPtr<nsIDOMHTMLDocument> htmlDocument(do_QueryInterface(htmlDoc));
  144:   if (htmlDocument)
  145:     htmlDocument->GetTitle(title);
  146:   if (title.IsEmpty())
  147:     title = href;
  148:   
  149:   NSTextField* textField = [mBrowserWindowController getAddBookmarkTitle];
  150:   [textField setStringValue: [NSString stringWithCharacters: title.get() length: nsCRT::strlen(title.get())]];
  151: 
  152:   [mBrowserWindowController cacheBookmarkDS: self];
  153:   
  154:   [NSApp beginSheet:	[mBrowserWindowController getAddBookmarkSheetWindow]
  155:      modalForWindow:	[mBrowserWindowController window]
  156:       modalDelegate:	nil //self
  157:      didEndSelector:	nil //@selector(sheetDidEnd:)
  158:         contextInfo:	nil];
  159: }
  160: 
  161: -(void)endAddBookmark: (int)aCode
  162: {
  163:   if (aCode == 0)
  164:     return;
  165:   
  166:   const char* titleC = [[[mBrowserWindowController getAddBookmarkTitle] stringValue] cString];
  167:   nsAutoString title; title.AssignWithConversion(titleC);
  168: 
  169:   nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(mBookmarks->gBookmarks));
  170:   nsCOMPtr<nsIDOMElement> elt;
  171:   domDoc->CreateElementNS(NS_LITERAL_STRING("http://chimera.mozdev.org/bookmarks"),
  172:                           NS_LITERAL_STRING("bookmark"),
  173:                           getter_AddRefs(elt));
  174: 
  175:   elt->SetAttribute(NS_LITERAL_STRING("name"), title);
  176:   nsAutoString href; href.AssignWithConversion([mCachedHref cString]);
  177:   [mCachedHref release];
  178:   
  179:   elt->SetAttribute(NS_LITERAL_STRING("href"), href);
  180: 
  181:   nsCOMPtr<nsIDOMElement> parent(do_QueryInterface(mCachedParent));
  182:   nsCOMPtr<nsIDOMNode> dummy;
  183:   parent->AppendChild(elt, getter_AddRefs(dummy));
  184: 
  185:   nsCOMPtr<nsIContent> childContent(do_QueryInterface(elt));
  186:   mBookmarks->BookmarkAdded(mCachedParent, childContent);
  187: }
  188: 
  189: -(IBAction)deleteBookmark: (id)aSender
  190: {
  191:     if (!mBookmarks)
  192:         return;
  193:     
  194:     int index = [mOutlineView selectedRow];
  195:     if (index == -1)
  196:         return;
  197:         
  198:     BookmarkItem* item = [mOutlineView itemAtRow: index];
  199:     nsCOMPtr<nsIContent> content = [item contentNode];
  200:     nsCOMPtr<nsIDOMElement> child(do_QueryInterface(content));
  201:     nsCOMPtr<nsIDOMNode> parent;
  202:     child->GetParentNode(getter_AddRefs(parent));
  203:     nsCOMPtr<nsIContent> parentContent(do_QueryInterface(parent));
  204:     nsCOMPtr<nsIDOMNode> dummy;
  205:     parent->RemoveChild(child, getter_AddRefs(dummy));
  206:     mBookmarks->BookmarkRemoved(parentContent, content);
  207:     
  208:     int total = [mOutlineView numberOfRows];
  209:     if (index == total)
  210:         index--;
  211:         
  212:     [mOutlineView selectRow: index byExtendingSelection: NO];
  213: }
  214: 
  215: -(IBAction)openBookmark: (id)aSender
  216: {
  217:     int index = [mOutlineView selectedRow];
  218:     if (index == -1)
  219:         return;
  220:     
  221:     id item = [mOutlineView itemAtRow: index];
  222:     if (!item)
  223:         return;
  224:         
  225:     if ([mOutlineView isExpandable: item]) {
  226:         if ([mOutlineView isItemExpanded: item])
  227:             [mOutlineView collapseItem: item];
  228:         else
  229:             [mOutlineView expandItem: item];
  230:     }
  231:     else {
  232:         nsIContent* content = [item contentNode];
  233:         nsAutoString href;
  234:         content->GetAttr(kNameSpaceID_None, BookmarksService::gHrefAtom, href);
  235:         if (!href.IsEmpty()) {
  236:             nsCAutoString cstr; cstr.AssignWithConversion(href);
  237:             NSString* url = [NSString stringWithCString: cstr.get()];
  238:             [[[mBrowserWindowController getMyBrowserView] getBrowserView] loadURI:[NSURL URLWithString: url] flags:NSLoadFlagsNone];
  239:             // Focus and activate our content area.
  240:             [[[mBrowserWindowController getMyBrowserView] getBrowserView] setActive: YES];
  241:         }
  242:     } 
  243: }
  244: 
  245: - (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
  246: {
  247:     return NO;
  248: }
  249: 
  250: - (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
  251: {
  252:     if (!mBookmarks)
  253:         return nil;
  254:        
  255:     nsCOMPtr<nsIContent> content;
  256:     if (!item)
  257:         mBookmarks->GetRootContent(getter_AddRefs(content));
  258:     else
  259:         content = [item contentNode];
  260:     
  261:     nsCOMPtr<nsIContent> child;
  262:     content->ChildAt(index, *getter_AddRefs(child));
  263:     return mBookmarks->GetWrapperFor(child);
  264: }
  265: 
  266: - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
  267: {
  268:     if (!mBookmarks)
  269:         return NO;
  270:     
  271:     if (!item)
  272:         return YES; // The root node is always open.
  273:     
  274:     nsCOMPtr<nsIAtom> tagName;
  275:     nsIContent* content = [item contentNode];
  276:     content->GetTag(*getter_AddRefs(tagName));
  277:     
  278:     return (tagName == BookmarksService::gFolderAtom);
  279: }
  280: 
  281: - (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
  282: {
  283:     if (!mBookmarks)
  284:         return 0;
  285:   
  286:     nsCOMPtr<nsIContent> content;
  287:     if (!item)
  288:         mBookmarks->GetRootContent(getter_AddRefs(content));
  289:     else 
  290:         content = [item contentNode];
  291:     
  292:     PRInt32 childCount;
  293:     content->ChildCount(childCount);
  294:     
  295:     return childCount;
  296: }
  297: 
  298: - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
  299: {
  300:     NSString 					*columnName = [tableColumn identifier];
  301:     NSMutableAttributedString 	*cellValue = [[NSMutableAttributedString alloc] init];
  302:     NSFileWrapper				*fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:nil];
  303:     NSTextAttachment			*textAttachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper];
  304:     NSMutableAttributedString   *attachmentAttrString = nil;
  305:     NSCell 						*attachmentAttrStringCell;
  306: 
  307:     if ([columnName isEqualToString: @"name"]) {
  308:         nsIContent* content = [item contentNode];
  309:         nsAutoString nameAttr;
  310:         content->GetAttr(kNameSpaceID_None, BookmarksService::gNameAtom, nameAttr);
  311:         nsCAutoString cStr; cStr.AssignWithConversion(nameAttr);
  312:         
  313:         //Set cell's textual contents
  314:         [cellValue replaceCharactersInRange:NSMakeRange(0, [cellValue length])
  315:                                  withString:[NSString stringWithCString: cStr.get()]];
  316:         
  317:         //Create an attributed string to hold the empty attachment, then release the components.
  318:         attachmentAttrString = [[NSMutableAttributedString attributedStringWithAttachment:textAttachment] retain];
  319:         [textAttachment release];
  320:         [fileWrapper release];
  321: 
  322:         //Get the cell of the text attachment.
  323:         attachmentAttrStringCell = (NSCell *)[(NSTextAttachment *)[attachmentAttrString attribute:NSAttachmentAttributeName
  324:                                                                                           atIndex:0
  325:                                                                                    effectiveRange:nil] attachmentCell];
  326:         //Figure out which image to add, and set the cell's image.
  327:         if ( [self outlineView:outlineView isItemExpandable:item] ) {
  328:             [attachmentAttrStringCell setImage:[NSImage imageNamed:@"folder"]];
  329:         } else {
  330:             [attachmentAttrStringCell setImage:[NSImage imageNamed:@"smallbookmark"]];
  331:         }
  332:         //Insert the image
  333:         [cellValue replaceCharactersInRange:NSMakeRange(0, 0) withAttributedString:attachmentAttrString];
  334:         
  335:         //Tweak the baseline to vertically center the text.
  336:         [cellValue addAttribute:NSBaselineOffsetAttributeName
  337:                           value:[NSNumber numberWithFloat:-3.0]
  338:                           range:NSMakeRange(0, 1)];
  339:     }
  340:     return cellValue;
  341: }
  342: 
  343: - (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
  344: {
  345: }
  346: 
  347: - (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren
  348: {
  349:     printf("Reloading?\n");
  350:     if (!item)
  351:         [mOutlineView reloadData];
  352:     else if ([mOutlineView isItemExpanded: item])
  353:         [mOutlineView reloadItem: item reloadChildren: aReloadChildren];
  354: }
  355: 
  356: @end
  357: 
  358: @implementation BookmarkItem
  359: -(nsIContent*)contentNode
  360: {
  361:     return mContentNode;
  362: }
  363: 
  364: -(void)setContentNode: (nsIContent*)aContentNode
  365: {
  366:     mContentNode = aContentNode;
  367: }
  368: 
  369: - (id)copyWithZone:(NSZone *)aZone
  370: {
  371:     BookmarkItem* copy = [[[self class] allocWithZone: aZone] init];
  372:     [copy setContentNode: mContentNode];
  373:     return copy;
  374: }
  375: 
  376: @end
  377: 
  378: // Helper for stripping whitespace
  379: static void
  380: StripWhitespaceNodes(nsIContent* aElement)
  381: {
  382:     PRInt32 childCount;
  383:     aElement->ChildCount(childCount);
  384:     for (PRInt32 i = 0; i < childCount; i++) {
  385:         nsCOMPtr<nsIContent> child;
  386:         aElement->ChildAt(i, *getter_AddRefs(child));
  387:         nsCOMPtr<nsITextContent> text = do_QueryInterface(child);
  388:         if (text) {
  389:             PRBool isEmpty;
  390:             text->IsOnlyWhitespace(&isEmpty);
  391:             if (isEmpty) {
  392:                 // This node contained nothing but whitespace.
  393:                 // Remove it from the content model.
  394:                 aElement->RemoveChildAt(i, PR_TRUE);
  395:                 i--; // Decrement our count, since we just removed this child.
  396:                 childCount--; // Also decrement our total count.
  397:             }
  398:         }
  399:         else StripWhitespaceNodes(child);
  400:     }
  401: }
  402: 
  403: PRUint32 BookmarksService::gRefCnt = 0;
  404: nsIDocument* BookmarksService::gBookmarks = nsnull;
  405: NSMutableDictionary* BookmarksService::gDictionary = nil;
  406: MainController* BookmarksService::gMainController = nil;
  407: NSMenu* BookmarksService::gBookmarksMenu = nil;
  408: nsIAtom* BookmarksService::gFolderAtom = nsnull;
  409: nsIAtom* BookmarksService::gBookmarkAtom = nsnull;
  410: nsIAtom* BookmarksService::gHrefAtom = nsnull;
  411: nsIAtom* BookmarksService::gNameAtom = nsnull;
  412: nsVoidArray* BookmarksService::gInstances = nsnull;
  413: 
  414: BookmarksService::BookmarksService(BookmarksDataSource* aDataSource)
  415: {
  416:   mDataSource = aDataSource;
  417:   mToolbar = nil;
  418: }
  419: 
  420: BookmarksService::BookmarksService(BookmarksToolbar* aToolbar)
  421: {
  422:   mDataSource = nil;
  423:   mToolbar = aToolbar;
  424: }
  425: 
  426: BookmarksService::~BookmarksService()
  427: {
  428: }
  429: 
  430: void
  431: BookmarksService::GetRootContent(nsIContent** aResult)
  432: {
  433:     *aResult = nsnull;
  434:     if (gBookmarks) {
  435:         nsCOMPtr<nsIDOMElement> elt;
  436:         nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
  437:         domDoc->GetDocumentElement(getter_AddRefs(elt));
  438:         elt->QueryInterface(NS_GET_IID(nsIContent), (void**)aResult); // Addref happens here.
  439:     }
  440: }
  441: 
  442: BookmarkItem*
  443: BookmarksService::GetWrapperFor(nsIContent* aContent)
  444: {
  445:     if (!gDictionary)
  446:         gDictionary = [[NSMutableDictionary alloc] initWithCapacity: 30];
  447:     
  448:     PRUint32 contentID;
  449:     aContent->GetContentID(&contentID);
  450:     
  451:     BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: contentID]];
  452:     if (item)
  453:         return item;
  454:     else {
  455:         // Create an item.
  456:         item = [[[BookmarkItem alloc] init] autorelease]; // The dictionary retains us.
  457:         [item setContentNode: aContent];
  458:         [gDictionary setObject: item forKey: [NSNumber numberWithInt: contentID]];
  459:     }
  460:     return item;
  461: }
  462: 
  463: NSMenu*
  464: BookmarksService::LocateMenu(nsIContent* aContent)
  465: {
  466:   nsCOMPtr<nsIContent> parent;
  467:   aContent->GetParent(*getter_AddRefs(parent));
  468:   if (!parent)
  469:     return BookmarksService::gBookmarksMenu;
  470: 
  471:   NSMenu* parentMenu = LocateMenu(parent);
  472:   
  473:   PRUint32 contentID;
  474:   aContent->GetContentID(&contentID);
  475: 
  476:   NSMenuItem* childMenu = [parentMenu itemWithTag: contentID];
  477:   return [childMenu menu];
  478: }
  479: 
  480: void
  481: BookmarksService::BookmarkAdded(nsIContent* aContainer, nsIContent* aChild)
  482: {
  483:   if (!gInstances || !gDictionary)
  484:     return;
  485: 
  486:   PRInt32 count = gInstances->Count();
  487:   for (PRInt32 i = 0; i < count; i++) {
  488:     BookmarksService* instance = (BookmarksService*)gInstances->ElementAt(i);
  489: 
  490:     if (instance->mDataSource) {
  491:       // We're a tree view.
  492:       nsCOMPtr<nsIContent> parent;
  493:       aContainer->GetParent(*getter_AddRefs(parent));
  494: 
  495:       BookmarkItem* item = nil;
  496:       if (parent)
  497:         // We're not the root.
  498:         item = GetWrapperFor(aContainer);
  499: 
  500:       [(instance->mDataSource) reloadDataForItem: item reloadChildren: YES];
  501:     }
  502:     else {
  503:       // We're the menu.
  504:       PRInt32 index = -1;
  505:       aChild->IndexOf(aContainer, index);
  506:       NSMenu* menu = LocateMenu(aContainer);
  507:       AddMenuBookmark(menu, aContainer, aChild, index);
  508:     }
  509:   }
  510:   
  511:   FlushBookmarks();  
  512: }
  513: 
  514: void
  515: BookmarksService::BookmarkChanged(nsIContent* aItem)
  516: {
  517:   if (!gInstances || !gDictionary)
  518:     return;
  519: 
  520:   PRInt32 count = gInstances->Count();
  521:   for (PRInt32 i = 0; i < count; i++) {
  522:     BookmarksService* instance = (BookmarksService*)gInstances->ElementAt(i);
  523:    
  524:     if (instance->mDataSource) {
  525:       BookmarkItem* item = GetWrapperFor(aItem);
  526:       [(instance->mDataSource) reloadDataForItem: item reloadChildren: NO];
  527:     }
  528:   }
  529: 
  530:   FlushBookmarks();  
  531: }
  532: 
  533: void
  534: BookmarksService::BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild)
  535: {
  536:   if (!gInstances)
  537:     return;
  538: 
  539:   PRInt32 count = gInstances->Count();
  540:   for (PRInt32 i = 0; i < count; i++) {
  541:     BookmarksService* instance = (BookmarksService*)gInstances->ElementAt(i);
  542: 
  543:     if (instance->mDataSource) {
  544:       // We're a tree view.
  545:       nsCOMPtr<nsIContent> parent;
  546:       aContainer->GetParent(*getter_AddRefs(parent));
  547: 
  548:       BookmarkItem* item = nil;
  549:       if (parent)
  550:         // We're not the root.
  551:         item = GetWrapperFor(aContainer);
  552: 
  553:       [(instance->mDataSource) reloadDataForItem: item reloadChildren: YES];
  554:     }
  555:     else {
  556:       // We're the menu.
  557:       NSMenu* menu = LocateMenu(aContainer);
  558:       PRUint32 contentID;
  559:       aChild->GetContentID(&contentID);
  560:       NSMenuItem* childItem = [menu itemWithTag: contentID];
  561:       [menu removeItem: childItem];
  562:     }
  563:   }
  564: 
  565:   FlushBookmarks(); 
  566: }
  567: 
  568: void
  569: BookmarksService::AddObserver()
  570: {
  571:     gRefCnt++;
  572:     if (gRefCnt == 1) {
  573:         gBookmarkAtom = NS_NewAtom("bookmark");
  574:         gFolderAtom = NS_NewAtom("folder");
  575:         gNameAtom = NS_NewAtom("name");
  576:         gHrefAtom = NS_NewAtom("href");
  577:         gInstances = new nsVoidArray();
  578:                 
  579:         nsCOMPtr<nsIFile> profileDir;
  580:         NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profileDir));
  581:         profileDir->Append("bookmarks.xml");
  582:     
  583:         nsCAutoString bookmarksFileURL;
  584:         NS_GetURLSpecFromFile(profileDir, bookmarksFileURL);
  585:         
  586:         nsCOMPtr<nsIURI> uri;
  587:         NS_NewURI(getter_AddRefs(uri), bookmarksFileURL.get());
  588:     
  589:         nsCOMPtr<nsIXBLService> xblService(do_GetService("@mozilla.org/xbl;1"));    
  590:         xblService->FetchSyncXMLDocument(uri, &gBookmarks); // The addref is here.
  591:         
  592:         nsCOMPtr<nsIContent> rootNode;
  593:         GetRootContent(getter_AddRefs(rootNode));
  594:         StripWhitespaceNodes(rootNode);
  595:     }
  596:     
  597:     gInstances->AppendElement(this);
  598: }
  599: 
  600: void
  601: BookmarksService::RemoveObserver()
  602: {
  603:     if (gRefCnt == 0)
  604:         return;
  605:  
  606:     gInstances->RemoveElement(this);
  607:      
  608:     gRefCnt--;
  609:     if (gRefCnt == 0) {
  610:         NS_IF_RELEASE(gBookmarks);
  611:         NS_RELEASE(gBookmarkAtom);
  612:         NS_RELEASE(gFolderAtom);
  613:         NS_RELEASE(gNameAtom);
  614:         NS_RELEASE(gHrefAtom);
  615:         [gDictionary release];
  616:     }
  617: }
  618: 
  619: void
  620: BookmarksService::FlushBookmarks()
  621: {
  622:     nsCOMPtr<nsIFile> bookmarksFile;
  623:     NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(bookmarksFile));
  624:     bookmarksFile->Append("bookmarks.xml");
  625: 
  626:     nsCOMPtr<nsIOutputStream> outputStream;
  627:     NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), bookmarksFile);
  628: 
  629:     nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
  630:     
  631:     nsCOMPtr<nsIDOMSerializer> domSerializer(do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID));
  632:     domSerializer->SerializeToStream(domDoc, outputStream, nsnull);
  633: }
  634: 
  635: void
  636: BookmarksService::ConstructBookmarksToolbar()
  637: {
  638:   nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
  639:   nsCOMPtr<nsIDOMElement> toolbarRoot;
  640:   domDoc->GetElementById(NS_LITERAL_STRING("toolbar"), getter_AddRefs(toolbarRoot));
  641:   
  642: }
  643: 
  644: void
  645: BookmarksService::ConstructBookmarksMenu(NSMenu* aMenu, nsIContent* aContent)
  646: {
  647:     nsCOMPtr<nsIContent> content = aContent;
  648:     if (!content) {
  649:         GetRootContent(getter_AddRefs(content));
  650:         GetWrapperFor(content);
  651:         gBookmarksMenu = aMenu;
  652:     }
  653:     
  654:     // Now walk our children, and for folders also recur into them.
  655:     PRInt32 childCount;
  656:     content->ChildCount(childCount);
  657:     
  658:     for (PRInt32 i = 0; i < childCount; i++) {
  659:       nsCOMPtr<nsIContent> child;
  660:       content->ChildAt(i, *getter_AddRefs(child));
  661:       AddMenuBookmark(aMenu, content, child, -1);
  662:     }
  663: }
  664: 
  665: void
  666: BookmarksService::AddMenuBookmark(NSMenu* aMenu, nsIContent* aParent, nsIContent* aChild, PRInt32 aIndex)
  667: {
  668:   nsAutoString name;
  669:   aChild->GetAttr(kNameSpaceID_None, gNameAtom, name);
  670:   nsCAutoString nameCStr; nameCStr.AssignWithConversion(name);
  671:   NSString* title = [NSString stringWithCString: nameCStr.get()];
  672: 
  673:   // Create a menu or menu item for the child.
  674:   NSMenuItem* menuItem = [[[NSMenuItem alloc] initWithTitle: title action: NULL keyEquivalent: @""] autorelease];
  675:   GetWrapperFor(aChild);
  676: 
  677:   if (aIndex == -1)
  678:     [aMenu addItem: menuItem];
  679:   else
  680:     [aMenu insertItem: menuItem atIndex: aIndex];
  681:   
  682:   nsCOMPtr<nsIAtom> tagName;
  683:   aChild->GetTag(*getter_AddRefs(tagName));
  684: 
  685:   if (tagName == gFolderAtom) {
  686:     NSMenu* menu = [[[NSMenu alloc] initWithTitle: title] autorelease];
  687:     [aMenu setSubmenu: menu forItem: menuItem];
  688:     [menu setAutoenablesItems: NO];
  689:     ConstructBookmarksMenu(menu, aChild);
  690:   }
  691:   else {
  692:     [menuItem setTarget: gMainController];
  693:     [menuItem setAction: @selector(openMenuBookmark:)];
  694:   }
  695: 
  696:   PRUint32 contentID;
  697:   aChild->GetContentID(&contentID);
  698:   [menuItem setTag: contentID];
  699: }
  700: 
  701: void 
  702: BookmarksService::OpenMenuBookmark(BrowserWindowController* aController, id aMenuItem)
  703: {
  704:     // Get the corresponding bookmark item.
  705:     BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: [aMenuItem tag]]];
  706:         
  707:     // Get the content node.
  708:     nsIContent* content = [item contentNode];
  709:         
  710:     // Get the href attribute.  This is the URL we want to load.
  711:     nsAutoString href;
  712:     content->GetAttr(kNameSpaceID_None, gHrefAtom, href);
  713:     nsCAutoString cref; cref.AssignWithConversion(href);
  714:     if (cref.IsEmpty())
  715:         return;
  716:         
  717:     NSString* url = [NSString stringWithCString: cref.get()];
  718:     
  719:     // Now load the URL in the window.
  720:     [aController loadURL:[NSURL URLWithString: url]];
  721:     
  722:     // Focus and activate our content area.
  723:     [[[aController getMyBrowserView] getBrowserView] setActive: YES];
  724: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>