Annotation of chimera/BookmarksService.mm, revision 1.5
1.1 hyatt 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"
1.5 ! hyatt 16: #include "nsIDOMWindow.h"
! 17: #include "nsIDOMHTMLDocument.h"
1.1 hyatt 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"
1.5 ! hyatt 26: #include "nsIWebBrowser.h"
1.1 hyatt 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];
1.5 ! hyatt 40: }
! 41:
! 42: -(void) windowClosing
! 43: {
! 44: if (mBookmarks) {
1.4 hyatt 45: mBookmarks->RemoveObserver();
1.5 ! hyatt 46: delete mBookmarks;
! 47: }
1.1 hyatt 48: }
49:
50: -(void) ensureBookmarks
51: {
52: if (mBookmarks)
53: return;
54:
1.5 ! hyatt 55: mBookmarks = new BookmarksService(self);
1.4 hyatt 56: mBookmarks->AddObserver();
1.1 hyatt 57:
58: [mOutlineView setTarget: self];
59: [mOutlineView setDoubleAction: @selector(openBookmark:)];
60: [mOutlineView reloadData];
61: }
62:
1.2 hyatt 63: -(IBAction)addBookmark:(id)aSender
64: {
65: if (!mBookmarks)
66: return;
1.5 ! hyatt 67:
1.2 hyatt 68: nsCOMPtr<nsIContent> content;
69: int index = [mOutlineView selectedRow];
1.5 ! hyatt 70:
1.2 hyatt 71: if (index > 0) {
72: BookmarkItem* item = [mOutlineView itemAtRow: index];
1.5 ! hyatt 73: if ([mOutlineView isExpandable: item])
1.2 hyatt 74: content = [item contentNode];
75: }
76:
77: if (!content)
78: mBookmarks->GetRootContent(getter_AddRefs(content));
79:
1.5 ! hyatt 80: nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(mBookmarks->gBookmarks));
1.2 hyatt 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:
1.5 ! hyatt 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);
1.2 hyatt 112:
113: nsCOMPtr<nsIDOMElement> parent(do_QueryInterface(content));
114: nsCOMPtr<nsIDOMNode> dummy;
115: parent->AppendChild(elt, getter_AddRefs(dummy));
1.5 ! hyatt 116:
! 117: mBookmarks->NotifyObservers(content, PR_TRUE);
1.2 hyatt 118: }
119:
120: -(IBAction)deleteBookmark: (id)aSender
121: {
122: }
123:
1.1 hyatt 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;
1.2 hyatt 187:
1.1 hyatt 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:
1.5 ! hyatt 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:
1.1 hyatt 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;
1.4 hyatt 271: nsIDocument* BookmarksService::gBookmarks = nsnull;
272: NSMutableDictionary* BookmarksService::gDictionary = nil;
1.1 hyatt 273: nsIAtom* BookmarksService::gFolderAtom = nsnull;
274: nsIAtom* BookmarksService::gBookmarkAtom = nsnull;
275: nsIAtom* BookmarksService::gHrefAtom = nsnull;
276: nsIAtom* BookmarksService::gNameAtom = nsnull;
1.5 ! hyatt 277: nsVoidArray* BookmarksService::gInstances = nsnull;
1.1 hyatt 278:
1.5 ! hyatt 279: BookmarksService::BookmarksService(BookmarksDataSource* aDataSource)
1.1 hyatt 280: {
1.5 ! hyatt 281: mDataSource = aDataSource;
1.1 hyatt 282: }
283:
284: BookmarksService::~BookmarksService()
285: {
286: }
287:
288: void
289: BookmarksService::GetRootContent(nsIContent** aResult)
290: {
291: *aResult = nsnull;
1.4 hyatt 292: if (gBookmarks) {
1.1 hyatt 293: nsCOMPtr<nsIDOMElement> elt;
1.4 hyatt 294: nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
1.1 hyatt 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: {
1.4 hyatt 303: if (!gDictionary)
304: gDictionary = [[NSMutableDictionary alloc] initWithCapacity: 30];
1.1 hyatt 305:
306: PRUint32 contentID;
307: aContent->GetContentID(&contentID);
308:
1.4 hyatt 309: BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: contentID]];
1.1 hyatt 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];
1.4 hyatt 316: [gDictionary setObject: item forKey: [NSNumber numberWithInt: contentID]];
1.1 hyatt 317: }
318: return item;
319: }
320:
1.5 ! hyatt 321: void
! 322: BookmarksService::NotifyObservers(nsIContent* aContainer, PRBool aReloadChildren)
1.4 hyatt 323: {
1.5 ! hyatt 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: }
1.4 hyatt 332: }
333:
334:
1.5 ! hyatt 335: void
! 336: BookmarksService::NotifyObserver(nsIContent* aContainer, PRBool aReloadChildren)
1.4 hyatt 337: {
1.5 ! hyatt 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];
1.4 hyatt 352: }
353:
354: void
355: BookmarksService::AddObserver()
1.1 hyatt 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");
1.5 ! hyatt 363: gInstances = new nsVoidArray();
1.4 hyatt 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);
1.1 hyatt 381: }
382:
1.5 ! hyatt 383: gInstances->AppendElement(this);
1.1 hyatt 384: }
385:
386: void
1.4 hyatt 387: BookmarksService::RemoveObserver()
1.1 hyatt 388: {
389: if (gRefCnt == 0)
390: return;
1.4 hyatt 391:
1.5 ! hyatt 392: gInstances->RemoveElement(this);
! 393:
1.1 hyatt 394: gRefCnt--;
395: if (gRefCnt == 0) {
1.4 hyatt 396: NS_IF_RELEASE(gBookmarks);
1.1 hyatt 397: NS_RELEASE(gBookmarkAtom);
398: NS_RELEASE(gFolderAtom);
399: NS_RELEASE(gNameAtom);
400: NS_RELEASE(gHrefAtom);
1.4 hyatt 401: [gDictionary release];
1.1 hyatt 402: }
403: }
404:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>