Annotation of chimera/BookmarksService.mm, revision 1.9
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"
1.6 hyatt 23: #include "nsIDOMSerializer.h"
1.1 hyatt 24: #include "nsNetUtil.h"
25: #include "nsINamespaceManager.h"
26: #include "nsIXBLService.h"
1.5 hyatt 27: #include "nsIWebBrowser.h"
1.1 hyatt 28:
29: @implementation BookmarksDataSource
30:
31: -(id) init
32: {
33: [super init];
34: mBookmarks = nsnull;
35: return self;
36: }
37:
38: -(void) dealloc
39: {
40: [super dealloc];
1.5 hyatt 41: }
42:
43: -(void) windowClosing
44: {
45: if (mBookmarks) {
1.4 hyatt 46: mBookmarks->RemoveObserver();
1.5 hyatt 47: delete mBookmarks;
48: }
1.1 hyatt 49: }
50:
51: -(void) ensureBookmarks
52: {
53: if (mBookmarks)
54: return;
55:
1.5 hyatt 56: mBookmarks = new BookmarksService(self);
1.4 hyatt 57: mBookmarks->AddObserver();
1.1 hyatt 58:
59: [mOutlineView setTarget: self];
60: [mOutlineView setDoubleAction: @selector(openBookmark:)];
61: [mOutlineView reloadData];
62: }
63:
1.2 hyatt 64: -(IBAction)addBookmark:(id)aSender
65: {
66: if (!mBookmarks)
67: return;
1.5 hyatt 68:
1.2 hyatt 69: nsCOMPtr<nsIContent> content;
70: int index = [mOutlineView selectedRow];
1.5 hyatt 71:
1.7 hyatt 72: if (index >= 0) {
1.2 hyatt 73: BookmarkItem* item = [mOutlineView itemAtRow: index];
1.5 hyatt 74: if ([mOutlineView isExpandable: item])
1.2 hyatt 75: content = [item contentNode];
76: }
77:
78: if (!content)
79: mBookmarks->GetRootContent(getter_AddRefs(content));
80:
1.5 hyatt 81: nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(mBookmarks->gBookmarks));
1.2 hyatt 82: nsCOMPtr<nsIDOMElement> elt;
83: domDoc->CreateElementNS(NS_LITERAL_STRING("http://chimera.mozdev.org/bookmarks"),
84: NS_LITERAL_STRING("bookmark"),
85: getter_AddRefs(elt));
86:
1.5 hyatt 87: // Fetch the title of the current page and the URL.
88: nsCOMPtr<nsIWebBrowser> webBrowser = getter_AddRefs([[mBrowserView getBrowserView] getWebBrowser]);
89: nsCOMPtr<nsIDOMWindow> window;
90: webBrowser->GetContentDOMWindow(getter_AddRefs(window));
91: nsCOMPtr<nsIDOMDocument> htmlDoc;
92: window->GetDocument(getter_AddRefs(htmlDoc));
93: nsCOMPtr<nsIDocument> pageDoc(do_QueryInterface(htmlDoc));
94:
95: nsAutoString href;
96: if (pageDoc) {
97: nsCOMPtr<nsIURI> url;
98: pageDoc->GetDocumentURL(getter_AddRefs(url));
99: nsXPIDLCString spec;
100: url->GetSpec(getter_Copies(spec));
101: href.AssignWithConversion(spec.get());
102: }
103:
104: nsAutoString title;
105: nsCOMPtr<nsIDOMHTMLDocument> htmlDocument(do_QueryInterface(htmlDoc));
106: if (htmlDocument)
107: htmlDocument->GetTitle(title);
108: if (title.IsEmpty())
109: title = href;
110:
111: elt->SetAttribute(NS_LITERAL_STRING("name"), title);
112: elt->SetAttribute(NS_LITERAL_STRING("href"), href);
1.2 hyatt 113:
114: nsCOMPtr<nsIDOMElement> parent(do_QueryInterface(content));
115: nsCOMPtr<nsIDOMNode> dummy;
116: parent->AppendChild(elt, getter_AddRefs(dummy));
1.5 hyatt 117:
118: mBookmarks->NotifyObservers(content, PR_TRUE);
1.2 hyatt 119: }
120:
121: -(IBAction)deleteBookmark: (id)aSender
122: {
1.6 hyatt 123: if (!mBookmarks)
124: return;
125:
126: int index = [mOutlineView selectedRow];
127: if (index == -1)
128: return;
129:
130: BookmarkItem* item = [mOutlineView itemAtRow: index];
131: nsCOMPtr<nsIContent> content = [item contentNode];
132: nsCOMPtr<nsIDOMElement> child(do_QueryInterface(content));
133: nsCOMPtr<nsIDOMNode> parent;
134: child->GetParentNode(getter_AddRefs(parent));
135: nsCOMPtr<nsIDOMNode> dummy;
136: parent->RemoveChild(child, getter_AddRefs(dummy));
137: nsCOMPtr<nsIContent> parentContent(do_QueryInterface(parent));
138: mBookmarks->NotifyObservers(parentContent, PR_TRUE);
139:
140: int total = [mOutlineView numberOfRows];
141: if (index == total)
142: index--;
143:
144: [mOutlineView selectRow: index byExtendingSelection: NO];
1.2 hyatt 145: }
146:
1.1 hyatt 147: -(IBAction)openBookmark: (id)aSender
148: {
149: int index = [mOutlineView selectedRow];
150: if (index == -1)
151: return;
152:
153: id item = [mOutlineView itemAtRow: index];
154: if (!item)
155: return;
156:
157: if ([mOutlineView isExpandable: item]) {
158: if ([mOutlineView isItemExpanded: item])
159: [mOutlineView collapseItem: item];
160: else
161: [mOutlineView expandItem: item];
162: }
163: else {
164: nsIContent* content = [item contentNode];
165: nsAutoString href;
166: content->GetAttr(kNameSpaceID_None, BookmarksService::gHrefAtom, href);
167: if (!href.IsEmpty()) {
168: nsCAutoString cstr; cstr.AssignWithConversion(href);
169: NSString* url = [NSString stringWithCString: cstr.get()];
170: [[mBrowserView getBrowserView] loadURI:[NSURL URLWithString: url] flags:NSLoadFlagsNone];
171: }
172: }
173: }
174:
1.9 ! hyatt 175: - (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
! 176: {
! 177: if (!mBookmarks)
! 178: return NO;
! 179:
! 180: return YES;
! 181: }
! 182:
1.1 hyatt 183: - (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
184: {
185: if (!mBookmarks)
186: return nil;
187:
188: nsCOMPtr<nsIContent> content;
189: if (!item)
190: mBookmarks->GetRootContent(getter_AddRefs(content));
191: else
192: content = [item contentNode];
193:
194: nsCOMPtr<nsIContent> child;
195: content->ChildAt(index, *getter_AddRefs(child));
196: return mBookmarks->GetWrapperFor(child);
197: }
198:
199: - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
200: {
201: if (!mBookmarks)
202: return NO;
203:
204: if (!item)
205: return YES; // The root node is always open.
206:
207: nsCOMPtr<nsIAtom> tagName;
208: nsIContent* content = [item contentNode];
209: content->GetTag(*getter_AddRefs(tagName));
210:
211: return (tagName == BookmarksService::gFolderAtom);
212: }
213:
214: - (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
215: {
216: if (!mBookmarks)
217: return 0;
1.2 hyatt 218:
1.1 hyatt 219: nsCOMPtr<nsIContent> content;
220: if (!item)
221: mBookmarks->GetRootContent(getter_AddRefs(content));
222: else
223: content = [item contentNode];
224:
225: PRInt32 childCount;
226: content->ChildCount(childCount);
227:
228: return childCount;
229: }
230:
231: - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
232: {
233: if (!item)
234: return nil;
235:
236: NSString* columnName = [tableColumn identifier];
237:
238: if ([columnName isEqualToString: @"name"]) {
239: nsIContent* content = [item contentNode];
240: nsAutoString nameAttr;
241: content->GetAttr(kNameSpaceID_None, BookmarksService::gNameAtom, nameAttr);
242: nsCAutoString cStr; cStr.AssignWithConversion(nameAttr);
243: return [NSString stringWithCString: cStr.get()];
244: }
245:
246: return nil;
247: }
248:
249: - (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
250: {
251: }
252:
1.5 hyatt 253: - (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren
254: {
255: printf("Reloading?\n");
256: if (!item)
257: [mOutlineView reloadData];
258: else if ([mOutlineView isItemExpanded: item])
259: [mOutlineView reloadItem: item reloadChildren: aReloadChildren];
260: }
261:
1.1 hyatt 262: @end
263:
264: @implementation BookmarkItem
265: -(nsIContent*)contentNode
266: {
267: return mContentNode;
268: }
269:
270: -(void)setContentNode: (nsIContent*)aContentNode
271: {
272: mContentNode = aContentNode;
273: }
1.7 hyatt 274:
275: - (id)copyWithZone:(NSZone *)aZone
276: {
277: BookmarkItem* copy = [[[self class] allocWithZone: aZone] init];
278: [copy setContentNode: mContentNode];
279: return copy;
280: }
281:
1.1 hyatt 282: @end
283:
284: // Helper for stripping whitespace
285: static void
286: StripWhitespaceNodes(nsIContent* aElement)
287: {
288: PRInt32 childCount;
289: aElement->ChildCount(childCount);
290: for (PRInt32 i = 0; i < childCount; i++) {
291: nsCOMPtr<nsIContent> child;
292: aElement->ChildAt(i, *getter_AddRefs(child));
293: nsCOMPtr<nsITextContent> text = do_QueryInterface(child);
294: if (text) {
295: PRBool isEmpty;
296: text->IsOnlyWhitespace(&isEmpty);
297: if (isEmpty) {
298: // This node contained nothing but whitespace.
299: // Remove it from the content model.
300: aElement->RemoveChildAt(i, PR_TRUE);
301: i--; // Decrement our count, since we just removed this child.
302: childCount--; // Also decrement our total count.
303: }
304: }
305: else StripWhitespaceNodes(child);
306: }
307: }
308:
309: PRUint32 BookmarksService::gRefCnt = 0;
1.4 hyatt 310: nsIDocument* BookmarksService::gBookmarks = nsnull;
311: NSMutableDictionary* BookmarksService::gDictionary = nil;
1.8 hyatt 312: MainController* BookmarksService::gMainController = nil;
1.1 hyatt 313: nsIAtom* BookmarksService::gFolderAtom = nsnull;
314: nsIAtom* BookmarksService::gBookmarkAtom = nsnull;
315: nsIAtom* BookmarksService::gHrefAtom = nsnull;
316: nsIAtom* BookmarksService::gNameAtom = nsnull;
1.5 hyatt 317: nsVoidArray* BookmarksService::gInstances = nsnull;
1.1 hyatt 318:
1.5 hyatt 319: BookmarksService::BookmarksService(BookmarksDataSource* aDataSource)
1.1 hyatt 320: {
1.5 hyatt 321: mDataSource = aDataSource;
1.1 hyatt 322: }
323:
324: BookmarksService::~BookmarksService()
325: {
326: }
327:
328: void
329: BookmarksService::GetRootContent(nsIContent** aResult)
330: {
331: *aResult = nsnull;
1.4 hyatt 332: if (gBookmarks) {
1.1 hyatt 333: nsCOMPtr<nsIDOMElement> elt;
1.4 hyatt 334: nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
1.1 hyatt 335: domDoc->GetDocumentElement(getter_AddRefs(elt));
336: elt->QueryInterface(NS_GET_IID(nsIContent), (void**)aResult); // Addref happens here.
337: }
338: }
339:
340: BookmarkItem*
341: BookmarksService::GetWrapperFor(nsIContent* aContent)
342: {
1.4 hyatt 343: if (!gDictionary)
344: gDictionary = [[NSMutableDictionary alloc] initWithCapacity: 30];
1.1 hyatt 345:
346: PRUint32 contentID;
347: aContent->GetContentID(&contentID);
348:
1.4 hyatt 349: BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: contentID]];
1.1 hyatt 350: if (item)
351: return item;
352: else {
353: // Create an item.
354: item = [[[BookmarkItem alloc] init] autorelease]; // The dictionary retains us.
355: [item setContentNode: aContent];
1.4 hyatt 356: [gDictionary setObject: item forKey: [NSNumber numberWithInt: contentID]];
1.1 hyatt 357: }
358: return item;
359: }
360:
1.5 hyatt 361: void
362: BookmarksService::NotifyObservers(nsIContent* aContainer, PRBool aReloadChildren)
1.4 hyatt 363: {
1.5 hyatt 364: if (!gInstances)
365: return;
366:
367: PRInt32 count = gInstances->Count();
368: for (PRInt32 i = 0; i < count; i++) {
369: BookmarksService* instance = (BookmarksService*)gInstances->ElementAt(i);
370: instance->NotifyObserver(aContainer, aReloadChildren);
371: }
1.6 hyatt 372:
373: FlushBookmarks();
1.4 hyatt 374: }
375:
376:
1.5 hyatt 377: void
378: BookmarksService::NotifyObserver(nsIContent* aContainer, PRBool aReloadChildren)
1.4 hyatt 379: {
1.5 hyatt 380: if (!gDictionary)
381: return;
1.6 hyatt 382:
1.5 hyatt 383: nsCOMPtr<nsIContent> parent;
384: aContainer->GetParent(*getter_AddRefs(parent));
385:
386: BookmarkItem* item = nil;
387: if (parent)
388: // We're not the root.
389: item = GetWrapperFor(aContainer);
390:
391: [mDataSource reloadDataForItem: item reloadChildren: aReloadChildren];
1.4 hyatt 392: }
393:
394: void
395: BookmarksService::AddObserver()
1.1 hyatt 396: {
397: gRefCnt++;
398: if (gRefCnt == 1) {
399: gBookmarkAtom = NS_NewAtom("bookmark");
400: gFolderAtom = NS_NewAtom("folder");
401: gNameAtom = NS_NewAtom("name");
402: gHrefAtom = NS_NewAtom("href");
1.5 hyatt 403: gInstances = new nsVoidArray();
1.8 hyatt 404:
1.4 hyatt 405: nsCOMPtr<nsIFile> profileDir;
406: NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profileDir));
407: profileDir->Append("bookmarks.xml");
408:
409: nsXPIDLCString bookmarksFileURL;
410: NS_GetURLSpecFromFile(profileDir, getter_Copies(bookmarksFileURL));
411:
412: nsCOMPtr<nsIURI> uri;
413: NS_NewURI(getter_AddRefs(uri), bookmarksFileURL.get());
414:
415: nsCOMPtr<nsIXBLService> xblService(do_GetService("@mozilla.org/xbl;1"));
416: xblService->FetchSyncXMLDocument(uri, &gBookmarks); // The addref is here.
417:
418: nsCOMPtr<nsIContent> rootNode;
419: GetRootContent(getter_AddRefs(rootNode));
420: StripWhitespaceNodes(rootNode);
1.1 hyatt 421: }
422:
1.5 hyatt 423: gInstances->AppendElement(this);
1.1 hyatt 424: }
425:
426: void
1.4 hyatt 427: BookmarksService::RemoveObserver()
1.1 hyatt 428: {
429: if (gRefCnt == 0)
430: return;
1.4 hyatt 431:
1.5 hyatt 432: gInstances->RemoveElement(this);
433:
1.1 hyatt 434: gRefCnt--;
435: if (gRefCnt == 0) {
1.4 hyatt 436: NS_IF_RELEASE(gBookmarks);
1.1 hyatt 437: NS_RELEASE(gBookmarkAtom);
438: NS_RELEASE(gFolderAtom);
439: NS_RELEASE(gNameAtom);
440: NS_RELEASE(gHrefAtom);
1.4 hyatt 441: [gDictionary release];
1.1 hyatt 442: }
443: }
444:
1.6 hyatt 445: void
446: BookmarksService::FlushBookmarks()
447: {
448: nsCOMPtr<nsIFile> bookmarksFile;
449: NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(bookmarksFile));
450: bookmarksFile->Append("bookmarks.xml");
451:
452: nsCOMPtr<nsIOutputStream> outputStream;
453: NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), bookmarksFile);
454:
455: nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
456:
457: nsCOMPtr<nsIDOMSerializer> domSerializer(do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID));
458: domSerializer->SerializeToStream(domDoc, outputStream, nsnull);
1.7 hyatt 459: }
460:
461: void
462: BookmarksService::ConstructBookmarksMenu(NSMenu* aMenu, nsIContent* aContent)
463: {
464: nsCOMPtr<nsIContent> content = aContent;
465: if (!content) {
466: GetRootContent(getter_AddRefs(content));
1.8 hyatt 467: GetWrapperFor(content);
1.7 hyatt 468: }
469:
470: // Now walk our children, and for folders also recur into them.
471: PRInt32 childCount;
472: content->ChildCount(childCount);
473:
474: for (PRInt32 i = 0; i < childCount; i++) {
475: nsCOMPtr<nsIContent> child;
476: content->ChildAt(i, *getter_AddRefs(child));
477:
478: // Obtain our name attribute.
479: nsAutoString name;
480: child->GetAttr(kNameSpaceID_None, gNameAtom, name);
481: nsCAutoString nameCStr; nameCStr.AssignWithConversion(name);
482: NSString* title = [NSString stringWithCString: nameCStr.get()];
483:
484: // Create a menu or menu item for the child.
1.8 hyatt 485: NSMenuItem* menuItem = [[[NSMenuItem alloc] initWithTitle: title action: NULL keyEquivalent: @""] autorelease];
486: GetWrapperFor(child);
487: [aMenu addItem: menuItem];
488:
1.7 hyatt 489: nsCOMPtr<nsIAtom> tag;
1.8 hyatt 490: child->GetTag(*getter_AddRefs(tag));
491:
1.7 hyatt 492: if (tag == gFolderAtom) {
493: NSMenu* menu = [[[NSMenu alloc] initWithTitle: title] autorelease];
1.8 hyatt 494: [aMenu setSubmenu: menu forItem: menuItem];
495: [menu setAutoenablesItems: NO];
1.7 hyatt 496: ConstructBookmarksMenu(menu, child);
497: }
498: else {
1.8 hyatt 499: [menuItem setTarget: gMainController];
500: [menuItem setAction: @selector(openMenuBookmark:)];
1.7 hyatt 501: }
1.8 hyatt 502:
503: PRUint32 contentID;
504: child->GetContentID(&contentID);
505: [menuItem setTag: contentID];
1.7 hyatt 506: }
1.6 hyatt 507: }
1.8 hyatt 508:
509: void
510: BookmarksService::OpenMenuBookmark(BrowserWindowController* aController, id aMenuItem)
511: {
512: // Get the corresponding bookmark item.
513: BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: [aMenuItem tag]]];
514:
515: // Get the content node.
516: nsIContent* content = [item contentNode];
517:
518: // Get the href attribute. This is the URL we want to load.
519: nsAutoString href;
520: content->GetAttr(kNameSpaceID_None, gHrefAtom, href);
521: nsCAutoString cref; cref.AssignWithConversion(href);
522: if (cref.IsEmpty())
523: return;
524:
525: NSString* url = [NSString stringWithCString: cref.get()];
526:
527: // Now load the URL in the window.
528: [aController loadURL:[NSURL URLWithString: url]];
529: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>