Fix a slew of bookmark dnd bugs in the sidebar and personal toolbar. (bug 143094)

This commit is contained in:
pinkerton%netscape.com 2002-06-25 18:21:07 +00:00
Родитель c82c7b9aae
Коммит 6552d49b49
24 изменённых файлов: 1732 добавлений и 804 удалений

Просмотреть файл

@ -45,6 +45,7 @@
#import "CHBookmarksToolbar.h"
#import "CHExtendedOutlineView.h"
@class BookmarkItem;
class BookmarksService;
class nsIAtom;
@ -93,6 +94,10 @@ class nsIAtom;
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
- (BOOL)outlineView:(NSOutlineView *)ov writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard;
- (NSDragOperation)outlineView:(NSOutlineView*)ov validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index;
- (BOOL)outlineView:(NSOutlineView*)ov acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index;
- (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren;
// Delegate methods
@ -106,8 +111,9 @@ class nsIAtom;
nsIContent* mContentNode;
}
-(nsIContent*)contentNode;
-(void)setContentNode: (nsIContent*)aContentNode;
- (nsIContent*)contentNode;
- (void)setContentNode: (nsIContent*)aContentNode;
- (NSNumber*)contentID;
- (id)copyWithZone:(NSZone *)aZone;
@end
@ -123,9 +129,9 @@ public:
void AddObserver();
void RemoveObserver();
static void BookmarkAdded(nsIContent* aContainer, nsIContent* aChild);
static void BookmarkChanged(nsIContent* aItem);
static void BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild);
static void BookmarkAdded(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush = true);
static void BookmarkChanged(nsIContent* aItem, bool shouldFlush = true);
static void BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush = true);
static void AddBookmarkToFolder(nsString& aURL, nsString& aTitle, nsIDOMElement* aFolder, nsIDOMElement* aBeforeElt);
static void MoveBookmarkToFolder(nsIDOMElement* aBookmark, nsIDOMElement* aFolder, nsIDOMElement* aBeforeElt);
@ -133,7 +139,9 @@ public:
public:
static void GetRootContent(nsIContent** aResult);
static BookmarkItem* GetRootItem();
static BookmarkItem* GetWrapperFor(nsIContent* aItem);
static BookmarkItem* GetWrapperFor(PRUint32 contentID);
static void FlushBookmarks();
static void ConstructBookmarksMenu(NSMenu* aMenu, nsIContent* aContent);
@ -153,10 +161,12 @@ public:
static NSString* ResolveKeyword(NSString* aKeyword);
static NSImage* CreateIconForBookmark(nsIDOMElement* aElement);
static BOOL DoAncestorsIncludeNode(BookmarkItem* bookmark, BookmarkItem* searchItem);
static bool IsBookmarkDropValid(BookmarkItem* proposedParent, int index, NSArray* draggedIDs);
static bool PerformBookmarkDrop(BookmarkItem* parent, int index, NSArray* draggedIDs);
static void DragBookmark(nsIDOMElement* aElement, NSView* aView, NSEvent* aEvent);
static void CompleteBookmarkDrag(NSPasteboard* aPasteboard, nsIDOMElement* aFolderElt, nsIDOMElement* aBeforeElt, int aPosition);
static void DropURL(NSString* title, NSURL* url, BookmarkItem* parent, int index);
public:
// Global counter and pointers to our singletons.

Просмотреть файл

@ -182,11 +182,11 @@
NSPopUpButton* popup = [mBrowserWindowController getAddBookmarkFolder];
BookmarksService::ConstructAddBookmarkFolderList(popup, item);
[NSApp beginSheet: [mBrowserWindowController getAddBookmarkSheetWindow]
modalForWindow: [mBrowserWindowController window]
modalDelegate: nil //self
didEndSelector: nil //@selector(sheetDidEnd:)
contextInfo: nil];
[NSApp beginSheet: [mBrowserWindowController getAddBookmarkSheetWindow]
modalForWindow: [mBrowserWindowController window]
modalDelegate: nil //self
didEndSelector: nil //@selector(sheetDidEnd:)
contextInfo: nil];
}
-(void)endAddBookmark: (int)aCode
@ -299,10 +299,10 @@
int count = [itemsToDelete count];
for (int i = 0; i < count; i++) {
BookmarkItem* item = [itemsToDelete objectAtIndex: i];
[self deleteBookmark: item];
[self deleteBookmark: item];
}
}
}
}
-(void)deleteBookmark:(id)aItem
{
@ -346,7 +346,7 @@
content->GetAttr(kNameSpaceID_None, BookmarksService::gHrefAtom, href);
if (!href.IsEmpty()) {
NSString* url = [NSString stringWithCharacters: href.get() length: href.Length()];
[[[mBrowserWindowController getBrowserWrapper] getBrowserView] loadURI:[NSURL URLWithString: url] flags: NSLoadFlagsNone];
[[[mBrowserWindowController getBrowserWrapper] getBrowserView] loadURI:[NSURL URLWithString: url] flags: NSLoadFlagsNone];
// Focus and activate our content area.
[[[mBrowserWindowController getBrowserWrapper] getBrowserView] setActive: YES];
}
@ -367,7 +367,7 @@
//
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
return NO;
return NO;
}
- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
@ -436,12 +436,12 @@
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
NSString *columnName = [tableColumn identifier];
NSMutableAttributedString *cellValue = [[NSMutableAttributedString alloc] init];
NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:nil];
NSTextAttachment *textAttachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper];
NSMutableAttributedString *attachmentAttrString = nil;
NSCell *attachmentAttrStringCell;
NSString *columnName = [tableColumn identifier];
NSMutableAttributedString *cellValue = [[NSMutableAttributedString alloc] init];
NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:nil];
NSTextAttachment *textAttachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper];
NSMutableAttributedString *attachmentAttrString = nil;
NSCell *attachmentAttrStringCell;
if ([columnName isEqualToString: @"name"]) {
nsIContent* content = [item contentNode];
@ -449,8 +449,7 @@
content->GetAttr(kNameSpaceID_None, BookmarksService::gNameAtom, nameAttr);
//Set cell's textual contents
[cellValue replaceCharactersInRange:NSMakeRange(0, [cellValue length])
withString:[NSString stringWithCharacters: nameAttr.get() length: nameAttr.Length()]];
[cellValue replaceCharactersInRange:NSMakeRange(0, [cellValue length]) withString:[NSString stringWithCharacters: nameAttr.get() length: nameAttr.Length()]];
//Create an attributed string to hold the empty attachment, then release the components.
attachmentAttrString = [[NSMutableAttributedString attributedStringWithAttachment:textAttachment] retain];
@ -458,9 +457,7 @@
[fileWrapper release];
//Get the cell of the text attachment.
attachmentAttrStringCell = (NSCell *)[(NSTextAttachment *)[attachmentAttrString attribute:NSAttachmentAttributeName
atIndex:0
effectiveRange:nil] attachmentCell];
attachmentAttrStringCell = (NSCell *)[(NSTextAttachment *)[attachmentAttrString attribute:NSAttachmentAttributeName atIndex:0 effectiveRange:nil] attachmentCell];
//Figure out which image to add, and set the cell's image.
// Use the bookmark groups image for groups.
if ([self outlineView:outlineView isItemExpandable:item]) {
@ -521,73 +518,97 @@
#endif
}
- (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren
{
printf("Reloading?\n");
if (!item)
[mOutlineView reloadData];
else if ([mOutlineView isItemExpanded: item])
[mOutlineView reloadItem: item reloadChildren: aReloadChildren];
}
- (BOOL)outlineView:(NSOutlineView*)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index
- (BOOL)outlineView:(NSOutlineView *)ov writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard
{
BookmarkItem* beforeItem = nil;
nsCOMPtr<nsIDOMElement> beforeElt;
nsCOMPtr<nsIDOMElement> folderElt;
nsCOMPtr<nsIContent> folderContent;
if (index == NSOutlineViewDropOnItemIndex)
if (!mBookmarks || [mOutlineView selectedRow] == -1) {
return NO;
}
#ifdef FILTER_DESCENDANT_ON_DRAG
NSArray *toDrag = BookmarksService::FilterOutDescendantsForDrag(items);
#else
NSArray *toDrag = items;
#endif
int count = [toDrag count];
if (count > 0) {
// Create Pasteboard Data
NSMutableArray *draggedID = [NSMutableArray arrayWithCapacity: count];
for (int i = 0; i < count; i++)
[draggedID addObject: [[toDrag objectAtIndex: i] contentID]];
[pboard declareTypes: [NSArray arrayWithObject: @"MozBookmarkType"] owner: self];
[pboard setPropertyList: draggedID forType: @"MozBookmarkType"];
return YES;
}
// get the folder element
if (!item)
mBookmarks->GetRootContent(getter_AddRefs(folderContent));
else
folderContent = [item contentNode];
folderElt = do_QueryInterface(folderContent);
// get the element to insert before, if there is one
PRInt32 childCount = 0;
folderContent->ChildCount(childCount);
if (index < childCount)
beforeItem = [[outlineView dataSource] outlineView:outlineView child:index ofItem:item];
if (beforeItem)
beforeElt = do_QueryInterface([beforeItem contentNode]);
// insert the dragged stuff into bookmarks
BookmarksService::CompleteBookmarkDrag([info draggingPasteboard], folderElt, beforeElt,
BookmarksService::CHInsertBefore);
return YES;
return NO;
}
- (NSDragOperation)outlineView:(NSOutlineView*)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index
- (NSDragOperation)outlineView:(NSOutlineView*)ov validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index
{
NSArray* types = [[info draggingPasteboard] types];
// if the index is -1, deny the drop
if (index == NSOutlineViewDropOnItemIndex)
return NSDragOperationNone;
return NSDragOperationGeneric;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard
{
NSMutableArray* contentIds = [NSMutableArray array];
for (unsigned int i = 0; i < [items count]; ++i) {
nsCOMPtr<nsIContent> content = [[items objectAtIndex:i] contentNode];
PRUint32 contentId;
content->GetContentID(&contentId);
[contentIds addObject:[NSNumber numberWithInt:contentId]];
if ([types containsObject: @"MozBookmarkType"]) {
NSArray *draggedIDs = [[info draggingPasteboard] propertyListForType: @"MozBookmarkType"];
BookmarkItem* parent;
parent = (item) ? item : BookmarksService::GetRootItem();
return (BookmarksService::IsBookmarkDropValid(parent, index, draggedIDs)) ? NSDragOperationGeneric : NSDragOperationNone;
} else if ([types containsObject: @"MozURLType"]) {
return NSDragOperationGeneric;
}
[pboard declareTypes:[NSArray arrayWithObject:@"MozBookmarkType"] owner:outlineView];
[pboard setPropertyList:contentIds forType:@"MozBookmarkType"];
return YES;
return NSDragOperationNone;
}
- (BOOL)outlineView:(NSOutlineView*)ov acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index {
NSArray *types = [[info draggingPasteboard] types];
BookmarkItem* parent = (item) ? item : BookmarksService::GetRootItem();
if ([types containsObject: @"MozBookmarkType"]) {
NSArray *draggedItems = [[info draggingPasteboard] propertyListForType: @"MozBookmarkType"];
BookmarksService::PerformBookmarkDrop(parent, index, draggedItems);
return YES;
} else if ([types containsObject: @"MozURLType"]) {
NSDictionary* data = [[info draggingPasteboard] propertyListForType: @"MozURLType"];
nsCOMPtr<nsIDOMElement> parentElt;
parentElt = do_QueryInterface([parent contentNode]);
PRInt32 childCount = 0;
[item contentNode]->ChildCount(childCount);
if (index >= childCount)
return NO;
BookmarkItem* beforeItem;
beforeItem = [[ov dataSource] outlineView:ov child:index ofItem:item];
if (!beforeItem)
return NO;
nsCOMPtr<nsIDOMElement> beforeElt;
beforeElt = do_QueryInterface([beforeItem contentNode]);
nsAutoString url; url.AssignWithConversion([[data objectForKey:@"url"] cString]);
nsAutoString title; title.AssignWithConversion([[data objectForKey:@"title"] cString]);
BookmarksService::AddBookmarkToFolder(url, title, parentElt, beforeElt);
return YES;
}
return NO;
}
- (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren
{
if (!item)
[mOutlineView reloadData];
else if ([mOutlineView isItemExpanded: item])
[mOutlineView reloadItem: item reloadChildren: aReloadChildren];
}
-(IBAction)openBookmarkInNewTab:(id)aSender
{
@ -711,19 +732,36 @@
@implementation BookmarkItem
-(nsIContent*)contentNode
{
return mContentNode;
return mContentNode;
}
- (NSNumber*)contentID
{
PRUint32 contentID = 0;
mContentNode->GetContentID(&contentID);
return [NSNumber numberWithInt: contentID];
}
- (NSString *)description
{
nsCOMPtr<nsIContent> item = [self contentNode];
nsCOMPtr<nsIDOMElement> element(do_QueryInterface(item));
nsAutoString href;
element->GetAttribute(NS_LITERAL_STRING("name"), href);
NSString* info = [NSString stringWithCharacters: href.get() length: href.Length()];
return [NSString stringWithFormat:@"<BookmarkItem, name = \"%@\">", info];
}
-(void)setContentNode: (nsIContent*)aContentNode
{
mContentNode = aContentNode;
mContentNode = aContentNode;
}
- (id)copyWithZone:(NSZone *)aZone
{
BookmarkItem* copy = [[[self class] allocWithZone: aZone] init];
[copy setContentNode: mContentNode];
return copy;
BookmarkItem* copy = [[[self class] allocWithZone: aZone] init];
[copy setContentNode: mContentNode];
return copy;
}
@end
@ -732,25 +770,26 @@
static void
StripWhitespaceNodes(nsIContent* aElement)
{
PRInt32 childCount;
aElement->ChildCount(childCount);
for (PRInt32 i = 0; i < childCount; i++) {
nsCOMPtr<nsIContent> child;
aElement->ChildAt(i, *getter_AddRefs(child));
nsCOMPtr<nsITextContent> text = do_QueryInterface(child);
if (text) {
PRBool isEmpty;
text->IsOnlyWhitespace(&isEmpty);
if (isEmpty) {
// This node contained nothing but whitespace.
// Remove it from the content model.
aElement->RemoveChildAt(i, PR_TRUE);
i--; // Decrement our count, since we just removed this child.
childCount--; // Also decrement our total count.
}
}
else StripWhitespaceNodes(child);
PRInt32 childCount = 0;
aElement->ChildCount(childCount);
for (PRInt32 i = 0; i < childCount; i++) {
nsCOMPtr<nsIContent> child;
aElement->ChildAt(i, *getter_AddRefs(child));
nsCOMPtr<nsITextContent> text = do_QueryInterface(child);
if (text) {
PRBool isEmpty = PR_FALSE;
text->IsOnlyWhitespace(&isEmpty);
if (isEmpty) {
// This node contained nothing but whitespace.
// Remove it from the content model.
aElement->RemoveChildAt(i, PR_TRUE);
i--; // Decrement our count, since we just removed this child.
childCount--; // Also decrement our total count.
}
}
else
StripWhitespaceNodes(child);
}
}
PRUint32 BookmarksService::gRefCnt = 0;
@ -792,34 +831,50 @@ BookmarksService::~BookmarksService()
void
BookmarksService::GetRootContent(nsIContent** aResult)
{
*aResult = nsnull;
if (gBookmarks) {
nsCOMPtr<nsIDOMElement> elt;
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
domDoc->GetDocumentElement(getter_AddRefs(elt));
elt->QueryInterface(NS_GET_IID(nsIContent), (void**)aResult); // Addref happens here.
}
*aResult = nsnull;
if (gBookmarks) {
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
if (!domDoc) return;
nsCOMPtr<nsIDOMElement> elt;
domDoc->GetDocumentElement(getter_AddRefs(elt));
if (elt)
elt->QueryInterface(NS_GET_IID(nsIContent), (void**)aResult); // Addref happens here.
}
}
BookmarkItem*
BookmarksService::GetRootItem() {
nsCOMPtr<nsIContent> rootContent;
BookmarksService::GetRootContent(getter_AddRefs(rootContent));
BookmarkItem* rootItem = BookmarksService::GetWrapperFor(rootContent);
return rootItem;
}
BookmarkItem*
BookmarksService::GetWrapperFor(nsIContent* aContent)
{
if (!gDictionary)
gDictionary = [[NSMutableDictionary alloc] initWithCapacity: 30];
PRUint32 contentID;
aContent->GetContentID(&contentID);
BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: contentID]];
if (item)
return item;
else {
// Create an item.
item = [[[BookmarkItem alloc] init] autorelease]; // The dictionary retains us.
[item setContentNode: aContent];
[gDictionary setObject: item forKey: [NSNumber numberWithInt: contentID]];
}
if (!gDictionary)
gDictionary = [[NSMutableDictionary alloc] initWithCapacity: 30];
PRUint32 contentID = 0;
aContent->GetContentID(&contentID);
BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: contentID]];
if (item)
return item;
// Create an item.
item = [[[BookmarkItem alloc] init] autorelease]; // The dictionary retains us.
[item setContentNode: aContent];
[gDictionary setObject: item forKey: [NSNumber numberWithInt: contentID]];
return item;
}
BookmarkItem*
BookmarksService::GetWrapperFor(PRUint32 contentID) {
BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithUnsignedInt: contentID]];
return item;
}
NSMenu*
@ -841,7 +896,7 @@ BookmarksService::LocateMenu(nsIContent* aContent)
}
void
BookmarksService::BookmarkAdded(nsIContent* aContainer, nsIContent* aChild)
BookmarksService::BookmarkAdded(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush = true)
{
if (!gInstances || !gDictionary)
return;
@ -883,11 +938,12 @@ BookmarksService::BookmarkAdded(nsIContent* aContainer, nsIContent* aChild)
}
}
FlushBookmarks();
if (shouldFlush)
FlushBookmarks();
}
void
BookmarksService::BookmarkChanged(nsIContent* aItem)
BookmarksService::BookmarkChanged(nsIContent* aItem, bool shouldFlush = true)
{
if (!gInstances || !gDictionary)
return;
@ -902,11 +958,12 @@ BookmarksService::BookmarkChanged(nsIContent* aItem)
}
}
FlushBookmarks();
if (shouldFlush)
FlushBookmarks();
}
void
BookmarksService::BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild)
BookmarksService::BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush = true)
{
if (!gInstances)
return;
@ -940,14 +997,15 @@ BookmarksService::BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild)
else {
// We're the menu.
NSMenu* menu = LocateMenu(aContainer);
PRUint32 contentID;
PRUint32 contentID = 0;
aChild->GetContentID(&contentID);
NSMenuItem* childItem = [menu itemWithTag: contentID];
[menu removeItem: childItem];
}
}
FlushBookmarks();
if (shouldFlush)
FlushBookmarks();
}
void
@ -969,7 +1027,7 @@ BookmarksService::AddObserver()
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profileDir));
profileDir->Append(NS_LITERAL_STRING("bookmarks.xml"));
PRBool fileExists;
PRBool fileExists = PR_FALSE;
profileDir->Exists(&fileExists);
// If the bookmarks file does not exist, copy from the defaults so we don't
@ -1119,9 +1177,10 @@ BookmarksService::FlushBookmarks()
nsCOMPtr<nsIOutputStream> outputStream;
NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), bookmarksFile);
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
nsCOMPtr<nsIDOMSerializer> domSerializer(do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID));
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
nsCOMPtr<nsIDOMSerializer> domSerializer(do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID));
if (domSerializer)
domSerializer->SerializeToStream(domDoc, outputStream, nsnull);
}
@ -1592,63 +1651,160 @@ BookmarksService::CreateIconForBookmark(nsIDOMElement* aElement)
return [NSImage imageNamed:@"groupbookmark"];
}
void
BookmarksService::DragBookmark(nsIDOMElement* aElement, NSView* aView, NSEvent* aEvent)
{
NSPasteboard *pboard;
NSString* title;
// Is searchItem equal to bookmark or bookmark's parent, grandparent, etc?
BOOL
BookmarksService::DoAncestorsIncludeNode(BookmarkItem* bookmark, BookmarkItem* searchItem) {
nsCOMPtr<nsIContent> search = [searchItem contentNode];
nsCOMPtr<nsIContent> current = [bookmark contentNode];
nsCOMPtr<nsIContent> root;
GetRootContent(getter_AddRefs(root));
// If the search item is the root node, return yes immediatly
if (search == root)
return YES;
// for each ancestor
while (current) {
// If this is the root node we can't search farther, and there was no match
if (current == root)
return NO;
// If the two nodes match, then the search term is an ancestor of the given bookmark
if (search == current)
return YES;
// If a match wasn't found, set up the next node to compare
nsCOMPtr<nsIContent> oldCurrent = current;
oldCurrent->GetParent(*getter_AddRefs(current));
}
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
PRUint32 contentId;
content->GetContentID(&contentId);
pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
[pboard declareTypes:[NSArray arrayWithObject:@"MozBookmarkType"] owner:aView];
[pboard setPropertyList:[NSArray arrayWithObject:[NSNumber numberWithInt:contentId]] forType:@"MozBookmarkType"];
nsAutoString nameStr;
aElement->GetAttribute(NS_LITERAL_STRING("name"), nameStr);
title = [NSString stringWithCharacters: nameStr.get() length: nameStr.Length()];
[aView dragImage: [MainController createImageForDragging: CreateIconForBookmark(aElement) title:title]
at:NSMakePoint(0,0) offset:NSMakeSize(0,0)
event:aEvent pasteboard:pboard source:aView slideBack:YES];
return NO;
}
void
BookmarksService::CompleteBookmarkDrag(NSPasteboard* aPasteboard, nsIDOMElement* aFolderElt,
nsIDOMElement* aBeforeElt, int aPosition)
#ifdef FILTER_DESCENDANT_ON_DRAG
/*
this has been disabled because it is too slow, and can cause a large
delay when the user is dragging lots of items. this needs to get
fixed someday.
It should filter out every node whose parent is also being dragged.
*/
NSArray*
BookmarksService::FilterOutDescendantsForDrag(NSArray* nodes)
{
NSArray* contentIds;
nsCOMPtr<nsIDOMElement> beforeElt = aBeforeElt;
if (aPosition == BookmarksService::CHInsertAfter && aBeforeElt) {
nsCOMPtr<nsIDOMNode> beforeNode;
aBeforeElt->GetNextSibling(getter_AddRefs(beforeNode));
beforeElt = do_QueryInterface(beforeNode);
}
if (aPosition == BookmarksService::CHInsertInto) {
aFolderElt = aBeforeElt;
beforeElt = nsnull;
}
NSMutableArray *toDrag = [NSMutableArray arrayWithArray: nodes];
unsigned int i = 0;
while (i < [toDrag count]) {
BookmarkItem* item = [toDrag objectAtIndex: i];
bool matchFound = false;
// check for recognized drag types
contentIds = [aPasteboard propertyListForType: @"MozBookmarkType"];
if (contentIds) {
// drag type is chimera bookmarks
for (unsigned int i = 0; i < [contentIds count]; ++i) {
BookmarkItem* item = [gDictionary objectForKey: [contentIds objectAtIndex:i]];
nsCOMPtr<nsIDOMElement> bookmarkElt = do_QueryInterface([item contentNode]);
MoveBookmarkToFolder(bookmarkElt, aFolderElt, beforeElt);
for (unsigned int j = 0; j < [toDrag count] && matchFound == NO; j++) {
if (i != j) // Don't compare to self, will always match
matchFound = BookmarksService::DoAncestorsIncludeNode(item, [toDrag objectAtIndex: j]);
}
} else {
// add bookmark for chimera url type
NSDictionary* data = [aPasteboard propertyListForType: @"MozURLType"];
nsAutoString url; url.AssignWithConversion([[data objectForKey:@"url"] cString]);
nsAutoString title; title.AssignWithConversion([[data objectForKey:@"title"] cString]);
AddBookmarkToFolder(url, title, aFolderElt, beforeElt);
// if a match was found, remove the node from the array
if (matchFound)
[toDrag removeObjectAtIndex: i];
else
i++;
}
return toDrag;
}
#endif
bool
BookmarksService::IsBookmarkDropValid(BookmarkItem* proposedParent, int index, NSArray* draggedIDs) {
NSMutableArray *draggedItems = [NSMutableArray arrayWithCapacity: [draggedIDs count]];
BOOL toolbarRootMoving = NO;
for (unsigned int i = 0; i < [draggedIDs count]; i++) {
NSNumber* contentID = [draggedIDs objectAtIndex: i];
BookmarkItem* bookmarkItem = BookmarksService::GetWrapperFor([contentID unsignedIntValue]);
nsCOMPtr<nsIContent> itemContent = [bookmarkItem contentNode];
nsCOMPtr<nsIDOMElement> itemElement(do_QueryInterface(itemContent));
if (itemElement == BookmarksService::gToolbarRoot)
toolbarRootMoving = YES;
if (bookmarkItem)
[draggedItems addObject: bookmarkItem];
}
// If we are being dropped into the top level, allow it
if ([proposedParent contentNode] == [BookmarksService::GetRootItem() contentNode])
return true;
// If we are not being dropped on the top level, and the toolbar root is being moved, disallow
if (toolbarRootMoving)
return false;
// Make sure that we are not being dropped into one of our own children
// If the proposed parent, or any of it's ancestors matches one of the nodes being dragged
// then deny the drag.
for (unsigned int i = 0; i < [draggedItems count]; i++) {
if (BookmarksService::DoAncestorsIncludeNode(proposedParent, [draggedItems objectAtIndex: i])) {
return false;
}
}
return true;
}
bool
BookmarksService::PerformBookmarkDrop(BookmarkItem* parent, int index, NSArray* draggedIDs) {
NSEnumerator *enumerator = [draggedIDs reverseObjectEnumerator];
NSNumber *contentID;
// for each item being dragged
while ( (contentID = [enumerator nextObject]) ) {
// get dragged node
nsCOMPtr<nsIContent> draggedNode = [GetWrapperFor([contentID unsignedIntValue]) contentNode];
// get the dragged nodes parent
nsCOMPtr<nsIContent> draggedParent;
if (draggedNode)
draggedNode->GetParent(*getter_AddRefs(draggedParent));
// get the proposed parent
nsCOMPtr<nsIContent> proposedParent = [parent contentNode];
PRInt32 existingIndex = 0;
if (draggedParent)
draggedParent->IndexOf(draggedNode, existingIndex);
// if the deleted nodes parent and the proposed parents are equal
// and if the deleted point is eariler in the list than the inserted point
if (proposedParent == draggedParent && existingIndex < index) {
index--; // if so, move the inserted point up one to compensate
}
// remove it from the tree
if (draggedParent)
draggedParent->RemoveChildAt(existingIndex, PR_TRUE);
BookmarkRemoved(draggedParent, draggedNode, false);
// insert into new position
if (proposedParent)
proposedParent->InsertChildAt(draggedNode, index, PR_TRUE, PR_TRUE);
BookmarkAdded(proposedParent, draggedNode, false);
}
FlushBookmarks();
return true;
}
void
BookmarksService::DropURL(NSString* title, NSURL* url, BookmarkItem* parent, int index)
{
NSLog(@"DropURL not implemented yet\n");
}

Просмотреть файл

@ -34,6 +34,7 @@
if ( (self = [super initWithFrame:frame]) ) {
mElement = nsnull;
[self setBezelStyle: NSRegularSquareBezelStyle];
[self setButtonType: NSMomentaryChangeButton];
[self setBordered: NO];
[self setImagePosition: NSImageLeft];
[self setRefusesFirstResponder: YES];
@ -138,7 +139,11 @@
// XXX mouseDragged is never called because buttons cancel dragging while you mouse down
// I have to fix this in an ugly way, by doing the "click" stuff myself and never relying
// on the superclass for that. Bah!
BookmarksService::DragBookmark(mElement, self, aEvent);
// perhaps you could just implement mouseUp to perform the action (which should be the case
// things shouldn't happen on mouse down) Then does mouseDragged get overridden?
// BookmarksService::DragBookmark(mElement, self, aEvent);
}
@end

Просмотреть файл

@ -40,7 +40,7 @@
if (operation == NSDragOperationDelete) {
NSArray* contentIds = nil;
NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
contentIds = [pboard propertyListForType:@"MozBookmarkType"];
contentIds = [pboard propertyListForType: @"MozBookmarkType"];
if (contentIds) {
for (unsigned int i = 0; i < [contentIds count]; ++i) {
BookmarkItem* item = [BookmarksService::gDictionary objectForKey: [contentIds objectAtIndex:i]];

Просмотреть файл

@ -309,18 +309,82 @@
- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
{
return YES;
BookmarkItem* parent;
int index = 0;
NSArray *draggedItems = [[sender draggingPasteboard] propertyListForType: @"MozBookmarkType"];
// If we are dropping into a folder
if (mDragInsertionPosition == BookmarksService::CHInsertInto) {
nsCOMPtr<nsIDOMElement> parentElt = [mDragInsertionButton element];
nsCOMPtr<nsIContent> parentContent(do_QueryInterface(parentElt));
parent = BookmarksService::GetWrapperFor(parentContent);
index = 0;
}
// If we are dropping onto the toolbar directly
else if (mDragInsertionPosition == BookmarksService::CHInsertBefore ||
mDragInsertionPosition == BookmarksService::CHInsertAfter) {
nsCOMPtr<nsIDOMElement> rootElt = BookmarksService::gToolbarRoot;
nsCOMPtr<nsIContent> rootContent(do_QueryInterface(rootElt));
parent = BookmarksService::GetWrapperFor(rootContent);
index = [mButtons indexOfObject: mDragInsertionButton];
if (index == NSNotFound)
rootContent->ChildCount(index);
else if (mDragInsertionPosition == BookmarksService::CHInsertAfter)
index++;
} else {
mDragInsertionButton = nil;
mDragInsertionPosition = BookmarksService::CHInsertNone;
[self setNeedsDisplay:YES];
return NO;
}
bool valid = BookmarksService::IsBookmarkDropValid(parent, index, draggedItems);
if (!valid) {
mDragInsertionButton = nil;
mDragInsertionPosition = BookmarksService::CHInsertNone;
[self setNeedsDisplay:YES];
}
return valid;
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
BookmarksService::CompleteBookmarkDrag([sender draggingPasteboard], BookmarksService::gToolbarRoot,
mDragInsertionButton ? [mDragInsertionButton element] : nil,
mDragInsertionPosition);
BookmarkItem* parent;
int index = 0;
NSArray *draggedItems = [[sender draggingPasteboard] propertyListForType: @"MozBookmarkType"];
// If we are dropping into a folder
if (mDragInsertionPosition == BookmarksService::CHInsertInto) {
nsCOMPtr<nsIDOMElement> parentElt = [mDragInsertionButton element];
nsCOMPtr<nsIContent> parentContent(do_QueryInterface(parentElt));
parent = BookmarksService::GetWrapperFor(parentContent);
index = 0;
}
// If we are dropping onto the toolbar directly
else if (mDragInsertionPosition == BookmarksService::CHInsertBefore ||
mDragInsertionPosition == BookmarksService::CHInsertAfter) {
nsCOMPtr<nsIDOMElement> rootElt = BookmarksService::gToolbarRoot;
nsCOMPtr<nsIContent> rootContent(do_QueryInterface(rootElt));
parent = BookmarksService::GetWrapperFor(rootContent);
index = [mButtons indexOfObject: mDragInsertionButton];
if (index == NSNotFound)
rootContent->ChildCount(index);
else if (mDragInsertionPosition == BookmarksService::CHInsertAfter)
index++;
} else {
mDragInsertionButton = nil;
mDragInsertionPosition = BookmarksService::CHInsertNone;
[self setNeedsDisplay:YES];
return NO;
}
BookmarksService::PerformBookmarkDrop(parent, index, draggedItems);
mDragInsertionButton = nil;
mDragInsertionPosition = BookmarksService::CHInsertNone;
[self setNeedsDisplay:YES];
return YES;
@ -329,14 +393,11 @@
- (NSRect)insertionRectForButton:(NSView*)aButton position:(int) aPosition
{
if (aPosition == BookmarksService::CHInsertInto) {
return NSMakeRect([aButton frame].origin.x, [aButton frame].origin.y,
[aButton frame].size.width, [aButton frame].size.height);
return NSMakeRect([aButton frame].origin.x, [aButton frame].origin.y, [aButton frame].size.width, [aButton frame].size.height);
} else if (aPosition == BookmarksService::CHInsertAfter) {
return NSMakeRect([aButton frame].origin.x+[aButton frame].size.width, [aButton frame].origin.y,
2, [aButton frame].size.height);
return NSMakeRect([aButton frame].origin.x+[aButton frame].size.width, [aButton frame].origin.y, 2, [aButton frame].size.height);
} else {// if (aPosition == BookmarksService::CHInsertBefore) {
return NSMakeRect([aButton frame].origin.x - 2, [aButton frame].origin.y,
2, [aButton frame].size.height);
return NSMakeRect([aButton frame].origin.x - 2, [aButton frame].origin.y, 2, [aButton frame].size.height);
}
}

Просмотреть файл

@ -104,7 +104,7 @@ static void FindOptionWithContentID(nsIDOMHTMLSelectElement* aSel, PRUint32 aID,
-(id)initWithSelect:(nsIDOMHTMLSelectElement*)aSel
{
if (self = [super init]) {
if ( (self = [super init]) ) {
mSelectElt = aSel;
}
return self;

Просмотреть файл

@ -34,6 +34,7 @@
if ( (self = [super initWithFrame:frame]) ) {
mElement = nsnull;
[self setBezelStyle: NSRegularSquareBezelStyle];
[self setButtonType: NSMomentaryChangeButton];
[self setBordered: NO];
[self setImagePosition: NSImageLeft];
[self setRefusesFirstResponder: YES];
@ -138,7 +139,11 @@
// XXX mouseDragged is never called because buttons cancel dragging while you mouse down
// I have to fix this in an ugly way, by doing the "click" stuff myself and never relying
// on the superclass for that. Bah!
BookmarksService::DragBookmark(mElement, self, aEvent);
// perhaps you could just implement mouseUp to perform the action (which should be the case
// things shouldn't happen on mouse down) Then does mouseDragged get overridden?
// BookmarksService::DragBookmark(mElement, self, aEvent);
}
@end

Просмотреть файл

@ -40,7 +40,7 @@
if (operation == NSDragOperationDelete) {
NSArray* contentIds = nil;
NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
contentIds = [pboard propertyListForType:@"MozBookmarkType"];
contentIds = [pboard propertyListForType: @"MozBookmarkType"];
if (contentIds) {
for (unsigned int i = 0; i < [contentIds count]; ++i) {
BookmarkItem* item = [BookmarksService::gDictionary objectForKey: [contentIds objectAtIndex:i]];

Просмотреть файл

@ -45,6 +45,7 @@
#import "CHBookmarksToolbar.h"
#import "CHExtendedOutlineView.h"
@class BookmarkItem;
class BookmarksService;
class nsIAtom;
@ -93,6 +94,10 @@ class nsIAtom;
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
- (BOOL)outlineView:(NSOutlineView *)ov writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard;
- (NSDragOperation)outlineView:(NSOutlineView*)ov validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index;
- (BOOL)outlineView:(NSOutlineView*)ov acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index;
- (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren;
// Delegate methods
@ -106,8 +111,9 @@ class nsIAtom;
nsIContent* mContentNode;
}
-(nsIContent*)contentNode;
-(void)setContentNode: (nsIContent*)aContentNode;
- (nsIContent*)contentNode;
- (void)setContentNode: (nsIContent*)aContentNode;
- (NSNumber*)contentID;
- (id)copyWithZone:(NSZone *)aZone;
@end
@ -123,9 +129,9 @@ public:
void AddObserver();
void RemoveObserver();
static void BookmarkAdded(nsIContent* aContainer, nsIContent* aChild);
static void BookmarkChanged(nsIContent* aItem);
static void BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild);
static void BookmarkAdded(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush = true);
static void BookmarkChanged(nsIContent* aItem, bool shouldFlush = true);
static void BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush = true);
static void AddBookmarkToFolder(nsString& aURL, nsString& aTitle, nsIDOMElement* aFolder, nsIDOMElement* aBeforeElt);
static void MoveBookmarkToFolder(nsIDOMElement* aBookmark, nsIDOMElement* aFolder, nsIDOMElement* aBeforeElt);
@ -133,7 +139,9 @@ public:
public:
static void GetRootContent(nsIContent** aResult);
static BookmarkItem* GetRootItem();
static BookmarkItem* GetWrapperFor(nsIContent* aItem);
static BookmarkItem* GetWrapperFor(PRUint32 contentID);
static void FlushBookmarks();
static void ConstructBookmarksMenu(NSMenu* aMenu, nsIContent* aContent);
@ -153,10 +161,12 @@ public:
static NSString* ResolveKeyword(NSString* aKeyword);
static NSImage* CreateIconForBookmark(nsIDOMElement* aElement);
static BOOL DoAncestorsIncludeNode(BookmarkItem* bookmark, BookmarkItem* searchItem);
static bool IsBookmarkDropValid(BookmarkItem* proposedParent, int index, NSArray* draggedIDs);
static bool PerformBookmarkDrop(BookmarkItem* parent, int index, NSArray* draggedIDs);
static void DragBookmark(nsIDOMElement* aElement, NSView* aView, NSEvent* aEvent);
static void CompleteBookmarkDrag(NSPasteboard* aPasteboard, nsIDOMElement* aFolderElt, nsIDOMElement* aBeforeElt, int aPosition);
static void DropURL(NSString* title, NSURL* url, BookmarkItem* parent, int index);
public:
// Global counter and pointers to our singletons.

Просмотреть файл

@ -182,11 +182,11 @@
NSPopUpButton* popup = [mBrowserWindowController getAddBookmarkFolder];
BookmarksService::ConstructAddBookmarkFolderList(popup, item);
[NSApp beginSheet: [mBrowserWindowController getAddBookmarkSheetWindow]
modalForWindow: [mBrowserWindowController window]
modalDelegate: nil //self
didEndSelector: nil //@selector(sheetDidEnd:)
contextInfo: nil];
[NSApp beginSheet: [mBrowserWindowController getAddBookmarkSheetWindow]
modalForWindow: [mBrowserWindowController window]
modalDelegate: nil //self
didEndSelector: nil //@selector(sheetDidEnd:)
contextInfo: nil];
}
-(void)endAddBookmark: (int)aCode
@ -299,10 +299,10 @@
int count = [itemsToDelete count];
for (int i = 0; i < count; i++) {
BookmarkItem* item = [itemsToDelete objectAtIndex: i];
[self deleteBookmark: item];
[self deleteBookmark: item];
}
}
}
}
-(void)deleteBookmark:(id)aItem
{
@ -346,7 +346,7 @@
content->GetAttr(kNameSpaceID_None, BookmarksService::gHrefAtom, href);
if (!href.IsEmpty()) {
NSString* url = [NSString stringWithCharacters: href.get() length: href.Length()];
[[[mBrowserWindowController getBrowserWrapper] getBrowserView] loadURI:[NSURL URLWithString: url] flags: NSLoadFlagsNone];
[[[mBrowserWindowController getBrowserWrapper] getBrowserView] loadURI:[NSURL URLWithString: url] flags: NSLoadFlagsNone];
// Focus and activate our content area.
[[[mBrowserWindowController getBrowserWrapper] getBrowserView] setActive: YES];
}
@ -367,7 +367,7 @@
//
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
return NO;
return NO;
}
- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
@ -436,12 +436,12 @@
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
NSString *columnName = [tableColumn identifier];
NSMutableAttributedString *cellValue = [[NSMutableAttributedString alloc] init];
NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:nil];
NSTextAttachment *textAttachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper];
NSMutableAttributedString *attachmentAttrString = nil;
NSCell *attachmentAttrStringCell;
NSString *columnName = [tableColumn identifier];
NSMutableAttributedString *cellValue = [[NSMutableAttributedString alloc] init];
NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:nil];
NSTextAttachment *textAttachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper];
NSMutableAttributedString *attachmentAttrString = nil;
NSCell *attachmentAttrStringCell;
if ([columnName isEqualToString: @"name"]) {
nsIContent* content = [item contentNode];
@ -449,8 +449,7 @@
content->GetAttr(kNameSpaceID_None, BookmarksService::gNameAtom, nameAttr);
//Set cell's textual contents
[cellValue replaceCharactersInRange:NSMakeRange(0, [cellValue length])
withString:[NSString stringWithCharacters: nameAttr.get() length: nameAttr.Length()]];
[cellValue replaceCharactersInRange:NSMakeRange(0, [cellValue length]) withString:[NSString stringWithCharacters: nameAttr.get() length: nameAttr.Length()]];
//Create an attributed string to hold the empty attachment, then release the components.
attachmentAttrString = [[NSMutableAttributedString attributedStringWithAttachment:textAttachment] retain];
@ -458,9 +457,7 @@
[fileWrapper release];
//Get the cell of the text attachment.
attachmentAttrStringCell = (NSCell *)[(NSTextAttachment *)[attachmentAttrString attribute:NSAttachmentAttributeName
atIndex:0
effectiveRange:nil] attachmentCell];
attachmentAttrStringCell = (NSCell *)[(NSTextAttachment *)[attachmentAttrString attribute:NSAttachmentAttributeName atIndex:0 effectiveRange:nil] attachmentCell];
//Figure out which image to add, and set the cell's image.
// Use the bookmark groups image for groups.
if ([self outlineView:outlineView isItemExpandable:item]) {
@ -521,73 +518,97 @@
#endif
}
- (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren
{
printf("Reloading?\n");
if (!item)
[mOutlineView reloadData];
else if ([mOutlineView isItemExpanded: item])
[mOutlineView reloadItem: item reloadChildren: aReloadChildren];
}
- (BOOL)outlineView:(NSOutlineView*)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index
- (BOOL)outlineView:(NSOutlineView *)ov writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard
{
BookmarkItem* beforeItem = nil;
nsCOMPtr<nsIDOMElement> beforeElt;
nsCOMPtr<nsIDOMElement> folderElt;
nsCOMPtr<nsIContent> folderContent;
if (index == NSOutlineViewDropOnItemIndex)
if (!mBookmarks || [mOutlineView selectedRow] == -1) {
return NO;
}
#ifdef FILTER_DESCENDANT_ON_DRAG
NSArray *toDrag = BookmarksService::FilterOutDescendantsForDrag(items);
#else
NSArray *toDrag = items;
#endif
int count = [toDrag count];
if (count > 0) {
// Create Pasteboard Data
NSMutableArray *draggedID = [NSMutableArray arrayWithCapacity: count];
for (int i = 0; i < count; i++)
[draggedID addObject: [[toDrag objectAtIndex: i] contentID]];
[pboard declareTypes: [NSArray arrayWithObject: @"MozBookmarkType"] owner: self];
[pboard setPropertyList: draggedID forType: @"MozBookmarkType"];
return YES;
}
// get the folder element
if (!item)
mBookmarks->GetRootContent(getter_AddRefs(folderContent));
else
folderContent = [item contentNode];
folderElt = do_QueryInterface(folderContent);
// get the element to insert before, if there is one
PRInt32 childCount = 0;
folderContent->ChildCount(childCount);
if (index < childCount)
beforeItem = [[outlineView dataSource] outlineView:outlineView child:index ofItem:item];
if (beforeItem)
beforeElt = do_QueryInterface([beforeItem contentNode]);
// insert the dragged stuff into bookmarks
BookmarksService::CompleteBookmarkDrag([info draggingPasteboard], folderElt, beforeElt,
BookmarksService::CHInsertBefore);
return YES;
return NO;
}
- (NSDragOperation)outlineView:(NSOutlineView*)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index
- (NSDragOperation)outlineView:(NSOutlineView*)ov validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index
{
NSArray* types = [[info draggingPasteboard] types];
// if the index is -1, deny the drop
if (index == NSOutlineViewDropOnItemIndex)
return NSDragOperationNone;
return NSDragOperationGeneric;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard
{
NSMutableArray* contentIds = [NSMutableArray array];
for (unsigned int i = 0; i < [items count]; ++i) {
nsCOMPtr<nsIContent> content = [[items objectAtIndex:i] contentNode];
PRUint32 contentId;
content->GetContentID(&contentId);
[contentIds addObject:[NSNumber numberWithInt:contentId]];
if ([types containsObject: @"MozBookmarkType"]) {
NSArray *draggedIDs = [[info draggingPasteboard] propertyListForType: @"MozBookmarkType"];
BookmarkItem* parent;
parent = (item) ? item : BookmarksService::GetRootItem();
return (BookmarksService::IsBookmarkDropValid(parent, index, draggedIDs)) ? NSDragOperationGeneric : NSDragOperationNone;
} else if ([types containsObject: @"MozURLType"]) {
return NSDragOperationGeneric;
}
[pboard declareTypes:[NSArray arrayWithObject:@"MozBookmarkType"] owner:outlineView];
[pboard setPropertyList:contentIds forType:@"MozBookmarkType"];
return YES;
return NSDragOperationNone;
}
- (BOOL)outlineView:(NSOutlineView*)ov acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index {
NSArray *types = [[info draggingPasteboard] types];
BookmarkItem* parent = (item) ? item : BookmarksService::GetRootItem();
if ([types containsObject: @"MozBookmarkType"]) {
NSArray *draggedItems = [[info draggingPasteboard] propertyListForType: @"MozBookmarkType"];
BookmarksService::PerformBookmarkDrop(parent, index, draggedItems);
return YES;
} else if ([types containsObject: @"MozURLType"]) {
NSDictionary* data = [[info draggingPasteboard] propertyListForType: @"MozURLType"];
nsCOMPtr<nsIDOMElement> parentElt;
parentElt = do_QueryInterface([parent contentNode]);
PRInt32 childCount = 0;
[item contentNode]->ChildCount(childCount);
if (index >= childCount)
return NO;
BookmarkItem* beforeItem;
beforeItem = [[ov dataSource] outlineView:ov child:index ofItem:item];
if (!beforeItem)
return NO;
nsCOMPtr<nsIDOMElement> beforeElt;
beforeElt = do_QueryInterface([beforeItem contentNode]);
nsAutoString url; url.AssignWithConversion([[data objectForKey:@"url"] cString]);
nsAutoString title; title.AssignWithConversion([[data objectForKey:@"title"] cString]);
BookmarksService::AddBookmarkToFolder(url, title, parentElt, beforeElt);
return YES;
}
return NO;
}
- (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren
{
if (!item)
[mOutlineView reloadData];
else if ([mOutlineView isItemExpanded: item])
[mOutlineView reloadItem: item reloadChildren: aReloadChildren];
}
-(IBAction)openBookmarkInNewTab:(id)aSender
{
@ -711,19 +732,36 @@
@implementation BookmarkItem
-(nsIContent*)contentNode
{
return mContentNode;
return mContentNode;
}
- (NSNumber*)contentID
{
PRUint32 contentID = 0;
mContentNode->GetContentID(&contentID);
return [NSNumber numberWithInt: contentID];
}
- (NSString *)description
{
nsCOMPtr<nsIContent> item = [self contentNode];
nsCOMPtr<nsIDOMElement> element(do_QueryInterface(item));
nsAutoString href;
element->GetAttribute(NS_LITERAL_STRING("name"), href);
NSString* info = [NSString stringWithCharacters: href.get() length: href.Length()];
return [NSString stringWithFormat:@"<BookmarkItem, name = \"%@\">", info];
}
-(void)setContentNode: (nsIContent*)aContentNode
{
mContentNode = aContentNode;
mContentNode = aContentNode;
}
- (id)copyWithZone:(NSZone *)aZone
{
BookmarkItem* copy = [[[self class] allocWithZone: aZone] init];
[copy setContentNode: mContentNode];
return copy;
BookmarkItem* copy = [[[self class] allocWithZone: aZone] init];
[copy setContentNode: mContentNode];
return copy;
}
@end
@ -732,25 +770,26 @@
static void
StripWhitespaceNodes(nsIContent* aElement)
{
PRInt32 childCount;
aElement->ChildCount(childCount);
for (PRInt32 i = 0; i < childCount; i++) {
nsCOMPtr<nsIContent> child;
aElement->ChildAt(i, *getter_AddRefs(child));
nsCOMPtr<nsITextContent> text = do_QueryInterface(child);
if (text) {
PRBool isEmpty;
text->IsOnlyWhitespace(&isEmpty);
if (isEmpty) {
// This node contained nothing but whitespace.
// Remove it from the content model.
aElement->RemoveChildAt(i, PR_TRUE);
i--; // Decrement our count, since we just removed this child.
childCount--; // Also decrement our total count.
}
}
else StripWhitespaceNodes(child);
PRInt32 childCount = 0;
aElement->ChildCount(childCount);
for (PRInt32 i = 0; i < childCount; i++) {
nsCOMPtr<nsIContent> child;
aElement->ChildAt(i, *getter_AddRefs(child));
nsCOMPtr<nsITextContent> text = do_QueryInterface(child);
if (text) {
PRBool isEmpty = PR_FALSE;
text->IsOnlyWhitespace(&isEmpty);
if (isEmpty) {
// This node contained nothing but whitespace.
// Remove it from the content model.
aElement->RemoveChildAt(i, PR_TRUE);
i--; // Decrement our count, since we just removed this child.
childCount--; // Also decrement our total count.
}
}
else
StripWhitespaceNodes(child);
}
}
PRUint32 BookmarksService::gRefCnt = 0;
@ -792,34 +831,50 @@ BookmarksService::~BookmarksService()
void
BookmarksService::GetRootContent(nsIContent** aResult)
{
*aResult = nsnull;
if (gBookmarks) {
nsCOMPtr<nsIDOMElement> elt;
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
domDoc->GetDocumentElement(getter_AddRefs(elt));
elt->QueryInterface(NS_GET_IID(nsIContent), (void**)aResult); // Addref happens here.
}
*aResult = nsnull;
if (gBookmarks) {
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
if (!domDoc) return;
nsCOMPtr<nsIDOMElement> elt;
domDoc->GetDocumentElement(getter_AddRefs(elt));
if (elt)
elt->QueryInterface(NS_GET_IID(nsIContent), (void**)aResult); // Addref happens here.
}
}
BookmarkItem*
BookmarksService::GetRootItem() {
nsCOMPtr<nsIContent> rootContent;
BookmarksService::GetRootContent(getter_AddRefs(rootContent));
BookmarkItem* rootItem = BookmarksService::GetWrapperFor(rootContent);
return rootItem;
}
BookmarkItem*
BookmarksService::GetWrapperFor(nsIContent* aContent)
{
if (!gDictionary)
gDictionary = [[NSMutableDictionary alloc] initWithCapacity: 30];
PRUint32 contentID;
aContent->GetContentID(&contentID);
BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: contentID]];
if (item)
return item;
else {
// Create an item.
item = [[[BookmarkItem alloc] init] autorelease]; // The dictionary retains us.
[item setContentNode: aContent];
[gDictionary setObject: item forKey: [NSNumber numberWithInt: contentID]];
}
if (!gDictionary)
gDictionary = [[NSMutableDictionary alloc] initWithCapacity: 30];
PRUint32 contentID = 0;
aContent->GetContentID(&contentID);
BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: contentID]];
if (item)
return item;
// Create an item.
item = [[[BookmarkItem alloc] init] autorelease]; // The dictionary retains us.
[item setContentNode: aContent];
[gDictionary setObject: item forKey: [NSNumber numberWithInt: contentID]];
return item;
}
BookmarkItem*
BookmarksService::GetWrapperFor(PRUint32 contentID) {
BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithUnsignedInt: contentID]];
return item;
}
NSMenu*
@ -841,7 +896,7 @@ BookmarksService::LocateMenu(nsIContent* aContent)
}
void
BookmarksService::BookmarkAdded(nsIContent* aContainer, nsIContent* aChild)
BookmarksService::BookmarkAdded(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush = true)
{
if (!gInstances || !gDictionary)
return;
@ -883,11 +938,12 @@ BookmarksService::BookmarkAdded(nsIContent* aContainer, nsIContent* aChild)
}
}
FlushBookmarks();
if (shouldFlush)
FlushBookmarks();
}
void
BookmarksService::BookmarkChanged(nsIContent* aItem)
BookmarksService::BookmarkChanged(nsIContent* aItem, bool shouldFlush = true)
{
if (!gInstances || !gDictionary)
return;
@ -902,11 +958,12 @@ BookmarksService::BookmarkChanged(nsIContent* aItem)
}
}
FlushBookmarks();
if (shouldFlush)
FlushBookmarks();
}
void
BookmarksService::BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild)
BookmarksService::BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush = true)
{
if (!gInstances)
return;
@ -940,14 +997,15 @@ BookmarksService::BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild)
else {
// We're the menu.
NSMenu* menu = LocateMenu(aContainer);
PRUint32 contentID;
PRUint32 contentID = 0;
aChild->GetContentID(&contentID);
NSMenuItem* childItem = [menu itemWithTag: contentID];
[menu removeItem: childItem];
}
}
FlushBookmarks();
if (shouldFlush)
FlushBookmarks();
}
void
@ -969,7 +1027,7 @@ BookmarksService::AddObserver()
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profileDir));
profileDir->Append(NS_LITERAL_STRING("bookmarks.xml"));
PRBool fileExists;
PRBool fileExists = PR_FALSE;
profileDir->Exists(&fileExists);
// If the bookmarks file does not exist, copy from the defaults so we don't
@ -1119,9 +1177,10 @@ BookmarksService::FlushBookmarks()
nsCOMPtr<nsIOutputStream> outputStream;
NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), bookmarksFile);
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
nsCOMPtr<nsIDOMSerializer> domSerializer(do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID));
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
nsCOMPtr<nsIDOMSerializer> domSerializer(do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID));
if (domSerializer)
domSerializer->SerializeToStream(domDoc, outputStream, nsnull);
}
@ -1592,63 +1651,160 @@ BookmarksService::CreateIconForBookmark(nsIDOMElement* aElement)
return [NSImage imageNamed:@"groupbookmark"];
}
void
BookmarksService::DragBookmark(nsIDOMElement* aElement, NSView* aView, NSEvent* aEvent)
{
NSPasteboard *pboard;
NSString* title;
// Is searchItem equal to bookmark or bookmark's parent, grandparent, etc?
BOOL
BookmarksService::DoAncestorsIncludeNode(BookmarkItem* bookmark, BookmarkItem* searchItem) {
nsCOMPtr<nsIContent> search = [searchItem contentNode];
nsCOMPtr<nsIContent> current = [bookmark contentNode];
nsCOMPtr<nsIContent> root;
GetRootContent(getter_AddRefs(root));
// If the search item is the root node, return yes immediatly
if (search == root)
return YES;
// for each ancestor
while (current) {
// If this is the root node we can't search farther, and there was no match
if (current == root)
return NO;
// If the two nodes match, then the search term is an ancestor of the given bookmark
if (search == current)
return YES;
// If a match wasn't found, set up the next node to compare
nsCOMPtr<nsIContent> oldCurrent = current;
oldCurrent->GetParent(*getter_AddRefs(current));
}
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
PRUint32 contentId;
content->GetContentID(&contentId);
pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
[pboard declareTypes:[NSArray arrayWithObject:@"MozBookmarkType"] owner:aView];
[pboard setPropertyList:[NSArray arrayWithObject:[NSNumber numberWithInt:contentId]] forType:@"MozBookmarkType"];
nsAutoString nameStr;
aElement->GetAttribute(NS_LITERAL_STRING("name"), nameStr);
title = [NSString stringWithCharacters: nameStr.get() length: nameStr.Length()];
[aView dragImage: [MainController createImageForDragging: CreateIconForBookmark(aElement) title:title]
at:NSMakePoint(0,0) offset:NSMakeSize(0,0)
event:aEvent pasteboard:pboard source:aView slideBack:YES];
return NO;
}
void
BookmarksService::CompleteBookmarkDrag(NSPasteboard* aPasteboard, nsIDOMElement* aFolderElt,
nsIDOMElement* aBeforeElt, int aPosition)
#ifdef FILTER_DESCENDANT_ON_DRAG
/*
this has been disabled because it is too slow, and can cause a large
delay when the user is dragging lots of items. this needs to get
fixed someday.
It should filter out every node whose parent is also being dragged.
*/
NSArray*
BookmarksService::FilterOutDescendantsForDrag(NSArray* nodes)
{
NSArray* contentIds;
nsCOMPtr<nsIDOMElement> beforeElt = aBeforeElt;
if (aPosition == BookmarksService::CHInsertAfter && aBeforeElt) {
nsCOMPtr<nsIDOMNode> beforeNode;
aBeforeElt->GetNextSibling(getter_AddRefs(beforeNode));
beforeElt = do_QueryInterface(beforeNode);
}
if (aPosition == BookmarksService::CHInsertInto) {
aFolderElt = aBeforeElt;
beforeElt = nsnull;
}
NSMutableArray *toDrag = [NSMutableArray arrayWithArray: nodes];
unsigned int i = 0;
while (i < [toDrag count]) {
BookmarkItem* item = [toDrag objectAtIndex: i];
bool matchFound = false;
// check for recognized drag types
contentIds = [aPasteboard propertyListForType: @"MozBookmarkType"];
if (contentIds) {
// drag type is chimera bookmarks
for (unsigned int i = 0; i < [contentIds count]; ++i) {
BookmarkItem* item = [gDictionary objectForKey: [contentIds objectAtIndex:i]];
nsCOMPtr<nsIDOMElement> bookmarkElt = do_QueryInterface([item contentNode]);
MoveBookmarkToFolder(bookmarkElt, aFolderElt, beforeElt);
for (unsigned int j = 0; j < [toDrag count] && matchFound == NO; j++) {
if (i != j) // Don't compare to self, will always match
matchFound = BookmarksService::DoAncestorsIncludeNode(item, [toDrag objectAtIndex: j]);
}
} else {
// add bookmark for chimera url type
NSDictionary* data = [aPasteboard propertyListForType: @"MozURLType"];
nsAutoString url; url.AssignWithConversion([[data objectForKey:@"url"] cString]);
nsAutoString title; title.AssignWithConversion([[data objectForKey:@"title"] cString]);
AddBookmarkToFolder(url, title, aFolderElt, beforeElt);
// if a match was found, remove the node from the array
if (matchFound)
[toDrag removeObjectAtIndex: i];
else
i++;
}
return toDrag;
}
#endif
bool
BookmarksService::IsBookmarkDropValid(BookmarkItem* proposedParent, int index, NSArray* draggedIDs) {
NSMutableArray *draggedItems = [NSMutableArray arrayWithCapacity: [draggedIDs count]];
BOOL toolbarRootMoving = NO;
for (unsigned int i = 0; i < [draggedIDs count]; i++) {
NSNumber* contentID = [draggedIDs objectAtIndex: i];
BookmarkItem* bookmarkItem = BookmarksService::GetWrapperFor([contentID unsignedIntValue]);
nsCOMPtr<nsIContent> itemContent = [bookmarkItem contentNode];
nsCOMPtr<nsIDOMElement> itemElement(do_QueryInterface(itemContent));
if (itemElement == BookmarksService::gToolbarRoot)
toolbarRootMoving = YES;
if (bookmarkItem)
[draggedItems addObject: bookmarkItem];
}
// If we are being dropped into the top level, allow it
if ([proposedParent contentNode] == [BookmarksService::GetRootItem() contentNode])
return true;
// If we are not being dropped on the top level, and the toolbar root is being moved, disallow
if (toolbarRootMoving)
return false;
// Make sure that we are not being dropped into one of our own children
// If the proposed parent, or any of it's ancestors matches one of the nodes being dragged
// then deny the drag.
for (unsigned int i = 0; i < [draggedItems count]; i++) {
if (BookmarksService::DoAncestorsIncludeNode(proposedParent, [draggedItems objectAtIndex: i])) {
return false;
}
}
return true;
}
bool
BookmarksService::PerformBookmarkDrop(BookmarkItem* parent, int index, NSArray* draggedIDs) {
NSEnumerator *enumerator = [draggedIDs reverseObjectEnumerator];
NSNumber *contentID;
// for each item being dragged
while ( (contentID = [enumerator nextObject]) ) {
// get dragged node
nsCOMPtr<nsIContent> draggedNode = [GetWrapperFor([contentID unsignedIntValue]) contentNode];
// get the dragged nodes parent
nsCOMPtr<nsIContent> draggedParent;
if (draggedNode)
draggedNode->GetParent(*getter_AddRefs(draggedParent));
// get the proposed parent
nsCOMPtr<nsIContent> proposedParent = [parent contentNode];
PRInt32 existingIndex = 0;
if (draggedParent)
draggedParent->IndexOf(draggedNode, existingIndex);
// if the deleted nodes parent and the proposed parents are equal
// and if the deleted point is eariler in the list than the inserted point
if (proposedParent == draggedParent && existingIndex < index) {
index--; // if so, move the inserted point up one to compensate
}
// remove it from the tree
if (draggedParent)
draggedParent->RemoveChildAt(existingIndex, PR_TRUE);
BookmarkRemoved(draggedParent, draggedNode, false);
// insert into new position
if (proposedParent)
proposedParent->InsertChildAt(draggedNode, index, PR_TRUE, PR_TRUE);
BookmarkAdded(proposedParent, draggedNode, false);
}
FlushBookmarks();
return true;
}
void
BookmarksService::DropURL(NSString* title, NSURL* url, BookmarkItem* parent, int index)
{
NSLog(@"DropURL not implemented yet\n");
}

Просмотреть файл

@ -309,18 +309,82 @@
- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
{
return YES;
BookmarkItem* parent;
int index = 0;
NSArray *draggedItems = [[sender draggingPasteboard] propertyListForType: @"MozBookmarkType"];
// If we are dropping into a folder
if (mDragInsertionPosition == BookmarksService::CHInsertInto) {
nsCOMPtr<nsIDOMElement> parentElt = [mDragInsertionButton element];
nsCOMPtr<nsIContent> parentContent(do_QueryInterface(parentElt));
parent = BookmarksService::GetWrapperFor(parentContent);
index = 0;
}
// If we are dropping onto the toolbar directly
else if (mDragInsertionPosition == BookmarksService::CHInsertBefore ||
mDragInsertionPosition == BookmarksService::CHInsertAfter) {
nsCOMPtr<nsIDOMElement> rootElt = BookmarksService::gToolbarRoot;
nsCOMPtr<nsIContent> rootContent(do_QueryInterface(rootElt));
parent = BookmarksService::GetWrapperFor(rootContent);
index = [mButtons indexOfObject: mDragInsertionButton];
if (index == NSNotFound)
rootContent->ChildCount(index);
else if (mDragInsertionPosition == BookmarksService::CHInsertAfter)
index++;
} else {
mDragInsertionButton = nil;
mDragInsertionPosition = BookmarksService::CHInsertNone;
[self setNeedsDisplay:YES];
return NO;
}
bool valid = BookmarksService::IsBookmarkDropValid(parent, index, draggedItems);
if (!valid) {
mDragInsertionButton = nil;
mDragInsertionPosition = BookmarksService::CHInsertNone;
[self setNeedsDisplay:YES];
}
return valid;
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
BookmarksService::CompleteBookmarkDrag([sender draggingPasteboard], BookmarksService::gToolbarRoot,
mDragInsertionButton ? [mDragInsertionButton element] : nil,
mDragInsertionPosition);
BookmarkItem* parent;
int index = 0;
NSArray *draggedItems = [[sender draggingPasteboard] propertyListForType: @"MozBookmarkType"];
// If we are dropping into a folder
if (mDragInsertionPosition == BookmarksService::CHInsertInto) {
nsCOMPtr<nsIDOMElement> parentElt = [mDragInsertionButton element];
nsCOMPtr<nsIContent> parentContent(do_QueryInterface(parentElt));
parent = BookmarksService::GetWrapperFor(parentContent);
index = 0;
}
// If we are dropping onto the toolbar directly
else if (mDragInsertionPosition == BookmarksService::CHInsertBefore ||
mDragInsertionPosition == BookmarksService::CHInsertAfter) {
nsCOMPtr<nsIDOMElement> rootElt = BookmarksService::gToolbarRoot;
nsCOMPtr<nsIContent> rootContent(do_QueryInterface(rootElt));
parent = BookmarksService::GetWrapperFor(rootContent);
index = [mButtons indexOfObject: mDragInsertionButton];
if (index == NSNotFound)
rootContent->ChildCount(index);
else if (mDragInsertionPosition == BookmarksService::CHInsertAfter)
index++;
} else {
mDragInsertionButton = nil;
mDragInsertionPosition = BookmarksService::CHInsertNone;
[self setNeedsDisplay:YES];
return NO;
}
BookmarksService::PerformBookmarkDrop(parent, index, draggedItems);
mDragInsertionButton = nil;
mDragInsertionPosition = BookmarksService::CHInsertNone;
[self setNeedsDisplay:YES];
return YES;
@ -329,14 +393,11 @@
- (NSRect)insertionRectForButton:(NSView*)aButton position:(int) aPosition
{
if (aPosition == BookmarksService::CHInsertInto) {
return NSMakeRect([aButton frame].origin.x, [aButton frame].origin.y,
[aButton frame].size.width, [aButton frame].size.height);
return NSMakeRect([aButton frame].origin.x, [aButton frame].origin.y, [aButton frame].size.width, [aButton frame].size.height);
} else if (aPosition == BookmarksService::CHInsertAfter) {
return NSMakeRect([aButton frame].origin.x+[aButton frame].size.width, [aButton frame].origin.y,
2, [aButton frame].size.height);
return NSMakeRect([aButton frame].origin.x+[aButton frame].size.width, [aButton frame].origin.y, 2, [aButton frame].size.height);
} else {// if (aPosition == BookmarksService::CHInsertBefore) {
return NSMakeRect([aButton frame].origin.x - 2, [aButton frame].origin.y,
2, [aButton frame].size.height);
return NSMakeRect([aButton frame].origin.x - 2, [aButton frame].origin.y, 2, [aButton frame].size.height);
}
}

Просмотреть файл

@ -104,7 +104,7 @@ static void FindOptionWithContentID(nsIDOMHTMLSelectElement* aSel, PRUint32 aID,
-(id)initWithSelect:(nsIDOMHTMLSelectElement*)aSel
{
if (self = [super init]) {
if ( (self = [super init]) ) {
mSelectElt = aSel;
}
return self;

Просмотреть файл

@ -45,6 +45,7 @@
#import "CHBookmarksToolbar.h"
#import "CHExtendedOutlineView.h"
@class BookmarkItem;
class BookmarksService;
class nsIAtom;
@ -93,6 +94,10 @@ class nsIAtom;
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
- (BOOL)outlineView:(NSOutlineView *)ov writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard;
- (NSDragOperation)outlineView:(NSOutlineView*)ov validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index;
- (BOOL)outlineView:(NSOutlineView*)ov acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index;
- (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren;
// Delegate methods
@ -106,8 +111,9 @@ class nsIAtom;
nsIContent* mContentNode;
}
-(nsIContent*)contentNode;
-(void)setContentNode: (nsIContent*)aContentNode;
- (nsIContent*)contentNode;
- (void)setContentNode: (nsIContent*)aContentNode;
- (NSNumber*)contentID;
- (id)copyWithZone:(NSZone *)aZone;
@end
@ -123,9 +129,9 @@ public:
void AddObserver();
void RemoveObserver();
static void BookmarkAdded(nsIContent* aContainer, nsIContent* aChild);
static void BookmarkChanged(nsIContent* aItem);
static void BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild);
static void BookmarkAdded(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush = true);
static void BookmarkChanged(nsIContent* aItem, bool shouldFlush = true);
static void BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush = true);
static void AddBookmarkToFolder(nsString& aURL, nsString& aTitle, nsIDOMElement* aFolder, nsIDOMElement* aBeforeElt);
static void MoveBookmarkToFolder(nsIDOMElement* aBookmark, nsIDOMElement* aFolder, nsIDOMElement* aBeforeElt);
@ -133,7 +139,9 @@ public:
public:
static void GetRootContent(nsIContent** aResult);
static BookmarkItem* GetRootItem();
static BookmarkItem* GetWrapperFor(nsIContent* aItem);
static BookmarkItem* GetWrapperFor(PRUint32 contentID);
static void FlushBookmarks();
static void ConstructBookmarksMenu(NSMenu* aMenu, nsIContent* aContent);
@ -153,10 +161,12 @@ public:
static NSString* ResolveKeyword(NSString* aKeyword);
static NSImage* CreateIconForBookmark(nsIDOMElement* aElement);
static BOOL DoAncestorsIncludeNode(BookmarkItem* bookmark, BookmarkItem* searchItem);
static bool IsBookmarkDropValid(BookmarkItem* proposedParent, int index, NSArray* draggedIDs);
static bool PerformBookmarkDrop(BookmarkItem* parent, int index, NSArray* draggedIDs);
static void DragBookmark(nsIDOMElement* aElement, NSView* aView, NSEvent* aEvent);
static void CompleteBookmarkDrag(NSPasteboard* aPasteboard, nsIDOMElement* aFolderElt, nsIDOMElement* aBeforeElt, int aPosition);
static void DropURL(NSString* title, NSURL* url, BookmarkItem* parent, int index);
public:
// Global counter and pointers to our singletons.

Просмотреть файл

@ -182,11 +182,11 @@
NSPopUpButton* popup = [mBrowserWindowController getAddBookmarkFolder];
BookmarksService::ConstructAddBookmarkFolderList(popup, item);
[NSApp beginSheet: [mBrowserWindowController getAddBookmarkSheetWindow]
modalForWindow: [mBrowserWindowController window]
modalDelegate: nil //self
didEndSelector: nil //@selector(sheetDidEnd:)
contextInfo: nil];
[NSApp beginSheet: [mBrowserWindowController getAddBookmarkSheetWindow]
modalForWindow: [mBrowserWindowController window]
modalDelegate: nil //self
didEndSelector: nil //@selector(sheetDidEnd:)
contextInfo: nil];
}
-(void)endAddBookmark: (int)aCode
@ -299,10 +299,10 @@
int count = [itemsToDelete count];
for (int i = 0; i < count; i++) {
BookmarkItem* item = [itemsToDelete objectAtIndex: i];
[self deleteBookmark: item];
[self deleteBookmark: item];
}
}
}
}
-(void)deleteBookmark:(id)aItem
{
@ -346,7 +346,7 @@
content->GetAttr(kNameSpaceID_None, BookmarksService::gHrefAtom, href);
if (!href.IsEmpty()) {
NSString* url = [NSString stringWithCharacters: href.get() length: href.Length()];
[[[mBrowserWindowController getBrowserWrapper] getBrowserView] loadURI:[NSURL URLWithString: url] flags: NSLoadFlagsNone];
[[[mBrowserWindowController getBrowserWrapper] getBrowserView] loadURI:[NSURL URLWithString: url] flags: NSLoadFlagsNone];
// Focus and activate our content area.
[[[mBrowserWindowController getBrowserWrapper] getBrowserView] setActive: YES];
}
@ -367,7 +367,7 @@
//
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
return NO;
return NO;
}
- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
@ -436,12 +436,12 @@
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
NSString *columnName = [tableColumn identifier];
NSMutableAttributedString *cellValue = [[NSMutableAttributedString alloc] init];
NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:nil];
NSTextAttachment *textAttachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper];
NSMutableAttributedString *attachmentAttrString = nil;
NSCell *attachmentAttrStringCell;
NSString *columnName = [tableColumn identifier];
NSMutableAttributedString *cellValue = [[NSMutableAttributedString alloc] init];
NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:nil];
NSTextAttachment *textAttachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper];
NSMutableAttributedString *attachmentAttrString = nil;
NSCell *attachmentAttrStringCell;
if ([columnName isEqualToString: @"name"]) {
nsIContent* content = [item contentNode];
@ -449,8 +449,7 @@
content->GetAttr(kNameSpaceID_None, BookmarksService::gNameAtom, nameAttr);
//Set cell's textual contents
[cellValue replaceCharactersInRange:NSMakeRange(0, [cellValue length])
withString:[NSString stringWithCharacters: nameAttr.get() length: nameAttr.Length()]];
[cellValue replaceCharactersInRange:NSMakeRange(0, [cellValue length]) withString:[NSString stringWithCharacters: nameAttr.get() length: nameAttr.Length()]];
//Create an attributed string to hold the empty attachment, then release the components.
attachmentAttrString = [[NSMutableAttributedString attributedStringWithAttachment:textAttachment] retain];
@ -458,9 +457,7 @@
[fileWrapper release];
//Get the cell of the text attachment.
attachmentAttrStringCell = (NSCell *)[(NSTextAttachment *)[attachmentAttrString attribute:NSAttachmentAttributeName
atIndex:0
effectiveRange:nil] attachmentCell];
attachmentAttrStringCell = (NSCell *)[(NSTextAttachment *)[attachmentAttrString attribute:NSAttachmentAttributeName atIndex:0 effectiveRange:nil] attachmentCell];
//Figure out which image to add, and set the cell's image.
// Use the bookmark groups image for groups.
if ([self outlineView:outlineView isItemExpandable:item]) {
@ -521,73 +518,97 @@
#endif
}
- (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren
{
printf("Reloading?\n");
if (!item)
[mOutlineView reloadData];
else if ([mOutlineView isItemExpanded: item])
[mOutlineView reloadItem: item reloadChildren: aReloadChildren];
}
- (BOOL)outlineView:(NSOutlineView*)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index
- (BOOL)outlineView:(NSOutlineView *)ov writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard
{
BookmarkItem* beforeItem = nil;
nsCOMPtr<nsIDOMElement> beforeElt;
nsCOMPtr<nsIDOMElement> folderElt;
nsCOMPtr<nsIContent> folderContent;
if (index == NSOutlineViewDropOnItemIndex)
if (!mBookmarks || [mOutlineView selectedRow] == -1) {
return NO;
}
#ifdef FILTER_DESCENDANT_ON_DRAG
NSArray *toDrag = BookmarksService::FilterOutDescendantsForDrag(items);
#else
NSArray *toDrag = items;
#endif
int count = [toDrag count];
if (count > 0) {
// Create Pasteboard Data
NSMutableArray *draggedID = [NSMutableArray arrayWithCapacity: count];
for (int i = 0; i < count; i++)
[draggedID addObject: [[toDrag objectAtIndex: i] contentID]];
[pboard declareTypes: [NSArray arrayWithObject: @"MozBookmarkType"] owner: self];
[pboard setPropertyList: draggedID forType: @"MozBookmarkType"];
return YES;
}
// get the folder element
if (!item)
mBookmarks->GetRootContent(getter_AddRefs(folderContent));
else
folderContent = [item contentNode];
folderElt = do_QueryInterface(folderContent);
// get the element to insert before, if there is one
PRInt32 childCount = 0;
folderContent->ChildCount(childCount);
if (index < childCount)
beforeItem = [[outlineView dataSource] outlineView:outlineView child:index ofItem:item];
if (beforeItem)
beforeElt = do_QueryInterface([beforeItem contentNode]);
// insert the dragged stuff into bookmarks
BookmarksService::CompleteBookmarkDrag([info draggingPasteboard], folderElt, beforeElt,
BookmarksService::CHInsertBefore);
return YES;
return NO;
}
- (NSDragOperation)outlineView:(NSOutlineView*)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index
- (NSDragOperation)outlineView:(NSOutlineView*)ov validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index
{
NSArray* types = [[info draggingPasteboard] types];
// if the index is -1, deny the drop
if (index == NSOutlineViewDropOnItemIndex)
return NSDragOperationNone;
return NSDragOperationGeneric;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard
{
NSMutableArray* contentIds = [NSMutableArray array];
for (unsigned int i = 0; i < [items count]; ++i) {
nsCOMPtr<nsIContent> content = [[items objectAtIndex:i] contentNode];
PRUint32 contentId;
content->GetContentID(&contentId);
[contentIds addObject:[NSNumber numberWithInt:contentId]];
if ([types containsObject: @"MozBookmarkType"]) {
NSArray *draggedIDs = [[info draggingPasteboard] propertyListForType: @"MozBookmarkType"];
BookmarkItem* parent;
parent = (item) ? item : BookmarksService::GetRootItem();
return (BookmarksService::IsBookmarkDropValid(parent, index, draggedIDs)) ? NSDragOperationGeneric : NSDragOperationNone;
} else if ([types containsObject: @"MozURLType"]) {
return NSDragOperationGeneric;
}
[pboard declareTypes:[NSArray arrayWithObject:@"MozBookmarkType"] owner:outlineView];
[pboard setPropertyList:contentIds forType:@"MozBookmarkType"];
return YES;
return NSDragOperationNone;
}
- (BOOL)outlineView:(NSOutlineView*)ov acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index {
NSArray *types = [[info draggingPasteboard] types];
BookmarkItem* parent = (item) ? item : BookmarksService::GetRootItem();
if ([types containsObject: @"MozBookmarkType"]) {
NSArray *draggedItems = [[info draggingPasteboard] propertyListForType: @"MozBookmarkType"];
BookmarksService::PerformBookmarkDrop(parent, index, draggedItems);
return YES;
} else if ([types containsObject: @"MozURLType"]) {
NSDictionary* data = [[info draggingPasteboard] propertyListForType: @"MozURLType"];
nsCOMPtr<nsIDOMElement> parentElt;
parentElt = do_QueryInterface([parent contentNode]);
PRInt32 childCount = 0;
[item contentNode]->ChildCount(childCount);
if (index >= childCount)
return NO;
BookmarkItem* beforeItem;
beforeItem = [[ov dataSource] outlineView:ov child:index ofItem:item];
if (!beforeItem)
return NO;
nsCOMPtr<nsIDOMElement> beforeElt;
beforeElt = do_QueryInterface([beforeItem contentNode]);
nsAutoString url; url.AssignWithConversion([[data objectForKey:@"url"] cString]);
nsAutoString title; title.AssignWithConversion([[data objectForKey:@"title"] cString]);
BookmarksService::AddBookmarkToFolder(url, title, parentElt, beforeElt);
return YES;
}
return NO;
}
- (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren
{
if (!item)
[mOutlineView reloadData];
else if ([mOutlineView isItemExpanded: item])
[mOutlineView reloadItem: item reloadChildren: aReloadChildren];
}
-(IBAction)openBookmarkInNewTab:(id)aSender
{
@ -711,19 +732,36 @@
@implementation BookmarkItem
-(nsIContent*)contentNode
{
return mContentNode;
return mContentNode;
}
- (NSNumber*)contentID
{
PRUint32 contentID = 0;
mContentNode->GetContentID(&contentID);
return [NSNumber numberWithInt: contentID];
}
- (NSString *)description
{
nsCOMPtr<nsIContent> item = [self contentNode];
nsCOMPtr<nsIDOMElement> element(do_QueryInterface(item));
nsAutoString href;
element->GetAttribute(NS_LITERAL_STRING("name"), href);
NSString* info = [NSString stringWithCharacters: href.get() length: href.Length()];
return [NSString stringWithFormat:@"<BookmarkItem, name = \"%@\">", info];
}
-(void)setContentNode: (nsIContent*)aContentNode
{
mContentNode = aContentNode;
mContentNode = aContentNode;
}
- (id)copyWithZone:(NSZone *)aZone
{
BookmarkItem* copy = [[[self class] allocWithZone: aZone] init];
[copy setContentNode: mContentNode];
return copy;
BookmarkItem* copy = [[[self class] allocWithZone: aZone] init];
[copy setContentNode: mContentNode];
return copy;
}
@end
@ -732,25 +770,26 @@
static void
StripWhitespaceNodes(nsIContent* aElement)
{
PRInt32 childCount;
aElement->ChildCount(childCount);
for (PRInt32 i = 0; i < childCount; i++) {
nsCOMPtr<nsIContent> child;
aElement->ChildAt(i, *getter_AddRefs(child));
nsCOMPtr<nsITextContent> text = do_QueryInterface(child);
if (text) {
PRBool isEmpty;
text->IsOnlyWhitespace(&isEmpty);
if (isEmpty) {
// This node contained nothing but whitespace.
// Remove it from the content model.
aElement->RemoveChildAt(i, PR_TRUE);
i--; // Decrement our count, since we just removed this child.
childCount--; // Also decrement our total count.
}
}
else StripWhitespaceNodes(child);
PRInt32 childCount = 0;
aElement->ChildCount(childCount);
for (PRInt32 i = 0; i < childCount; i++) {
nsCOMPtr<nsIContent> child;
aElement->ChildAt(i, *getter_AddRefs(child));
nsCOMPtr<nsITextContent> text = do_QueryInterface(child);
if (text) {
PRBool isEmpty = PR_FALSE;
text->IsOnlyWhitespace(&isEmpty);
if (isEmpty) {
// This node contained nothing but whitespace.
// Remove it from the content model.
aElement->RemoveChildAt(i, PR_TRUE);
i--; // Decrement our count, since we just removed this child.
childCount--; // Also decrement our total count.
}
}
else
StripWhitespaceNodes(child);
}
}
PRUint32 BookmarksService::gRefCnt = 0;
@ -792,34 +831,50 @@ BookmarksService::~BookmarksService()
void
BookmarksService::GetRootContent(nsIContent** aResult)
{
*aResult = nsnull;
if (gBookmarks) {
nsCOMPtr<nsIDOMElement> elt;
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
domDoc->GetDocumentElement(getter_AddRefs(elt));
elt->QueryInterface(NS_GET_IID(nsIContent), (void**)aResult); // Addref happens here.
}
*aResult = nsnull;
if (gBookmarks) {
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
if (!domDoc) return;
nsCOMPtr<nsIDOMElement> elt;
domDoc->GetDocumentElement(getter_AddRefs(elt));
if (elt)
elt->QueryInterface(NS_GET_IID(nsIContent), (void**)aResult); // Addref happens here.
}
}
BookmarkItem*
BookmarksService::GetRootItem() {
nsCOMPtr<nsIContent> rootContent;
BookmarksService::GetRootContent(getter_AddRefs(rootContent));
BookmarkItem* rootItem = BookmarksService::GetWrapperFor(rootContent);
return rootItem;
}
BookmarkItem*
BookmarksService::GetWrapperFor(nsIContent* aContent)
{
if (!gDictionary)
gDictionary = [[NSMutableDictionary alloc] initWithCapacity: 30];
PRUint32 contentID;
aContent->GetContentID(&contentID);
BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: contentID]];
if (item)
return item;
else {
// Create an item.
item = [[[BookmarkItem alloc] init] autorelease]; // The dictionary retains us.
[item setContentNode: aContent];
[gDictionary setObject: item forKey: [NSNumber numberWithInt: contentID]];
}
if (!gDictionary)
gDictionary = [[NSMutableDictionary alloc] initWithCapacity: 30];
PRUint32 contentID = 0;
aContent->GetContentID(&contentID);
BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: contentID]];
if (item)
return item;
// Create an item.
item = [[[BookmarkItem alloc] init] autorelease]; // The dictionary retains us.
[item setContentNode: aContent];
[gDictionary setObject: item forKey: [NSNumber numberWithInt: contentID]];
return item;
}
BookmarkItem*
BookmarksService::GetWrapperFor(PRUint32 contentID) {
BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithUnsignedInt: contentID]];
return item;
}
NSMenu*
@ -841,7 +896,7 @@ BookmarksService::LocateMenu(nsIContent* aContent)
}
void
BookmarksService::BookmarkAdded(nsIContent* aContainer, nsIContent* aChild)
BookmarksService::BookmarkAdded(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush = true)
{
if (!gInstances || !gDictionary)
return;
@ -883,11 +938,12 @@ BookmarksService::BookmarkAdded(nsIContent* aContainer, nsIContent* aChild)
}
}
FlushBookmarks();
if (shouldFlush)
FlushBookmarks();
}
void
BookmarksService::BookmarkChanged(nsIContent* aItem)
BookmarksService::BookmarkChanged(nsIContent* aItem, bool shouldFlush = true)
{
if (!gInstances || !gDictionary)
return;
@ -902,11 +958,12 @@ BookmarksService::BookmarkChanged(nsIContent* aItem)
}
}
FlushBookmarks();
if (shouldFlush)
FlushBookmarks();
}
void
BookmarksService::BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild)
BookmarksService::BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush = true)
{
if (!gInstances)
return;
@ -940,14 +997,15 @@ BookmarksService::BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild)
else {
// We're the menu.
NSMenu* menu = LocateMenu(aContainer);
PRUint32 contentID;
PRUint32 contentID = 0;
aChild->GetContentID(&contentID);
NSMenuItem* childItem = [menu itemWithTag: contentID];
[menu removeItem: childItem];
}
}
FlushBookmarks();
if (shouldFlush)
FlushBookmarks();
}
void
@ -969,7 +1027,7 @@ BookmarksService::AddObserver()
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profileDir));
profileDir->Append(NS_LITERAL_STRING("bookmarks.xml"));
PRBool fileExists;
PRBool fileExists = PR_FALSE;
profileDir->Exists(&fileExists);
// If the bookmarks file does not exist, copy from the defaults so we don't
@ -1119,9 +1177,10 @@ BookmarksService::FlushBookmarks()
nsCOMPtr<nsIOutputStream> outputStream;
NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), bookmarksFile);
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
nsCOMPtr<nsIDOMSerializer> domSerializer(do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID));
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
nsCOMPtr<nsIDOMSerializer> domSerializer(do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID));
if (domSerializer)
domSerializer->SerializeToStream(domDoc, outputStream, nsnull);
}
@ -1592,63 +1651,160 @@ BookmarksService::CreateIconForBookmark(nsIDOMElement* aElement)
return [NSImage imageNamed:@"groupbookmark"];
}
void
BookmarksService::DragBookmark(nsIDOMElement* aElement, NSView* aView, NSEvent* aEvent)
{
NSPasteboard *pboard;
NSString* title;
// Is searchItem equal to bookmark or bookmark's parent, grandparent, etc?
BOOL
BookmarksService::DoAncestorsIncludeNode(BookmarkItem* bookmark, BookmarkItem* searchItem) {
nsCOMPtr<nsIContent> search = [searchItem contentNode];
nsCOMPtr<nsIContent> current = [bookmark contentNode];
nsCOMPtr<nsIContent> root;
GetRootContent(getter_AddRefs(root));
// If the search item is the root node, return yes immediatly
if (search == root)
return YES;
// for each ancestor
while (current) {
// If this is the root node we can't search farther, and there was no match
if (current == root)
return NO;
// If the two nodes match, then the search term is an ancestor of the given bookmark
if (search == current)
return YES;
// If a match wasn't found, set up the next node to compare
nsCOMPtr<nsIContent> oldCurrent = current;
oldCurrent->GetParent(*getter_AddRefs(current));
}
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
PRUint32 contentId;
content->GetContentID(&contentId);
pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
[pboard declareTypes:[NSArray arrayWithObject:@"MozBookmarkType"] owner:aView];
[pboard setPropertyList:[NSArray arrayWithObject:[NSNumber numberWithInt:contentId]] forType:@"MozBookmarkType"];
nsAutoString nameStr;
aElement->GetAttribute(NS_LITERAL_STRING("name"), nameStr);
title = [NSString stringWithCharacters: nameStr.get() length: nameStr.Length()];
[aView dragImage: [MainController createImageForDragging: CreateIconForBookmark(aElement) title:title]
at:NSMakePoint(0,0) offset:NSMakeSize(0,0)
event:aEvent pasteboard:pboard source:aView slideBack:YES];
return NO;
}
void
BookmarksService::CompleteBookmarkDrag(NSPasteboard* aPasteboard, nsIDOMElement* aFolderElt,
nsIDOMElement* aBeforeElt, int aPosition)
#ifdef FILTER_DESCENDANT_ON_DRAG
/*
this has been disabled because it is too slow, and can cause a large
delay when the user is dragging lots of items. this needs to get
fixed someday.
It should filter out every node whose parent is also being dragged.
*/
NSArray*
BookmarksService::FilterOutDescendantsForDrag(NSArray* nodes)
{
NSArray* contentIds;
nsCOMPtr<nsIDOMElement> beforeElt = aBeforeElt;
if (aPosition == BookmarksService::CHInsertAfter && aBeforeElt) {
nsCOMPtr<nsIDOMNode> beforeNode;
aBeforeElt->GetNextSibling(getter_AddRefs(beforeNode));
beforeElt = do_QueryInterface(beforeNode);
}
if (aPosition == BookmarksService::CHInsertInto) {
aFolderElt = aBeforeElt;
beforeElt = nsnull;
}
NSMutableArray *toDrag = [NSMutableArray arrayWithArray: nodes];
unsigned int i = 0;
while (i < [toDrag count]) {
BookmarkItem* item = [toDrag objectAtIndex: i];
bool matchFound = false;
// check for recognized drag types
contentIds = [aPasteboard propertyListForType: @"MozBookmarkType"];
if (contentIds) {
// drag type is chimera bookmarks
for (unsigned int i = 0; i < [contentIds count]; ++i) {
BookmarkItem* item = [gDictionary objectForKey: [contentIds objectAtIndex:i]];
nsCOMPtr<nsIDOMElement> bookmarkElt = do_QueryInterface([item contentNode]);
MoveBookmarkToFolder(bookmarkElt, aFolderElt, beforeElt);
for (unsigned int j = 0; j < [toDrag count] && matchFound == NO; j++) {
if (i != j) // Don't compare to self, will always match
matchFound = BookmarksService::DoAncestorsIncludeNode(item, [toDrag objectAtIndex: j]);
}
} else {
// add bookmark for chimera url type
NSDictionary* data = [aPasteboard propertyListForType: @"MozURLType"];
nsAutoString url; url.AssignWithConversion([[data objectForKey:@"url"] cString]);
nsAutoString title; title.AssignWithConversion([[data objectForKey:@"title"] cString]);
AddBookmarkToFolder(url, title, aFolderElt, beforeElt);
// if a match was found, remove the node from the array
if (matchFound)
[toDrag removeObjectAtIndex: i];
else
i++;
}
return toDrag;
}
#endif
bool
BookmarksService::IsBookmarkDropValid(BookmarkItem* proposedParent, int index, NSArray* draggedIDs) {
NSMutableArray *draggedItems = [NSMutableArray arrayWithCapacity: [draggedIDs count]];
BOOL toolbarRootMoving = NO;
for (unsigned int i = 0; i < [draggedIDs count]; i++) {
NSNumber* contentID = [draggedIDs objectAtIndex: i];
BookmarkItem* bookmarkItem = BookmarksService::GetWrapperFor([contentID unsignedIntValue]);
nsCOMPtr<nsIContent> itemContent = [bookmarkItem contentNode];
nsCOMPtr<nsIDOMElement> itemElement(do_QueryInterface(itemContent));
if (itemElement == BookmarksService::gToolbarRoot)
toolbarRootMoving = YES;
if (bookmarkItem)
[draggedItems addObject: bookmarkItem];
}
// If we are being dropped into the top level, allow it
if ([proposedParent contentNode] == [BookmarksService::GetRootItem() contentNode])
return true;
// If we are not being dropped on the top level, and the toolbar root is being moved, disallow
if (toolbarRootMoving)
return false;
// Make sure that we are not being dropped into one of our own children
// If the proposed parent, or any of it's ancestors matches one of the nodes being dragged
// then deny the drag.
for (unsigned int i = 0; i < [draggedItems count]; i++) {
if (BookmarksService::DoAncestorsIncludeNode(proposedParent, [draggedItems objectAtIndex: i])) {
return false;
}
}
return true;
}
bool
BookmarksService::PerformBookmarkDrop(BookmarkItem* parent, int index, NSArray* draggedIDs) {
NSEnumerator *enumerator = [draggedIDs reverseObjectEnumerator];
NSNumber *contentID;
// for each item being dragged
while ( (contentID = [enumerator nextObject]) ) {
// get dragged node
nsCOMPtr<nsIContent> draggedNode = [GetWrapperFor([contentID unsignedIntValue]) contentNode];
// get the dragged nodes parent
nsCOMPtr<nsIContent> draggedParent;
if (draggedNode)
draggedNode->GetParent(*getter_AddRefs(draggedParent));
// get the proposed parent
nsCOMPtr<nsIContent> proposedParent = [parent contentNode];
PRInt32 existingIndex = 0;
if (draggedParent)
draggedParent->IndexOf(draggedNode, existingIndex);
// if the deleted nodes parent and the proposed parents are equal
// and if the deleted point is eariler in the list than the inserted point
if (proposedParent == draggedParent && existingIndex < index) {
index--; // if so, move the inserted point up one to compensate
}
// remove it from the tree
if (draggedParent)
draggedParent->RemoveChildAt(existingIndex, PR_TRUE);
BookmarkRemoved(draggedParent, draggedNode, false);
// insert into new position
if (proposedParent)
proposedParent->InsertChildAt(draggedNode, index, PR_TRUE, PR_TRUE);
BookmarkAdded(proposedParent, draggedNode, false);
}
FlushBookmarks();
return true;
}
void
BookmarksService::DropURL(NSString* title, NSURL* url, BookmarkItem* parent, int index)
{
NSLog(@"DropURL not implemented yet\n");
}

Просмотреть файл

@ -34,6 +34,7 @@
if ( (self = [super initWithFrame:frame]) ) {
mElement = nsnull;
[self setBezelStyle: NSRegularSquareBezelStyle];
[self setButtonType: NSMomentaryChangeButton];
[self setBordered: NO];
[self setImagePosition: NSImageLeft];
[self setRefusesFirstResponder: YES];
@ -138,7 +139,11 @@
// XXX mouseDragged is never called because buttons cancel dragging while you mouse down
// I have to fix this in an ugly way, by doing the "click" stuff myself and never relying
// on the superclass for that. Bah!
BookmarksService::DragBookmark(mElement, self, aEvent);
// perhaps you could just implement mouseUp to perform the action (which should be the case
// things shouldn't happen on mouse down) Then does mouseDragged get overridden?
// BookmarksService::DragBookmark(mElement, self, aEvent);
}
@end

Просмотреть файл

@ -40,7 +40,7 @@
if (operation == NSDragOperationDelete) {
NSArray* contentIds = nil;
NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
contentIds = [pboard propertyListForType:@"MozBookmarkType"];
contentIds = [pboard propertyListForType: @"MozBookmarkType"];
if (contentIds) {
for (unsigned int i = 0; i < [contentIds count]; ++i) {
BookmarkItem* item = [BookmarksService::gDictionary objectForKey: [contentIds objectAtIndex:i]];

Просмотреть файл

@ -309,18 +309,82 @@
- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
{
return YES;
BookmarkItem* parent;
int index = 0;
NSArray *draggedItems = [[sender draggingPasteboard] propertyListForType: @"MozBookmarkType"];
// If we are dropping into a folder
if (mDragInsertionPosition == BookmarksService::CHInsertInto) {
nsCOMPtr<nsIDOMElement> parentElt = [mDragInsertionButton element];
nsCOMPtr<nsIContent> parentContent(do_QueryInterface(parentElt));
parent = BookmarksService::GetWrapperFor(parentContent);
index = 0;
}
// If we are dropping onto the toolbar directly
else if (mDragInsertionPosition == BookmarksService::CHInsertBefore ||
mDragInsertionPosition == BookmarksService::CHInsertAfter) {
nsCOMPtr<nsIDOMElement> rootElt = BookmarksService::gToolbarRoot;
nsCOMPtr<nsIContent> rootContent(do_QueryInterface(rootElt));
parent = BookmarksService::GetWrapperFor(rootContent);
index = [mButtons indexOfObject: mDragInsertionButton];
if (index == NSNotFound)
rootContent->ChildCount(index);
else if (mDragInsertionPosition == BookmarksService::CHInsertAfter)
index++;
} else {
mDragInsertionButton = nil;
mDragInsertionPosition = BookmarksService::CHInsertNone;
[self setNeedsDisplay:YES];
return NO;
}
bool valid = BookmarksService::IsBookmarkDropValid(parent, index, draggedItems);
if (!valid) {
mDragInsertionButton = nil;
mDragInsertionPosition = BookmarksService::CHInsertNone;
[self setNeedsDisplay:YES];
}
return valid;
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
BookmarksService::CompleteBookmarkDrag([sender draggingPasteboard], BookmarksService::gToolbarRoot,
mDragInsertionButton ? [mDragInsertionButton element] : nil,
mDragInsertionPosition);
BookmarkItem* parent;
int index = 0;
NSArray *draggedItems = [[sender draggingPasteboard] propertyListForType: @"MozBookmarkType"];
// If we are dropping into a folder
if (mDragInsertionPosition == BookmarksService::CHInsertInto) {
nsCOMPtr<nsIDOMElement> parentElt = [mDragInsertionButton element];
nsCOMPtr<nsIContent> parentContent(do_QueryInterface(parentElt));
parent = BookmarksService::GetWrapperFor(parentContent);
index = 0;
}
// If we are dropping onto the toolbar directly
else if (mDragInsertionPosition == BookmarksService::CHInsertBefore ||
mDragInsertionPosition == BookmarksService::CHInsertAfter) {
nsCOMPtr<nsIDOMElement> rootElt = BookmarksService::gToolbarRoot;
nsCOMPtr<nsIContent> rootContent(do_QueryInterface(rootElt));
parent = BookmarksService::GetWrapperFor(rootContent);
index = [mButtons indexOfObject: mDragInsertionButton];
if (index == NSNotFound)
rootContent->ChildCount(index);
else if (mDragInsertionPosition == BookmarksService::CHInsertAfter)
index++;
} else {
mDragInsertionButton = nil;
mDragInsertionPosition = BookmarksService::CHInsertNone;
[self setNeedsDisplay:YES];
return NO;
}
BookmarksService::PerformBookmarkDrop(parent, index, draggedItems);
mDragInsertionButton = nil;
mDragInsertionPosition = BookmarksService::CHInsertNone;
[self setNeedsDisplay:YES];
return YES;
@ -329,14 +393,11 @@
- (NSRect)insertionRectForButton:(NSView*)aButton position:(int) aPosition
{
if (aPosition == BookmarksService::CHInsertInto) {
return NSMakeRect([aButton frame].origin.x, [aButton frame].origin.y,
[aButton frame].size.width, [aButton frame].size.height);
return NSMakeRect([aButton frame].origin.x, [aButton frame].origin.y, [aButton frame].size.width, [aButton frame].size.height);
} else if (aPosition == BookmarksService::CHInsertAfter) {
return NSMakeRect([aButton frame].origin.x+[aButton frame].size.width, [aButton frame].origin.y,
2, [aButton frame].size.height);
return NSMakeRect([aButton frame].origin.x+[aButton frame].size.width, [aButton frame].origin.y, 2, [aButton frame].size.height);
} else {// if (aPosition == BookmarksService::CHInsertBefore) {
return NSMakeRect([aButton frame].origin.x - 2, [aButton frame].origin.y,
2, [aButton frame].size.height);
return NSMakeRect([aButton frame].origin.x - 2, [aButton frame].origin.y, 2, [aButton frame].size.height);
}
}

Просмотреть файл

@ -104,7 +104,7 @@ static void FindOptionWithContentID(nsIDOMHTMLSelectElement* aSel, PRUint32 aID,
-(id)initWithSelect:(nsIDOMHTMLSelectElement*)aSel
{
if (self = [super init]) {
if ( (self = [super init]) ) {
mSelectElt = aSel;
}
return self;

Просмотреть файл

@ -34,6 +34,7 @@
if ( (self = [super initWithFrame:frame]) ) {
mElement = nsnull;
[self setBezelStyle: NSRegularSquareBezelStyle];
[self setButtonType: NSMomentaryChangeButton];
[self setBordered: NO];
[self setImagePosition: NSImageLeft];
[self setRefusesFirstResponder: YES];
@ -138,7 +139,11 @@
// XXX mouseDragged is never called because buttons cancel dragging while you mouse down
// I have to fix this in an ugly way, by doing the "click" stuff myself and never relying
// on the superclass for that. Bah!
BookmarksService::DragBookmark(mElement, self, aEvent);
// perhaps you could just implement mouseUp to perform the action (which should be the case
// things shouldn't happen on mouse down) Then does mouseDragged get overridden?
// BookmarksService::DragBookmark(mElement, self, aEvent);
}
@end

Просмотреть файл

@ -40,7 +40,7 @@
if (operation == NSDragOperationDelete) {
NSArray* contentIds = nil;
NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
contentIds = [pboard propertyListForType:@"MozBookmarkType"];
contentIds = [pboard propertyListForType: @"MozBookmarkType"];
if (contentIds) {
for (unsigned int i = 0; i < [contentIds count]; ++i) {
BookmarkItem* item = [BookmarksService::gDictionary objectForKey: [contentIds objectAtIndex:i]];

Просмотреть файл

@ -45,6 +45,7 @@
#import "CHBookmarksToolbar.h"
#import "CHExtendedOutlineView.h"
@class BookmarkItem;
class BookmarksService;
class nsIAtom;
@ -93,6 +94,10 @@ class nsIAtom;
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
- (BOOL)outlineView:(NSOutlineView *)ov writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard;
- (NSDragOperation)outlineView:(NSOutlineView*)ov validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index;
- (BOOL)outlineView:(NSOutlineView*)ov acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index;
- (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren;
// Delegate methods
@ -106,8 +111,9 @@ class nsIAtom;
nsIContent* mContentNode;
}
-(nsIContent*)contentNode;
-(void)setContentNode: (nsIContent*)aContentNode;
- (nsIContent*)contentNode;
- (void)setContentNode: (nsIContent*)aContentNode;
- (NSNumber*)contentID;
- (id)copyWithZone:(NSZone *)aZone;
@end
@ -123,9 +129,9 @@ public:
void AddObserver();
void RemoveObserver();
static void BookmarkAdded(nsIContent* aContainer, nsIContent* aChild);
static void BookmarkChanged(nsIContent* aItem);
static void BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild);
static void BookmarkAdded(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush = true);
static void BookmarkChanged(nsIContent* aItem, bool shouldFlush = true);
static void BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush = true);
static void AddBookmarkToFolder(nsString& aURL, nsString& aTitle, nsIDOMElement* aFolder, nsIDOMElement* aBeforeElt);
static void MoveBookmarkToFolder(nsIDOMElement* aBookmark, nsIDOMElement* aFolder, nsIDOMElement* aBeforeElt);
@ -133,7 +139,9 @@ public:
public:
static void GetRootContent(nsIContent** aResult);
static BookmarkItem* GetRootItem();
static BookmarkItem* GetWrapperFor(nsIContent* aItem);
static BookmarkItem* GetWrapperFor(PRUint32 contentID);
static void FlushBookmarks();
static void ConstructBookmarksMenu(NSMenu* aMenu, nsIContent* aContent);
@ -153,10 +161,12 @@ public:
static NSString* ResolveKeyword(NSString* aKeyword);
static NSImage* CreateIconForBookmark(nsIDOMElement* aElement);
static BOOL DoAncestorsIncludeNode(BookmarkItem* bookmark, BookmarkItem* searchItem);
static bool IsBookmarkDropValid(BookmarkItem* proposedParent, int index, NSArray* draggedIDs);
static bool PerformBookmarkDrop(BookmarkItem* parent, int index, NSArray* draggedIDs);
static void DragBookmark(nsIDOMElement* aElement, NSView* aView, NSEvent* aEvent);
static void CompleteBookmarkDrag(NSPasteboard* aPasteboard, nsIDOMElement* aFolderElt, nsIDOMElement* aBeforeElt, int aPosition);
static void DropURL(NSString* title, NSURL* url, BookmarkItem* parent, int index);
public:
// Global counter and pointers to our singletons.

Просмотреть файл

@ -182,11 +182,11 @@
NSPopUpButton* popup = [mBrowserWindowController getAddBookmarkFolder];
BookmarksService::ConstructAddBookmarkFolderList(popup, item);
[NSApp beginSheet: [mBrowserWindowController getAddBookmarkSheetWindow]
modalForWindow: [mBrowserWindowController window]
modalDelegate: nil //self
didEndSelector: nil //@selector(sheetDidEnd:)
contextInfo: nil];
[NSApp beginSheet: [mBrowserWindowController getAddBookmarkSheetWindow]
modalForWindow: [mBrowserWindowController window]
modalDelegate: nil //self
didEndSelector: nil //@selector(sheetDidEnd:)
contextInfo: nil];
}
-(void)endAddBookmark: (int)aCode
@ -299,10 +299,10 @@
int count = [itemsToDelete count];
for (int i = 0; i < count; i++) {
BookmarkItem* item = [itemsToDelete objectAtIndex: i];
[self deleteBookmark: item];
[self deleteBookmark: item];
}
}
}
}
-(void)deleteBookmark:(id)aItem
{
@ -346,7 +346,7 @@
content->GetAttr(kNameSpaceID_None, BookmarksService::gHrefAtom, href);
if (!href.IsEmpty()) {
NSString* url = [NSString stringWithCharacters: href.get() length: href.Length()];
[[[mBrowserWindowController getBrowserWrapper] getBrowserView] loadURI:[NSURL URLWithString: url] flags: NSLoadFlagsNone];
[[[mBrowserWindowController getBrowserWrapper] getBrowserView] loadURI:[NSURL URLWithString: url] flags: NSLoadFlagsNone];
// Focus and activate our content area.
[[[mBrowserWindowController getBrowserWrapper] getBrowserView] setActive: YES];
}
@ -367,7 +367,7 @@
//
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
return NO;
return NO;
}
- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
@ -436,12 +436,12 @@
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
NSString *columnName = [tableColumn identifier];
NSMutableAttributedString *cellValue = [[NSMutableAttributedString alloc] init];
NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:nil];
NSTextAttachment *textAttachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper];
NSMutableAttributedString *attachmentAttrString = nil;
NSCell *attachmentAttrStringCell;
NSString *columnName = [tableColumn identifier];
NSMutableAttributedString *cellValue = [[NSMutableAttributedString alloc] init];
NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:nil];
NSTextAttachment *textAttachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper];
NSMutableAttributedString *attachmentAttrString = nil;
NSCell *attachmentAttrStringCell;
if ([columnName isEqualToString: @"name"]) {
nsIContent* content = [item contentNode];
@ -449,8 +449,7 @@
content->GetAttr(kNameSpaceID_None, BookmarksService::gNameAtom, nameAttr);
//Set cell's textual contents
[cellValue replaceCharactersInRange:NSMakeRange(0, [cellValue length])
withString:[NSString stringWithCharacters: nameAttr.get() length: nameAttr.Length()]];
[cellValue replaceCharactersInRange:NSMakeRange(0, [cellValue length]) withString:[NSString stringWithCharacters: nameAttr.get() length: nameAttr.Length()]];
//Create an attributed string to hold the empty attachment, then release the components.
attachmentAttrString = [[NSMutableAttributedString attributedStringWithAttachment:textAttachment] retain];
@ -458,9 +457,7 @@
[fileWrapper release];
//Get the cell of the text attachment.
attachmentAttrStringCell = (NSCell *)[(NSTextAttachment *)[attachmentAttrString attribute:NSAttachmentAttributeName
atIndex:0
effectiveRange:nil] attachmentCell];
attachmentAttrStringCell = (NSCell *)[(NSTextAttachment *)[attachmentAttrString attribute:NSAttachmentAttributeName atIndex:0 effectiveRange:nil] attachmentCell];
//Figure out which image to add, and set the cell's image.
// Use the bookmark groups image for groups.
if ([self outlineView:outlineView isItemExpandable:item]) {
@ -521,73 +518,97 @@
#endif
}
- (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren
{
printf("Reloading?\n");
if (!item)
[mOutlineView reloadData];
else if ([mOutlineView isItemExpanded: item])
[mOutlineView reloadItem: item reloadChildren: aReloadChildren];
}
- (BOOL)outlineView:(NSOutlineView*)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index
- (BOOL)outlineView:(NSOutlineView *)ov writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard
{
BookmarkItem* beforeItem = nil;
nsCOMPtr<nsIDOMElement> beforeElt;
nsCOMPtr<nsIDOMElement> folderElt;
nsCOMPtr<nsIContent> folderContent;
if (index == NSOutlineViewDropOnItemIndex)
if (!mBookmarks || [mOutlineView selectedRow] == -1) {
return NO;
}
#ifdef FILTER_DESCENDANT_ON_DRAG
NSArray *toDrag = BookmarksService::FilterOutDescendantsForDrag(items);
#else
NSArray *toDrag = items;
#endif
int count = [toDrag count];
if (count > 0) {
// Create Pasteboard Data
NSMutableArray *draggedID = [NSMutableArray arrayWithCapacity: count];
for (int i = 0; i < count; i++)
[draggedID addObject: [[toDrag objectAtIndex: i] contentID]];
[pboard declareTypes: [NSArray arrayWithObject: @"MozBookmarkType"] owner: self];
[pboard setPropertyList: draggedID forType: @"MozBookmarkType"];
return YES;
}
// get the folder element
if (!item)
mBookmarks->GetRootContent(getter_AddRefs(folderContent));
else
folderContent = [item contentNode];
folderElt = do_QueryInterface(folderContent);
// get the element to insert before, if there is one
PRInt32 childCount = 0;
folderContent->ChildCount(childCount);
if (index < childCount)
beforeItem = [[outlineView dataSource] outlineView:outlineView child:index ofItem:item];
if (beforeItem)
beforeElt = do_QueryInterface([beforeItem contentNode]);
// insert the dragged stuff into bookmarks
BookmarksService::CompleteBookmarkDrag([info draggingPasteboard], folderElt, beforeElt,
BookmarksService::CHInsertBefore);
return YES;
return NO;
}
- (NSDragOperation)outlineView:(NSOutlineView*)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index
- (NSDragOperation)outlineView:(NSOutlineView*)ov validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index
{
NSArray* types = [[info draggingPasteboard] types];
// if the index is -1, deny the drop
if (index == NSOutlineViewDropOnItemIndex)
return NSDragOperationNone;
return NSDragOperationGeneric;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard
{
NSMutableArray* contentIds = [NSMutableArray array];
for (unsigned int i = 0; i < [items count]; ++i) {
nsCOMPtr<nsIContent> content = [[items objectAtIndex:i] contentNode];
PRUint32 contentId;
content->GetContentID(&contentId);
[contentIds addObject:[NSNumber numberWithInt:contentId]];
if ([types containsObject: @"MozBookmarkType"]) {
NSArray *draggedIDs = [[info draggingPasteboard] propertyListForType: @"MozBookmarkType"];
BookmarkItem* parent;
parent = (item) ? item : BookmarksService::GetRootItem();
return (BookmarksService::IsBookmarkDropValid(parent, index, draggedIDs)) ? NSDragOperationGeneric : NSDragOperationNone;
} else if ([types containsObject: @"MozURLType"]) {
return NSDragOperationGeneric;
}
[pboard declareTypes:[NSArray arrayWithObject:@"MozBookmarkType"] owner:outlineView];
[pboard setPropertyList:contentIds forType:@"MozBookmarkType"];
return YES;
return NSDragOperationNone;
}
- (BOOL)outlineView:(NSOutlineView*)ov acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index {
NSArray *types = [[info draggingPasteboard] types];
BookmarkItem* parent = (item) ? item : BookmarksService::GetRootItem();
if ([types containsObject: @"MozBookmarkType"]) {
NSArray *draggedItems = [[info draggingPasteboard] propertyListForType: @"MozBookmarkType"];
BookmarksService::PerformBookmarkDrop(parent, index, draggedItems);
return YES;
} else if ([types containsObject: @"MozURLType"]) {
NSDictionary* data = [[info draggingPasteboard] propertyListForType: @"MozURLType"];
nsCOMPtr<nsIDOMElement> parentElt;
parentElt = do_QueryInterface([parent contentNode]);
PRInt32 childCount = 0;
[item contentNode]->ChildCount(childCount);
if (index >= childCount)
return NO;
BookmarkItem* beforeItem;
beforeItem = [[ov dataSource] outlineView:ov child:index ofItem:item];
if (!beforeItem)
return NO;
nsCOMPtr<nsIDOMElement> beforeElt;
beforeElt = do_QueryInterface([beforeItem contentNode]);
nsAutoString url; url.AssignWithConversion([[data objectForKey:@"url"] cString]);
nsAutoString title; title.AssignWithConversion([[data objectForKey:@"title"] cString]);
BookmarksService::AddBookmarkToFolder(url, title, parentElt, beforeElt);
return YES;
}
return NO;
}
- (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren
{
if (!item)
[mOutlineView reloadData];
else if ([mOutlineView isItemExpanded: item])
[mOutlineView reloadItem: item reloadChildren: aReloadChildren];
}
-(IBAction)openBookmarkInNewTab:(id)aSender
{
@ -711,19 +732,36 @@
@implementation BookmarkItem
-(nsIContent*)contentNode
{
return mContentNode;
return mContentNode;
}
- (NSNumber*)contentID
{
PRUint32 contentID = 0;
mContentNode->GetContentID(&contentID);
return [NSNumber numberWithInt: contentID];
}
- (NSString *)description
{
nsCOMPtr<nsIContent> item = [self contentNode];
nsCOMPtr<nsIDOMElement> element(do_QueryInterface(item));
nsAutoString href;
element->GetAttribute(NS_LITERAL_STRING("name"), href);
NSString* info = [NSString stringWithCharacters: href.get() length: href.Length()];
return [NSString stringWithFormat:@"<BookmarkItem, name = \"%@\">", info];
}
-(void)setContentNode: (nsIContent*)aContentNode
{
mContentNode = aContentNode;
mContentNode = aContentNode;
}
- (id)copyWithZone:(NSZone *)aZone
{
BookmarkItem* copy = [[[self class] allocWithZone: aZone] init];
[copy setContentNode: mContentNode];
return copy;
BookmarkItem* copy = [[[self class] allocWithZone: aZone] init];
[copy setContentNode: mContentNode];
return copy;
}
@end
@ -732,25 +770,26 @@
static void
StripWhitespaceNodes(nsIContent* aElement)
{
PRInt32 childCount;
aElement->ChildCount(childCount);
for (PRInt32 i = 0; i < childCount; i++) {
nsCOMPtr<nsIContent> child;
aElement->ChildAt(i, *getter_AddRefs(child));
nsCOMPtr<nsITextContent> text = do_QueryInterface(child);
if (text) {
PRBool isEmpty;
text->IsOnlyWhitespace(&isEmpty);
if (isEmpty) {
// This node contained nothing but whitespace.
// Remove it from the content model.
aElement->RemoveChildAt(i, PR_TRUE);
i--; // Decrement our count, since we just removed this child.
childCount--; // Also decrement our total count.
}
}
else StripWhitespaceNodes(child);
PRInt32 childCount = 0;
aElement->ChildCount(childCount);
for (PRInt32 i = 0; i < childCount; i++) {
nsCOMPtr<nsIContent> child;
aElement->ChildAt(i, *getter_AddRefs(child));
nsCOMPtr<nsITextContent> text = do_QueryInterface(child);
if (text) {
PRBool isEmpty = PR_FALSE;
text->IsOnlyWhitespace(&isEmpty);
if (isEmpty) {
// This node contained nothing but whitespace.
// Remove it from the content model.
aElement->RemoveChildAt(i, PR_TRUE);
i--; // Decrement our count, since we just removed this child.
childCount--; // Also decrement our total count.
}
}
else
StripWhitespaceNodes(child);
}
}
PRUint32 BookmarksService::gRefCnt = 0;
@ -792,34 +831,50 @@ BookmarksService::~BookmarksService()
void
BookmarksService::GetRootContent(nsIContent** aResult)
{
*aResult = nsnull;
if (gBookmarks) {
nsCOMPtr<nsIDOMElement> elt;
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
domDoc->GetDocumentElement(getter_AddRefs(elt));
elt->QueryInterface(NS_GET_IID(nsIContent), (void**)aResult); // Addref happens here.
}
*aResult = nsnull;
if (gBookmarks) {
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
if (!domDoc) return;
nsCOMPtr<nsIDOMElement> elt;
domDoc->GetDocumentElement(getter_AddRefs(elt));
if (elt)
elt->QueryInterface(NS_GET_IID(nsIContent), (void**)aResult); // Addref happens here.
}
}
BookmarkItem*
BookmarksService::GetRootItem() {
nsCOMPtr<nsIContent> rootContent;
BookmarksService::GetRootContent(getter_AddRefs(rootContent));
BookmarkItem* rootItem = BookmarksService::GetWrapperFor(rootContent);
return rootItem;
}
BookmarkItem*
BookmarksService::GetWrapperFor(nsIContent* aContent)
{
if (!gDictionary)
gDictionary = [[NSMutableDictionary alloc] initWithCapacity: 30];
PRUint32 contentID;
aContent->GetContentID(&contentID);
BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: contentID]];
if (item)
return item;
else {
// Create an item.
item = [[[BookmarkItem alloc] init] autorelease]; // The dictionary retains us.
[item setContentNode: aContent];
[gDictionary setObject: item forKey: [NSNumber numberWithInt: contentID]];
}
if (!gDictionary)
gDictionary = [[NSMutableDictionary alloc] initWithCapacity: 30];
PRUint32 contentID = 0;
aContent->GetContentID(&contentID);
BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithInt: contentID]];
if (item)
return item;
// Create an item.
item = [[[BookmarkItem alloc] init] autorelease]; // The dictionary retains us.
[item setContentNode: aContent];
[gDictionary setObject: item forKey: [NSNumber numberWithInt: contentID]];
return item;
}
BookmarkItem*
BookmarksService::GetWrapperFor(PRUint32 contentID) {
BookmarkItem* item = [gDictionary objectForKey: [NSNumber numberWithUnsignedInt: contentID]];
return item;
}
NSMenu*
@ -841,7 +896,7 @@ BookmarksService::LocateMenu(nsIContent* aContent)
}
void
BookmarksService::BookmarkAdded(nsIContent* aContainer, nsIContent* aChild)
BookmarksService::BookmarkAdded(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush = true)
{
if (!gInstances || !gDictionary)
return;
@ -883,11 +938,12 @@ BookmarksService::BookmarkAdded(nsIContent* aContainer, nsIContent* aChild)
}
}
FlushBookmarks();
if (shouldFlush)
FlushBookmarks();
}
void
BookmarksService::BookmarkChanged(nsIContent* aItem)
BookmarksService::BookmarkChanged(nsIContent* aItem, bool shouldFlush = true)
{
if (!gInstances || !gDictionary)
return;
@ -902,11 +958,12 @@ BookmarksService::BookmarkChanged(nsIContent* aItem)
}
}
FlushBookmarks();
if (shouldFlush)
FlushBookmarks();
}
void
BookmarksService::BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild)
BookmarksService::BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild, bool shouldFlush = true)
{
if (!gInstances)
return;
@ -940,14 +997,15 @@ BookmarksService::BookmarkRemoved(nsIContent* aContainer, nsIContent* aChild)
else {
// We're the menu.
NSMenu* menu = LocateMenu(aContainer);
PRUint32 contentID;
PRUint32 contentID = 0;
aChild->GetContentID(&contentID);
NSMenuItem* childItem = [menu itemWithTag: contentID];
[menu removeItem: childItem];
}
}
FlushBookmarks();
if (shouldFlush)
FlushBookmarks();
}
void
@ -969,7 +1027,7 @@ BookmarksService::AddObserver()
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profileDir));
profileDir->Append(NS_LITERAL_STRING("bookmarks.xml"));
PRBool fileExists;
PRBool fileExists = PR_FALSE;
profileDir->Exists(&fileExists);
// If the bookmarks file does not exist, copy from the defaults so we don't
@ -1119,9 +1177,10 @@ BookmarksService::FlushBookmarks()
nsCOMPtr<nsIOutputStream> outputStream;
NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), bookmarksFile);
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
nsCOMPtr<nsIDOMSerializer> domSerializer(do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID));
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(gBookmarks));
nsCOMPtr<nsIDOMSerializer> domSerializer(do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID));
if (domSerializer)
domSerializer->SerializeToStream(domDoc, outputStream, nsnull);
}
@ -1592,63 +1651,160 @@ BookmarksService::CreateIconForBookmark(nsIDOMElement* aElement)
return [NSImage imageNamed:@"groupbookmark"];
}
void
BookmarksService::DragBookmark(nsIDOMElement* aElement, NSView* aView, NSEvent* aEvent)
{
NSPasteboard *pboard;
NSString* title;
// Is searchItem equal to bookmark or bookmark's parent, grandparent, etc?
BOOL
BookmarksService::DoAncestorsIncludeNode(BookmarkItem* bookmark, BookmarkItem* searchItem) {
nsCOMPtr<nsIContent> search = [searchItem contentNode];
nsCOMPtr<nsIContent> current = [bookmark contentNode];
nsCOMPtr<nsIContent> root;
GetRootContent(getter_AddRefs(root));
// If the search item is the root node, return yes immediatly
if (search == root)
return YES;
// for each ancestor
while (current) {
// If this is the root node we can't search farther, and there was no match
if (current == root)
return NO;
// If the two nodes match, then the search term is an ancestor of the given bookmark
if (search == current)
return YES;
// If a match wasn't found, set up the next node to compare
nsCOMPtr<nsIContent> oldCurrent = current;
oldCurrent->GetParent(*getter_AddRefs(current));
}
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
PRUint32 contentId;
content->GetContentID(&contentId);
pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
[pboard declareTypes:[NSArray arrayWithObject:@"MozBookmarkType"] owner:aView];
[pboard setPropertyList:[NSArray arrayWithObject:[NSNumber numberWithInt:contentId]] forType:@"MozBookmarkType"];
nsAutoString nameStr;
aElement->GetAttribute(NS_LITERAL_STRING("name"), nameStr);
title = [NSString stringWithCharacters: nameStr.get() length: nameStr.Length()];
[aView dragImage: [MainController createImageForDragging: CreateIconForBookmark(aElement) title:title]
at:NSMakePoint(0,0) offset:NSMakeSize(0,0)
event:aEvent pasteboard:pboard source:aView slideBack:YES];
return NO;
}
void
BookmarksService::CompleteBookmarkDrag(NSPasteboard* aPasteboard, nsIDOMElement* aFolderElt,
nsIDOMElement* aBeforeElt, int aPosition)
#ifdef FILTER_DESCENDANT_ON_DRAG
/*
this has been disabled because it is too slow, and can cause a large
delay when the user is dragging lots of items. this needs to get
fixed someday.
It should filter out every node whose parent is also being dragged.
*/
NSArray*
BookmarksService::FilterOutDescendantsForDrag(NSArray* nodes)
{
NSArray* contentIds;
nsCOMPtr<nsIDOMElement> beforeElt = aBeforeElt;
if (aPosition == BookmarksService::CHInsertAfter && aBeforeElt) {
nsCOMPtr<nsIDOMNode> beforeNode;
aBeforeElt->GetNextSibling(getter_AddRefs(beforeNode));
beforeElt = do_QueryInterface(beforeNode);
}
if (aPosition == BookmarksService::CHInsertInto) {
aFolderElt = aBeforeElt;
beforeElt = nsnull;
}
NSMutableArray *toDrag = [NSMutableArray arrayWithArray: nodes];
unsigned int i = 0;
while (i < [toDrag count]) {
BookmarkItem* item = [toDrag objectAtIndex: i];
bool matchFound = false;
// check for recognized drag types
contentIds = [aPasteboard propertyListForType: @"MozBookmarkType"];
if (contentIds) {
// drag type is chimera bookmarks
for (unsigned int i = 0; i < [contentIds count]; ++i) {
BookmarkItem* item = [gDictionary objectForKey: [contentIds objectAtIndex:i]];
nsCOMPtr<nsIDOMElement> bookmarkElt = do_QueryInterface([item contentNode]);
MoveBookmarkToFolder(bookmarkElt, aFolderElt, beforeElt);
for (unsigned int j = 0; j < [toDrag count] && matchFound == NO; j++) {
if (i != j) // Don't compare to self, will always match
matchFound = BookmarksService::DoAncestorsIncludeNode(item, [toDrag objectAtIndex: j]);
}
} else {
// add bookmark for chimera url type
NSDictionary* data = [aPasteboard propertyListForType: @"MozURLType"];
nsAutoString url; url.AssignWithConversion([[data objectForKey:@"url"] cString]);
nsAutoString title; title.AssignWithConversion([[data objectForKey:@"title"] cString]);
AddBookmarkToFolder(url, title, aFolderElt, beforeElt);
// if a match was found, remove the node from the array
if (matchFound)
[toDrag removeObjectAtIndex: i];
else
i++;
}
return toDrag;
}
#endif
bool
BookmarksService::IsBookmarkDropValid(BookmarkItem* proposedParent, int index, NSArray* draggedIDs) {
NSMutableArray *draggedItems = [NSMutableArray arrayWithCapacity: [draggedIDs count]];
BOOL toolbarRootMoving = NO;
for (unsigned int i = 0; i < [draggedIDs count]; i++) {
NSNumber* contentID = [draggedIDs objectAtIndex: i];
BookmarkItem* bookmarkItem = BookmarksService::GetWrapperFor([contentID unsignedIntValue]);
nsCOMPtr<nsIContent> itemContent = [bookmarkItem contentNode];
nsCOMPtr<nsIDOMElement> itemElement(do_QueryInterface(itemContent));
if (itemElement == BookmarksService::gToolbarRoot)
toolbarRootMoving = YES;
if (bookmarkItem)
[draggedItems addObject: bookmarkItem];
}
// If we are being dropped into the top level, allow it
if ([proposedParent contentNode] == [BookmarksService::GetRootItem() contentNode])
return true;
// If we are not being dropped on the top level, and the toolbar root is being moved, disallow
if (toolbarRootMoving)
return false;
// Make sure that we are not being dropped into one of our own children
// If the proposed parent, or any of it's ancestors matches one of the nodes being dragged
// then deny the drag.
for (unsigned int i = 0; i < [draggedItems count]; i++) {
if (BookmarksService::DoAncestorsIncludeNode(proposedParent, [draggedItems objectAtIndex: i])) {
return false;
}
}
return true;
}
bool
BookmarksService::PerformBookmarkDrop(BookmarkItem* parent, int index, NSArray* draggedIDs) {
NSEnumerator *enumerator = [draggedIDs reverseObjectEnumerator];
NSNumber *contentID;
// for each item being dragged
while ( (contentID = [enumerator nextObject]) ) {
// get dragged node
nsCOMPtr<nsIContent> draggedNode = [GetWrapperFor([contentID unsignedIntValue]) contentNode];
// get the dragged nodes parent
nsCOMPtr<nsIContent> draggedParent;
if (draggedNode)
draggedNode->GetParent(*getter_AddRefs(draggedParent));
// get the proposed parent
nsCOMPtr<nsIContent> proposedParent = [parent contentNode];
PRInt32 existingIndex = 0;
if (draggedParent)
draggedParent->IndexOf(draggedNode, existingIndex);
// if the deleted nodes parent and the proposed parents are equal
// and if the deleted point is eariler in the list than the inserted point
if (proposedParent == draggedParent && existingIndex < index) {
index--; // if so, move the inserted point up one to compensate
}
// remove it from the tree
if (draggedParent)
draggedParent->RemoveChildAt(existingIndex, PR_TRUE);
BookmarkRemoved(draggedParent, draggedNode, false);
// insert into new position
if (proposedParent)
proposedParent->InsertChildAt(draggedNode, index, PR_TRUE, PR_TRUE);
BookmarkAdded(proposedParent, draggedNode, false);
}
FlushBookmarks();
return true;
}
void
BookmarksService::DropURL(NSString* title, NSURL* url, BookmarkItem* parent, int index)
{
NSLog(@"DropURL not implemented yet\n");
}

Просмотреть файл

@ -309,18 +309,82 @@
- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
{
return YES;
BookmarkItem* parent;
int index = 0;
NSArray *draggedItems = [[sender draggingPasteboard] propertyListForType: @"MozBookmarkType"];
// If we are dropping into a folder
if (mDragInsertionPosition == BookmarksService::CHInsertInto) {
nsCOMPtr<nsIDOMElement> parentElt = [mDragInsertionButton element];
nsCOMPtr<nsIContent> parentContent(do_QueryInterface(parentElt));
parent = BookmarksService::GetWrapperFor(parentContent);
index = 0;
}
// If we are dropping onto the toolbar directly
else if (mDragInsertionPosition == BookmarksService::CHInsertBefore ||
mDragInsertionPosition == BookmarksService::CHInsertAfter) {
nsCOMPtr<nsIDOMElement> rootElt = BookmarksService::gToolbarRoot;
nsCOMPtr<nsIContent> rootContent(do_QueryInterface(rootElt));
parent = BookmarksService::GetWrapperFor(rootContent);
index = [mButtons indexOfObject: mDragInsertionButton];
if (index == NSNotFound)
rootContent->ChildCount(index);
else if (mDragInsertionPosition == BookmarksService::CHInsertAfter)
index++;
} else {
mDragInsertionButton = nil;
mDragInsertionPosition = BookmarksService::CHInsertNone;
[self setNeedsDisplay:YES];
return NO;
}
bool valid = BookmarksService::IsBookmarkDropValid(parent, index, draggedItems);
if (!valid) {
mDragInsertionButton = nil;
mDragInsertionPosition = BookmarksService::CHInsertNone;
[self setNeedsDisplay:YES];
}
return valid;
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
BookmarksService::CompleteBookmarkDrag([sender draggingPasteboard], BookmarksService::gToolbarRoot,
mDragInsertionButton ? [mDragInsertionButton element] : nil,
mDragInsertionPosition);
BookmarkItem* parent;
int index = 0;
NSArray *draggedItems = [[sender draggingPasteboard] propertyListForType: @"MozBookmarkType"];
// If we are dropping into a folder
if (mDragInsertionPosition == BookmarksService::CHInsertInto) {
nsCOMPtr<nsIDOMElement> parentElt = [mDragInsertionButton element];
nsCOMPtr<nsIContent> parentContent(do_QueryInterface(parentElt));
parent = BookmarksService::GetWrapperFor(parentContent);
index = 0;
}
// If we are dropping onto the toolbar directly
else if (mDragInsertionPosition == BookmarksService::CHInsertBefore ||
mDragInsertionPosition == BookmarksService::CHInsertAfter) {
nsCOMPtr<nsIDOMElement> rootElt = BookmarksService::gToolbarRoot;
nsCOMPtr<nsIContent> rootContent(do_QueryInterface(rootElt));
parent = BookmarksService::GetWrapperFor(rootContent);
index = [mButtons indexOfObject: mDragInsertionButton];
if (index == NSNotFound)
rootContent->ChildCount(index);
else if (mDragInsertionPosition == BookmarksService::CHInsertAfter)
index++;
} else {
mDragInsertionButton = nil;
mDragInsertionPosition = BookmarksService::CHInsertNone;
[self setNeedsDisplay:YES];
return NO;
}
BookmarksService::PerformBookmarkDrop(parent, index, draggedItems);
mDragInsertionButton = nil;
mDragInsertionPosition = BookmarksService::CHInsertNone;
[self setNeedsDisplay:YES];
return YES;
@ -329,14 +393,11 @@
- (NSRect)insertionRectForButton:(NSView*)aButton position:(int) aPosition
{
if (aPosition == BookmarksService::CHInsertInto) {
return NSMakeRect([aButton frame].origin.x, [aButton frame].origin.y,
[aButton frame].size.width, [aButton frame].size.height);
return NSMakeRect([aButton frame].origin.x, [aButton frame].origin.y, [aButton frame].size.width, [aButton frame].size.height);
} else if (aPosition == BookmarksService::CHInsertAfter) {
return NSMakeRect([aButton frame].origin.x+[aButton frame].size.width, [aButton frame].origin.y,
2, [aButton frame].size.height);
return NSMakeRect([aButton frame].origin.x+[aButton frame].size.width, [aButton frame].origin.y, 2, [aButton frame].size.height);
} else {// if (aPosition == BookmarksService::CHInsertBefore) {
return NSMakeRect([aButton frame].origin.x - 2, [aButton frame].origin.y,
2, [aButton frame].size.height);
return NSMakeRect([aButton frame].origin.x - 2, [aButton frame].origin.y, 2, [aButton frame].size.height);
}
}

Просмотреть файл

@ -104,7 +104,7 @@ static void FindOptionWithContentID(nsIDOMHTMLSelectElement* aSel, PRUint32 aID,
-(id)initWithSelect:(nsIDOMHTMLSelectElement*)aSel
{
if (self = [super init]) {
if ( (self = [super init]) ) {
mSelectElt = aSel;
}
return self;