File:  [mozdev] / chimera / BookmarksService.mm
Revision 1.22: download - view: text, annotated - select for diffs - revision graph
Wed Apr 17 08:31:11 2002 UTC (16 years, 11 months ago) by hyatt
Branches: MAIN
CVS tags: HEAD
Nearly have the personal toolbar going.

    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: nsIDOMElement* BookmarksService::gToolbarRoot = nsnull;
  409: nsIAtom* BookmarksService::gFolderAtom = nsnull;
  410: nsIAtom* BookmarksService::gBookmarkAtom = nsnull;
  411: nsIAtom* BookmarksService::gHrefAtom = nsnull;
  412: nsIAtom* BookmarksService::gNameAtom = nsnull;
  413: nsVoidArray* BookmarksService::gInstances = nsnull;
  414: 
  415: BookmarksService::BookmarksService(BookmarksDataSource* aDataSource)
  416: {
  417:   mDataSource = aDataSource;
  418:   mToolbar = nil;
  419: }
  420: 
  421: BookmarksService::BookmarksService(BookmarksToolbar* aToolbar)
  422: {
  423:   mDataSource = nil;
  424:   mToolbar = aToolbar;
  425: }
  426: 
  427: BookmarksService::~BookmarksService()
  428: {
  429: }
  430: 
  431: void
  432: BookmarksService::GetRootContent(nsIContent** aResult)
  433: {
  434:     *aResult = nsnull;
  435:     if (gBookmarks) {
  436:         nsCOMPtr<nsIDOMElement> elt;
  437:         nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
  438:         domDoc->GetDocumentElement(getter_AddRefs(elt));
  439:         elt->QueryInterface(NS_GET_IID(nsIContent), (void**)aResult); // Addref happens here.
  440:     }
  441: }
  442: 
  443: BookmarkItem*
  444: BookmarksService::GetWrapperFor(nsIContent* aContent)
  445: {
  446:     if (!gDictionary)
  447:         gDictionary = [[NSMutableDictionary alloc] initWithCapacity: 30];
  448:     
  449:     PRUint32 contentID;
  450:     aContent->GetContentID(&contentID);
  451:     
  452:     BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: contentID]];
  453:     if (item)
  454:         return item;
  455:     else {
  456:         // Create an item.
  457:         item = [[[BookmarkItem alloc] init] autorelease]; // The dictionary retains us.
  458:         [item setContentNode: aContent];
  459:         [gDictionary setObject: item forKey: [NSNumber numberWithInt: contentID]];
  460:     }
  461:     return item;
  462: }
  463: 
  464: NSMenu*
  465: BookmarksService::LocateMenu(nsIContent* aContent)
  466: {
  467:   nsCOMPtr<nsIContent> parent;
  468:   aContent->GetParent(*getter_AddRefs(parent));
  469:   if (!parent)
  470:     return BookmarksService::gBookmarksMenu;
  471: 
  472:   NSMenu* parentMenu = LocateMenu(parent);
  473:   
  474:   PRUint32 contentID;
  475:   aContent->GetContentID(&contentID);
  476: 
  477:   NSMenuItem* childMenu = [parentMenu itemWithTag: contentID];
  478:   return [childMenu menu];
  479: }
  480: 
  481: void
  482: BookmarksService::BookmarkAdded(nsIContent* aContainer, nsIContent* aChild)
  483: {
  484:   if (!gInstances || !gDictionary)
  485:     return;
  486: 
  487:   PRInt32 count = gInstances->Count();
  488:   for (PRInt32 i = 0; i < count; i++) {
  489:     BookmarksService* instance = (BookmarksService*)gInstances->ElementAt(i);
  490: 
  491:     if (instance->mDataSource) {
  492:       // We're a tree view.
  493:       nsCOMPtr<nsIContent> parent;
  494:       aContainer->GetParent(*getter_AddRefs(parent));
  495: 
  496:       BookmarkItem* item = nil;
  497:       if (parent)
  498:         // We're not the root.
  499:         item = GetWrapperFor(aContainer);
  500: 
  501:       [(instance->mDataSource) reloadDataForItem: item reloadChildren: YES];
  502:     }
  503:     else {
  504:       // We're the menu.
  505:       PRInt32 index = -1;
  506:       aChild->IndexOf(aContainer, index);
  507:       NSMenu* menu = LocateMenu(aContainer);
  508:       AddMenuBookmark(menu, aContainer, aChild, index);
  509:     }
  510:   }
  511:   
  512:   FlushBookmarks();  
  513: }
  514: 
  515: void
  516: BookmarksService::BookmarkChanged(nsIContent* aItem)
  517: {
  518:   if (!gInstances || !gDictionary)
  519:     return;
  520: 
  521:   PRInt32 count = gInstances->Count();
  522:   for (PRInt32 i = 0; i < count; i++) {
  523:     BookmarksService* instance = (BookmarksService*)gInstances->ElementAt(i);
  524:    
  525:     if (instance->mDataSource) {
  526:       BookmarkItem* item = GetWrapperFor(aItem);
  527:       [(instance->mDataSource) reloadDataForItem: item reloadChildren: NO];
  528:     }
  529:   }
  530: 
  531:   FlushBookmarks();  
  532: }
  533: 
  534: void
  535: BookmarksService::BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild)
  536: {
  537:   if (!gInstances)
  538:     return;
  539: 
  540:   PRInt32 count = gInstances->Count();
  541:   for (PRInt32 i = 0; i < count; i++) {
  542:     BookmarksService* instance = (BookmarksService*)gInstances->ElementAt(i);
  543: 
  544:     if (instance->mDataSource) {
  545:       // We're a tree view.
  546:       nsCOMPtr<nsIContent> parent;
  547:       aContainer->GetParent(*getter_AddRefs(parent));
  548: 
  549:       BookmarkItem* item = nil;
  550:       if (parent)
  551:         // We're not the root.
  552:         item = GetWrapperFor(aContainer);
  553: 
  554:       [(instance->mDataSource) reloadDataForItem: item reloadChildren: YES];
  555:     }
  556:     else {
  557:       // We're the menu.
  558:       NSMenu* menu = LocateMenu(aContainer);
  559:       PRUint32 contentID;
  560:       aChild->GetContentID(&contentID);
  561:       NSMenuItem* childItem = [menu itemWithTag: contentID];
  562:       [menu removeItem: childItem];
  563:     }
  564:   }
  565: 
  566:   FlushBookmarks(); 
  567: }
  568: 
  569: void
  570: BookmarksService::AddObserver()
  571: {
  572:     gRefCnt++;
  573:     if (gRefCnt == 1) {
  574:         gBookmarkAtom = NS_NewAtom("bookmark");
  575:         gFolderAtom = NS_NewAtom("folder");
  576:         gNameAtom = NS_NewAtom("name");
  577:         gHrefAtom = NS_NewAtom("href");
  578:         gInstances = new nsVoidArray();
  579:                 
  580:         nsCOMPtr<nsIFile> profileDir;
  581:         NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profileDir));
  582:         profileDir->Append("bookmarks.xml");
  583:     
  584:         nsCAutoString bookmarksFileURL;
  585:         NS_GetURLSpecFromFile(profileDir, bookmarksFileURL);
  586:         
  587:         nsCOMPtr<nsIURI> uri;
  588:         NS_NewURI(getter_AddRefs(uri), bookmarksFileURL.get());
  589:     
  590:         nsCOMPtr<nsIXBLService> xblService(do_GetService("@mozilla.org/xbl;1"));    
  591:         xblService->FetchSyncXMLDocument(uri, &gBookmarks); // The addref is here.
  592:         
  593:         nsCOMPtr<nsIContent> rootNode;
  594:         GetRootContent(getter_AddRefs(rootNode));
  595:         StripWhitespaceNodes(rootNode);
  596:     }
  597:     
  598:     gInstances->AppendElement(this);
  599: }
  600: 
  601: void
  602: BookmarksService::RemoveObserver()
  603: {
  604:     if (gRefCnt == 0)
  605:         return;
  606:  
  607:     gInstances->RemoveElement(this);
  608:      
  609:     gRefCnt--;
  610:     if (gRefCnt == 0) {
  611:         NS_IF_RELEASE(gBookmarks);
  612:         NS_RELEASE(gBookmarkAtom);
  613:         NS_RELEASE(gFolderAtom);
  614:         NS_RELEASE(gNameAtom);
  615:         NS_RELEASE(gHrefAtom);
  616:         [gDictionary release];
  617:     }
  618: }
  619: 
  620: void
  621: BookmarksService::FlushBookmarks()
  622: {
  623:     nsCOMPtr<nsIFile> bookmarksFile;
  624:     NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(bookmarksFile));
  625:     bookmarksFile->Append("bookmarks.xml");
  626: 
  627:     nsCOMPtr<nsIOutputStream> outputStream;
  628:     NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), bookmarksFile);
  629: 
  630:     nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
  631:     
  632:     nsCOMPtr<nsIDOMSerializer> domSerializer(do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID));
  633:     domSerializer->SerializeToStream(domDoc, outputStream, nsnull);
  634: }
  635: 
  636: void BookmarksService::EnsureToolbarRoot()
  637: {
  638:   if (gToolbarRoot)
  639:     return;
  640: 
  641:   nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
  642:   nsCOMPtr<nsIDOMElement> rootElt;
  643:   domDoc->GetDocumentElement(getter_AddRefs(rootElt));
  644:   
  645:   nsCOMPtr<nsIDOMNode> child;
  646:   rootElt->GetFirstChild(getter_AddRefs(child));
  647:   nsAutoString typeValue;
  648:   while (child) {
  649:     nsCOMPtr<nsIDOMElement> childElt(do_QueryInterface(child));
  650:     if (childElt) {
  651:       childElt->GetAttribute(NS_LITERAL_STRING("type"), typeValue);
  652:       if (typeValue.Equals(NS_LITERAL_STRING("toolbar")))
  653:         gToolbarRoot = childElt;
  654:     }
  655:     
  656:     nsCOMPtr<nsIDOMNode> temp;
  657:     child->GetNextSibling(getter_AddRefs(temp));
  658:     child = temp;
  659:   }
  660: 
  661:   if (!gToolbarRoot) {
  662:     printf("Repairing personal toolbar.\n");
  663:     nsCOMPtr<nsIDOMElement> elt;
  664:     domDoc->CreateElementNS(NS_LITERAL_STRING("http://chimera.mozdev.org/bookmarks/"),
  665:                             NS_LITERAL_STRING("folder"),
  666:                             getter_AddRefs(elt));
  667: 
  668:     elt->SetAttribute(NS_LITERAL_STRING("name"), NS_LITERAL_STRING("Toolbar Bookmarks"));
  669:     elt->SetAttribute(NS_LITERAL_STRING("type"), NS_LITERAL_STRING("toolbar"));
  670: 
  671:     nsCOMPtr<nsIDOMNode> dummy;
  672:     rootElt->AppendChild(elt, getter_AddRefs(dummy));
  673:     gToolbarRoot = elt;
  674:   }
  675: }
  676: 
  677: void
  678: BookmarksService::ConstructBookmarksMenu(NSMenu* aMenu, nsIContent* aContent)
  679: {
  680:     nsCOMPtr<nsIContent> content = aContent;
  681:     if (!content) {
  682:         GetRootContent(getter_AddRefs(content));
  683:         GetWrapperFor(content);
  684:         gBookmarksMenu = aMenu;
  685:     }
  686:     
  687:     // Now walk our children, and for folders also recur into them.
  688:     PRInt32 childCount;
  689:     content->ChildCount(childCount);
  690:     
  691:     for (PRInt32 i = 0; i < childCount; i++) {
  692:       nsCOMPtr<nsIContent> child;
  693:       content->ChildAt(i, *getter_AddRefs(child));
  694:       AddMenuBookmark(aMenu, content, child, -1);
  695:     }
  696: }
  697: 
  698: void
  699: BookmarksService::AddMenuBookmark(NSMenu* aMenu, nsIContent* aParent, nsIContent* aChild, PRInt32 aIndex)
  700: {
  701:   nsAutoString name;
  702:   aChild->GetAttr(kNameSpaceID_None, gNameAtom, name);
  703:   nsCAutoString nameCStr; nameCStr.AssignWithConversion(name);
  704:   NSString* title = [NSString stringWithCString: nameCStr.get()];
  705: 
  706:   // Create a menu or menu item for the child.
  707:   NSMenuItem* menuItem = [[[NSMenuItem alloc] initWithTitle: title action: NULL keyEquivalent: @""] autorelease];
  708:   GetWrapperFor(aChild);
  709: 
  710:   if (aIndex == -1)
  711:     [aMenu addItem: menuItem];
  712:   else
  713:     [aMenu insertItem: menuItem atIndex: aIndex];
  714:   
  715:   nsCOMPtr<nsIAtom> tagName;
  716:   aChild->GetTag(*getter_AddRefs(tagName));
  717: 
  718:   if (tagName == gFolderAtom) {
  719:     NSMenu* menu = [[[NSMenu alloc] initWithTitle: title] autorelease];
  720:     [aMenu setSubmenu: menu forItem: menuItem];
  721:     [menu setAutoenablesItems: NO];
  722:     ConstructBookmarksMenu(menu, aChild);
  723:   }
  724:   else {
  725:     [menuItem setTarget: gMainController];
  726:     [menuItem setAction: @selector(openMenuBookmark:)];
  727:   }
  728: 
  729:   PRUint32 contentID;
  730:   aChild->GetContentID(&contentID);
  731:   [menuItem setTag: contentID];
  732: }
  733: 
  734: void 
  735: BookmarksService::OpenMenuBookmark(BrowserWindowController* aController, id aMenuItem)
  736: {
  737:     // Get the corresponding bookmark item.
  738:     BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: [aMenuItem tag]]];
  739:         
  740:     // Get the content node.
  741:     nsIContent* content = [item contentNode];
  742:         
  743:     // Get the href attribute.  This is the URL we want to load.
  744:     nsAutoString href;
  745:     content->GetAttr(kNameSpaceID_None, gHrefAtom, href);
  746:     nsCAutoString cref; cref.AssignWithConversion(href);
  747:     if (cref.IsEmpty())
  748:         return;
  749:         
  750:     NSString* url = [NSString stringWithCString: cref.get()];
  751:     
  752:     // Now load the URL in the window.
  753:     [aController loadURL:[NSURL URLWithString: url]];
  754:     
  755:     // Focus and activate our content area.
  756:     [[[aController getMyBrowserView] getBrowserView] setActive: YES];
  757: }

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