File:  [mozdev] / chimera / BookmarksService.mm
Revision 1.5: download - view: text, annotated - select for diffs - revision graph
Sat Feb 9 08:12:33 2002 UTC (17 years, 1 month ago) by hyatt
Branches: MAIN
CVS tags: HEAD
Adding bookmarks works.

    1: /*
    2:  *  BookmarksService.cpp
    3:  *  Chimera
    4:  *
    5:  *  Created by David Hyatt on Thu Feb 07 2002.
    6:  *  Copyright (c) 2001 __MyCompanyName__. All rights reserved.
    7:  *
    8:  */
    9: 
   10: #import "NSBrowserView.h"
   11: #include "BookmarksService.h"
   12: #include "nsIDocument.h"
   13: #include "nsIContent.h"
   14: #include "nsIAtom.h"
   15: #include "nsITextContent.h"
   16: #include "nsIDOMWindow.h"
   17: #include "nsIDOMHTMLDocument.h"
   18: #include "nsIDOMElement.h"
   19: #include "nsString.h"
   20: #include "nsIFile.h"
   21: #include "nsAppDirectoryServiceDefs.h"
   22: #include "nsIXMLHttpRequest.h"
   23: #include "nsNetUtil.h"
   24: #include "nsINamespaceManager.h"
   25: #include "nsIXBLService.h"
   26: #include "nsIWebBrowser.h"
   27: 
   28: @implementation BookmarksDataSource
   29: 
   30: -(id) init
   31: {
   32:     [super init];
   33:     mBookmarks = nsnull;
   34:     return self;
   35: }
   36: 
   37: -(void) dealloc
   38: {
   39:     [super dealloc];
   40: }
   41: 
   42: -(void) windowClosing
   43: {
   44:     if (mBookmarks) {
   45:         mBookmarks->RemoveObserver();
   46:         delete mBookmarks;
   47:     }
   48: }
   49: 
   50: -(void) ensureBookmarks
   51: {
   52:     if (mBookmarks)
   53:         return;
   54:     
   55:     mBookmarks = new BookmarksService(self);
   56:     mBookmarks->AddObserver();
   57:     
   58:     [mOutlineView setTarget: self];
   59:     [mOutlineView setDoubleAction: @selector(openBookmark:)];
   60:     [mOutlineView reloadData];
   61: }
   62: 
   63: -(IBAction)addBookmark:(id)aSender
   64: {
   65:     if (!mBookmarks)
   66:         return;
   67:     
   68:     nsCOMPtr<nsIContent> content;
   69:     int index = [mOutlineView selectedRow];
   70:    
   71:     if (index > 0) {
   72:         BookmarkItem* item = [mOutlineView itemAtRow: index];
   73:         if ([mOutlineView isExpandable: item]) 
   74:             content = [item contentNode];
   75:     }
   76:     
   77:     if (!content)
   78:         mBookmarks->GetRootContent(getter_AddRefs(content));
   79:         
   80:     nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(mBookmarks->gBookmarks));
   81:     nsCOMPtr<nsIDOMElement> elt;
   82:     domDoc->CreateElementNS(NS_LITERAL_STRING("http://chimera.mozdev.org/bookmarks"), 
   83:                             NS_LITERAL_STRING("bookmark"), 
   84:                             getter_AddRefs(elt));
   85:     
   86:     // Fetch the title of the current page and the URL.
   87:     nsCOMPtr<nsIWebBrowser> webBrowser = getter_AddRefs([[mBrowserView getBrowserView] getWebBrowser]);
   88:     nsCOMPtr<nsIDOMWindow> window;
   89:     webBrowser->GetContentDOMWindow(getter_AddRefs(window));
   90:     nsCOMPtr<nsIDOMDocument> htmlDoc;
   91:     window->GetDocument(getter_AddRefs(htmlDoc));
   92:     nsCOMPtr<nsIDocument> pageDoc(do_QueryInterface(htmlDoc));
   93:     
   94:     nsAutoString href; 
   95:     if (pageDoc) {
   96:         nsCOMPtr<nsIURI> url;
   97:         pageDoc->GetDocumentURL(getter_AddRefs(url));
   98:         nsXPIDLCString spec;
   99:         url->GetSpec(getter_Copies(spec));
  100:         href.AssignWithConversion(spec.get());
  101:     }
  102:     
  103:     nsAutoString title;
  104:     nsCOMPtr<nsIDOMHTMLDocument> htmlDocument(do_QueryInterface(htmlDoc));
  105:     if (htmlDocument)
  106:         htmlDocument->GetTitle(title);
  107:     if (title.IsEmpty())
  108:         title = href;
  109:         
  110:     elt->SetAttribute(NS_LITERAL_STRING("name"), title);
  111:     elt->SetAttribute(NS_LITERAL_STRING("href"), href);    
  112:     
  113:     nsCOMPtr<nsIDOMElement> parent(do_QueryInterface(content));
  114:     nsCOMPtr<nsIDOMNode> dummy;
  115:     parent->AppendChild(elt, getter_AddRefs(dummy));
  116: 
  117:     mBookmarks->NotifyObservers(content, PR_TRUE);
  118: }
  119: 
  120: -(IBAction)deleteBookmark: (id)aSender
  121: {
  122: }
  123: 
  124: -(IBAction)openBookmark: (id)aSender
  125: {
  126:     int index = [mOutlineView selectedRow];
  127:     if (index == -1)
  128:         return;
  129:     
  130:     id item = [mOutlineView itemAtRow: index];
  131:     if (!item)
  132:         return;
  133:         
  134:     if ([mOutlineView isExpandable: item]) {
  135:         if ([mOutlineView isItemExpanded: item])
  136:             [mOutlineView collapseItem: item];
  137:         else
  138:             [mOutlineView expandItem: item];
  139:     }
  140:     else {
  141:         nsIContent* content = [item contentNode];
  142:         nsAutoString href;
  143:         content->GetAttr(kNameSpaceID_None, BookmarksService::gHrefAtom, href);
  144:         if (!href.IsEmpty()) {
  145:             nsCAutoString cstr; cstr.AssignWithConversion(href);
  146:             NSString* url = [NSString stringWithCString: cstr.get()];
  147:             [[mBrowserView getBrowserView] loadURI:[NSURL URLWithString: url] flags:NSLoadFlagsNone];
  148:         }
  149:     } 
  150: }
  151: 
  152: - (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
  153: {
  154:     if (!mBookmarks)
  155:         return nil;
  156:        
  157:     nsCOMPtr<nsIContent> content;
  158:     if (!item)
  159:         mBookmarks->GetRootContent(getter_AddRefs(content));
  160:     else
  161:         content = [item contentNode];
  162:     
  163:     nsCOMPtr<nsIContent> child;
  164:     content->ChildAt(index, *getter_AddRefs(child));
  165:     return mBookmarks->GetWrapperFor(child);
  166: }
  167: 
  168: - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
  169: {
  170:     if (!mBookmarks)
  171:         return NO;
  172:     
  173:     if (!item)
  174:         return YES; // The root node is always open.
  175:     
  176:     nsCOMPtr<nsIAtom> tagName;
  177:     nsIContent* content = [item contentNode];
  178:     content->GetTag(*getter_AddRefs(tagName));
  179:     
  180:     return (tagName == BookmarksService::gFolderAtom);
  181: }
  182: 
  183: - (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
  184: {
  185:     if (!mBookmarks)
  186:         return 0;
  187:   
  188:     nsCOMPtr<nsIContent> content;
  189:     if (!item)
  190:         mBookmarks->GetRootContent(getter_AddRefs(content));
  191:     else 
  192:         content = [item contentNode];
  193:     
  194:     PRInt32 childCount;
  195:     content->ChildCount(childCount);
  196:     
  197:     return childCount;
  198: }
  199: 
  200: - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
  201: {
  202:     if (!item)
  203:         return nil;
  204:     
  205:     NSString* columnName = [tableColumn identifier];
  206:       
  207:     if ([columnName isEqualToString: @"name"]) {
  208:         nsIContent* content = [item contentNode];
  209:         nsAutoString nameAttr;
  210:         content->GetAttr(kNameSpaceID_None, BookmarksService::gNameAtom, nameAttr);
  211:         nsCAutoString cStr; cStr.AssignWithConversion(nameAttr);
  212:         return [NSString stringWithCString: cStr.get()];
  213:     }
  214:     
  215:     return nil;
  216: }
  217: 
  218: - (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
  219: {
  220: }
  221: 
  222: - (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren
  223: {
  224:     printf("Reloading?\n");
  225:     if (!item)
  226:         [mOutlineView reloadData];
  227:     else if ([mOutlineView isItemExpanded: item])
  228:         [mOutlineView reloadItem: item reloadChildren: aReloadChildren];
  229: }
  230: 
  231: @end
  232: 
  233: @implementation BookmarkItem
  234: -(nsIContent*)contentNode
  235: {
  236:     return mContentNode;
  237: }
  238: 
  239: -(void)setContentNode: (nsIContent*)aContentNode
  240: {
  241:     mContentNode = aContentNode;
  242: }
  243: @end
  244: 
  245: // Helper for stripping whitespace
  246: static void
  247: StripWhitespaceNodes(nsIContent* aElement)
  248: {
  249:     PRInt32 childCount;
  250:     aElement->ChildCount(childCount);
  251:     for (PRInt32 i = 0; i < childCount; i++) {
  252:         nsCOMPtr<nsIContent> child;
  253:         aElement->ChildAt(i, *getter_AddRefs(child));
  254:         nsCOMPtr<nsITextContent> text = do_QueryInterface(child);
  255:         if (text) {
  256:             PRBool isEmpty;
  257:             text->IsOnlyWhitespace(&isEmpty);
  258:             if (isEmpty) {
  259:                 // This node contained nothing but whitespace.
  260:                 // Remove it from the content model.
  261:                 aElement->RemoveChildAt(i, PR_TRUE);
  262:                 i--; // Decrement our count, since we just removed this child.
  263:                 childCount--; // Also decrement our total count.
  264:             }
  265:         }
  266:         else StripWhitespaceNodes(child);
  267:     }
  268: }
  269: 
  270: PRUint32 BookmarksService::gRefCnt = 0;
  271: nsIDocument* BookmarksService::gBookmarks = nsnull;
  272: NSMutableDictionary* BookmarksService::gDictionary = nil;
  273: nsIAtom* BookmarksService::gFolderAtom = nsnull;
  274: nsIAtom* BookmarksService::gBookmarkAtom = nsnull;
  275: nsIAtom* BookmarksService::gHrefAtom = nsnull;
  276: nsIAtom* BookmarksService::gNameAtom = nsnull;
  277: nsVoidArray* BookmarksService::gInstances = nsnull;
  278: 
  279: BookmarksService::BookmarksService(BookmarksDataSource* aDataSource)
  280: {
  281:     mDataSource = aDataSource;
  282: }
  283: 
  284: BookmarksService::~BookmarksService()
  285: {
  286: }
  287: 
  288: void
  289: BookmarksService::GetRootContent(nsIContent** aResult)
  290: {
  291:     *aResult = nsnull;
  292:     if (gBookmarks) {
  293:         nsCOMPtr<nsIDOMElement> elt;
  294:         nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
  295:         domDoc->GetDocumentElement(getter_AddRefs(elt));
  296:         elt->QueryInterface(NS_GET_IID(nsIContent), (void**)aResult); // Addref happens here.
  297:     }
  298: }
  299: 
  300: BookmarkItem*
  301: BookmarksService::GetWrapperFor(nsIContent* aContent)
  302: {
  303:     if (!gDictionary)
  304:         gDictionary = [[NSMutableDictionary alloc] initWithCapacity: 30];
  305:     
  306:     PRUint32 contentID;
  307:     aContent->GetContentID(&contentID);
  308:     
  309:     BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: contentID]];
  310:     if (item)
  311:         return item;
  312:     else {
  313:         // Create an item.
  314:         item = [[[BookmarkItem alloc] init] autorelease]; // The dictionary retains us.
  315:         [item setContentNode: aContent];
  316:         [gDictionary setObject: item forKey: [NSNumber numberWithInt: contentID]];
  317:     }
  318:     return item;
  319: }
  320: 
  321: void
  322: BookmarksService::NotifyObservers(nsIContent* aContainer, PRBool aReloadChildren)
  323: {
  324:     if (!gInstances)
  325:         return;
  326:     
  327:     PRInt32 count = gInstances->Count();
  328:     for (PRInt32 i = 0; i < count; i++) {
  329:         BookmarksService* instance = (BookmarksService*)gInstances->ElementAt(i);
  330:         instance->NotifyObserver(aContainer, aReloadChildren);
  331:     }
  332: }
  333: 
  334: 
  335: void
  336: BookmarksService::NotifyObserver(nsIContent* aContainer, PRBool aReloadChildren)
  337: {
  338:     if (!gDictionary)
  339:         return;
  340:        
  341:     printf("uh. appended!\n");
  342:     
  343:     nsCOMPtr<nsIContent> parent;
  344:     aContainer->GetParent(*getter_AddRefs(parent));
  345:     
  346:     BookmarkItem* item = nil;
  347:     if (parent)
  348:         // We're not the root.
  349:         item = GetWrapperFor(aContainer);
  350:     
  351:     [mDataSource reloadDataForItem: item reloadChildren: aReloadChildren];
  352: }
  353: 
  354: void
  355: BookmarksService::AddObserver()
  356: {
  357:     gRefCnt++;
  358:     if (gRefCnt == 1) {
  359:         gBookmarkAtom = NS_NewAtom("bookmark");
  360:         gFolderAtom = NS_NewAtom("folder");
  361:         gNameAtom = NS_NewAtom("name");
  362:         gHrefAtom = NS_NewAtom("href");
  363:         gInstances = new nsVoidArray();
  364:         
  365:         nsCOMPtr<nsIFile> profileDir;
  366:         NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profileDir));
  367:         profileDir->Append("bookmarks.xml");
  368:     
  369:         nsXPIDLCString bookmarksFileURL;
  370:         NS_GetURLSpecFromFile(profileDir, getter_Copies(bookmarksFileURL));
  371:         
  372:         nsCOMPtr<nsIURI> uri;
  373:         NS_NewURI(getter_AddRefs(uri), bookmarksFileURL.get());
  374:     
  375:         nsCOMPtr<nsIXBLService> xblService(do_GetService("@mozilla.org/xbl;1"));    
  376:         xblService->FetchSyncXMLDocument(uri, &gBookmarks); // The addref is here.
  377:         
  378:         nsCOMPtr<nsIContent> rootNode;
  379:         GetRootContent(getter_AddRefs(rootNode));
  380:         StripWhitespaceNodes(rootNode);
  381:     }
  382:     
  383:     gInstances->AppendElement(this);
  384: }
  385: 
  386: void
  387: BookmarksService::RemoveObserver()
  388: {
  389:     if (gRefCnt == 0)
  390:         return;
  391:  
  392:     gInstances->RemoveElement(this);
  393:      
  394:     gRefCnt--;
  395:     if (gRefCnt == 0) {
  396:         NS_IF_RELEASE(gBookmarks);
  397:         NS_RELEASE(gBookmarkAtom);
  398:         NS_RELEASE(gFolderAtom);
  399:         NS_RELEASE(gNameAtom);
  400:         NS_RELEASE(gHrefAtom);
  401:         [gDictionary release];
  402:     }
  403: }
  404: 

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