summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa
diff options
context:
space:
mode:
authorpinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-29 20:30:54 +0000
committerpinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-29 20:30:54 +0000
commit02f58f54e138f44d26743fa1f8bef78fc705ae80 (patch)
tree792a99808f6fa13439d141094189887e31cc2a23 /chrome/browser/cocoa
parent135c20361491522381a596cf036d17eedc501a46 (diff)
downloadchromium_src-02f58f54e138f44d26743fa1f8bef78fc705ae80.zip
chromium_src-02f58f54e138f44d26743fa1f8bef78fc705ae80.tar.gz
chromium_src-02f58f54e138f44d26743fa1f8bef78fc705ae80.tar.bz2
Implement dropping of tabs into an existing tab strip from another window. Implement dragging and dropping of tabs within a window.
Review URL: http://codereview.chromium.org/102010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14879 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa')
-rw-r--r--chrome/browser/cocoa/browser_window_controller.mm48
-rw-r--r--chrome/browser/cocoa/tab_strip_controller.h10
-rw-r--r--chrome/browser/cocoa/tab_strip_controller.mm64
-rw-r--r--chrome/browser/cocoa/tab_view.mm53
-rw-r--r--chrome/browser/cocoa/tab_window_controller.h20
-rw-r--r--chrome/browser/cocoa/tab_window_controller.mm8
6 files changed, 162 insertions, 41 deletions
diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm
index efc08fc..5c35e2c 100644
--- a/chrome/browser/cocoa/browser_window_controller.mm
+++ b/chrome/browser/cocoa/browser_window_controller.mm
@@ -277,16 +277,52 @@ willPositionSheet:(NSWindow *)sheet
return [tabStripController_ selectedTabGrowBoxRect];
}
-- (void)dropTabView:(NSView *)view atIndex:(NSUInteger)index {
- [tabStripController_ dropTabView:view atIndex:index];
+// Drop a given tab view at the location of the current placeholder. If there
+// is no placeholder, it will go at the end. |dragController| is the window
+// controller of a tab being dropped from a different window. It will be nil
+// if the drag is within the window. The implementation will call
+// |-removePlaceholder| since the drag is now complete. This also calls
+// |-layoutTabs| internally so clients do not need to call it again. When
+// dragging tabs between windows, this should be called *before*
+// |-detachTabView| on the source window since it needs to still be in the
+// source window's tab model for this method to find the information it needs
+// to complete the drop.
+- (void)dropTabView:(NSView*)view
+ fromController:(TabWindowController*)dragController {
+ if (dragController) {
+ // Moving between windows. Figure out the TabContents to drop into our tab
+ // model from the source window's model.
+ BOOL isBrowser =
+ [dragController isKindOfClass:[BrowserWindowController class]];
+ DCHECK(isBrowser);
+ if (!isBrowser) return;
+ BrowserWindowController* dragBWC = (BrowserWindowController*)dragController;
+ int index = [dragBWC->tabStripController_ indexForTabView:view];
+ TabContents* contents =
+ dragBWC->browser_->tabstrip_model()->GetTabContentsAt(index);
+
+ // Deposit it into our model at the appropriate location (it already knows
+ // where it should go from tracking the drag).
+ [tabStripController_ dropTabContents:contents];
+ } else {
+ // Moving within a window.
+ int index = [tabStripController_ indexForTabView:view];
+ [tabStripController_ moveTabFromIndex:index];
+ }
+
+ // Remove the placeholder since the drag is now complete.
+ [self removePlaceholder];
}
-- (NSView *)selectedTabView {
- return [tabStripController_ selectedTabView];
+// Tells the tab strip to forget about this tab in preparation for it being
+// put into a different tab strip, such as during a drop on another window.
+- (void)detachTabView:(NSView*)view {
+ int index = [tabStripController_ indexForTabView:view];
+ browser_->tabstrip_model()->DetachTabContentsAt(index);
}
-- (TabStripController *)tabStripController {
- return tabStripController_;
+- (NSView *)selectedTabView {
+ return [tabStripController_ selectedTabView];
}
- (void)setIsLoading:(BOOL)isLoading {
diff --git a/chrome/browser/cocoa/tab_strip_controller.h b/chrome/browser/cocoa/tab_strip_controller.h
index 28e5ff0..35fbc42 100644
--- a/chrome/browser/cocoa/tab_strip_controller.h
+++ b/chrome/browser/cocoa/tab_strip_controller.h
@@ -69,8 +69,14 @@ class ToolbarModel;
// Return the view for the currently selected tab.
- (NSView *)selectedTabView;
-// Drop a tab view at a new index in the array.
-- (void)dropTabView:(NSView *)view atIndex:(NSUInteger)index;
+// Move the given tab at index |from| in this window to the location of the
+// current placeholder.
+- (void)moveTabFromIndex:(NSInteger)from;
+
+// Drop a given TabContents at the location of the current placeholder. If there
+// is no placeholder, it will go at the end. Used when dragging from another
+// window when we don't have access to the TabContents as part of our strip.
+- (void)dropTabContents:(TabContents*)contents;
// Given a tab view in the strip, return its index. Returns -1 if not present.
- (NSInteger)indexForTabView:(NSView*)view;
diff --git a/chrome/browser/cocoa/tab_strip_controller.mm b/chrome/browser/cocoa/tab_strip_controller.mm
index 28de716..b2267d0 100644
--- a/chrome/browser/cocoa/tab_strip_controller.mm
+++ b/chrome/browser/cocoa/tab_strip_controller.mm
@@ -17,7 +17,6 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/common/l10n_util.h"
-#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@implementation TabStripController
@@ -136,7 +135,6 @@
}
}
-
- (void)insertPlaceholderForTab:(TabView*)tab
frame:(NSRect)frame
yStretchiness:(CGFloat)yStretchiness {
@@ -146,7 +144,6 @@
[self layoutTabs];
}
-
// Lay out all tabs in the order of their TabContentsControllers, which matches
// the ordering in the TabStripModel. This call isn't that expensive, though
// it is O(n) in the number of tabs. Tabs will animate to their new position
@@ -350,14 +347,69 @@
[updatedController tabDidChange:contents];
}
+// Called when a tab is moved (usually by drag&drop). Keep our parallel arrays
+// in sync with the tab strip model.
+- (void)tabMovedWithContents:(TabContents*)contents
+ fromIndex:(NSInteger)from
+ toIndex:(NSInteger)to {
+ scoped_nsobject<TabContentsController> movedController(
+ [[tabContentsArray_ objectAtIndex:from] retain]);
+ [tabContentsArray_ removeObjectAtIndex:from];
+ [tabContentsArray_ insertObject:movedController.get() atIndex:to];
+ scoped_nsobject<TabView> movedView(
+ [[tabArray_ objectAtIndex:from] retain]);
+ [tabArray_ removeObjectAtIndex:from];
+ [tabArray_ insertObject:movedView.get() atIndex:to];
+
+ [self layoutTabs];
+}
+
- (NSView *)selectedTabView {
int selectedIndex = tabModel_->selected_index();
return [self viewAtIndex:selectedIndex];
}
-- (void)dropTabView:(NSView *)view atIndex:(NSUInteger)index {
- // TODO(pinkerton): implement drop
- NOTIMPLEMENTED();
+// Find the index based on the x coordinate of the placeholder. If there is
+// no placeholder, this returns the end of the tab strip.
+- (int)indexOfPlaceholder {
+ double placeholderX = placeholderFrame_.origin.x;
+ int index = 0;
+ int location = 0;
+ const int count = tabModel_->count();
+ while (index < count) {
+ NSView* curr = [self viewAtIndex:index];
+ // The placeholder tab works by changing the frame of the tab being dragged
+ // to be the bounds of the placeholder, so we need to skip it while we're
+ // iterating, otherwise we'll end up off by one. Note This only effects
+ // dragging to the right, not to the left.
+ if (curr == placeholderTab_) {
+ index++;
+ continue;
+ }
+ if (placeholderX <= NSMinX([curr frame]))
+ break;
+ index++;
+ location++;
+ }
+ return location;
+}
+
+// Move the given tab at index |from| in this window to the location of the
+// current placeholder.
+- (void)moveTabFromIndex:(NSInteger)from {
+ int toIndex = [self indexOfPlaceholder];
+ tabModel_->MoveTabContentsAt(from, toIndex, true);
+}
+
+// Drop a given TabContents at the location of the current placeholder. If there
+// is no placeholder, it will go at the end. Used when dragging from another
+// window when we don't have access to the TabContents as part of our strip.
+- (void)dropTabContents:(TabContents*)contents {
+ int index = [self indexOfPlaceholder];
+
+ // Insert it into this tab strip. We want it in the foreground and to not
+ // inherit the current tab's group.
+ tabModel_->InsertTabContentsAt(index, contents, true, false);
}
// Return the rect, in WebKit coordinates (flipped), of the window's grow box
diff --git a/chrome/browser/cocoa/tab_view.mm b/chrome/browser/cocoa/tab_view.mm
index fd31652..01f30e6 100644
--- a/chrome/browser/cocoa/tab_view.mm
+++ b/chrome/browser/cocoa/tab_view.mm
@@ -70,7 +70,7 @@
BOOL isLastRemainingTab = [sourceController numberOfTabs] <= 1;
BOOL dragging = YES;
- BOOL moved = NO;
+ BOOL moveBetweenWindows = NO;
NSPoint lastPoint =
[[theEvent window] convertBaseToScreen:[theEvent locationInWindow]];
@@ -103,7 +103,8 @@
}
}
- [sourceController removePlaceholder];
+ if (dragging)
+ [sourceController removePlaceholder];
TabWindowController* draggedController = nil;
TabWindowController* targetController = nil;
@@ -178,7 +179,7 @@
NSEventType type = [theEvent type];
if (type == NSLeftMouseDragged) {
- moved = YES;
+ moveBetweenWindows = YES;
if (!draggedController) {
if (isLastRemainingTab) {
draggedController = sourceController;
@@ -257,27 +258,20 @@
// The drag/click is done. If the user dragged the mouse, finalize the drag
// and clean up.
- if (moved) {
- TabWindowController *dropController = targetController;
-#if 1
- dropController = nil; // Don't allow drops on other windows for now
-#endif
+ if (moveBetweenWindows) {
+ // Move between windows. If |targetController| is nil, we're not dropping
+ // into any existing window.
+ TabWindowController* dropController = targetController;
if (dropController) {
- // TODO(alcor/pinkerton): hookup drops on existing windows
- NSRect adjustedFrame = [self bounds];
- NSRect dropTabFrame = [[dropController tabStripView] frame];
- adjustedFrame.origin = [self convertPointToBase:NSZeroPoint];
- adjustedFrame.origin =
- [sourceWindow convertBaseToScreen:adjustedFrame.origin];
- adjustedFrame.origin.x = adjustedFrame.origin.x - dropTabFrame.origin.x;
- //adjustedFrame.origin.y = adjustedFrame.origin.y - dropTabFrame.origin.y;
- //adjustedFrame.size.height += adjustedFrame.origin.y;
- adjustedFrame.origin.y = 0;
- // TODO(alcor): get add tab stuff working
- // [dropController addTab:tab_];
- [self setFrame:adjustedFrame];
- [dropController layoutTabs];
- [draggedController close];
+ // The ordering here is important. We need to be able to get from the
+ // TabView in the |draggedController| to whatever is needed by the tab
+ // model. To do so, it still has to be in the model, so we have to call
+ // "drop" before we call "detach".
+ NSView* draggedTabView = [draggedController selectedTabView];
+ [draggedController removeOverlay];
+ [dropController dropTabView:draggedTabView
+ fromController:draggedController];
+ [draggedController detachTabView:draggedTabView];
[dropController showWindow:nil];
} else {
[targetController removePlaceholder];
@@ -291,7 +285,20 @@
[draggedController layoutTabs];
}
[sourceController layoutTabs];
+ } else {
+ // Move or click within a window. We need to differentiate between a
+ // click on the tab and a drag by checking against the initial x position.
+ NSPoint currentPoint = [NSEvent mouseLocation];
+ BOOL wasDrag = fabs(currentPoint.x - lastPoint.x) > kDragStartDistance;
+ if (wasDrag) {
+ // Move tab to new location.
+ TabWindowController* dropController = sourceController;
+ [dropController dropTabView:[dropController selectedTabView]
+ fromController:nil];
+ }
}
+
+ [sourceController removePlaceholder];
}
@end
diff --git a/chrome/browser/cocoa/tab_window_controller.h b/chrome/browser/cocoa/tab_window_controller.h
index e86c829..6311f33 100644
--- a/chrome/browser/cocoa/tab_window_controller.h
+++ b/chrome/browser/cocoa/tab_window_controller.h
@@ -62,6 +62,23 @@
// Removes the placeholder installed by |-insertPlaceholderForTab:atLocation:|.
- (void)removePlaceholder;
+// Drop a given tab view at the location of the current placeholder. If there
+// is no placeholder, it will go at the end. |controller| is the window
+// controller of a tab being dropped from a different window. It will be nil
+// if the drag is within the window. The implementation will call
+// |-removePlaceholder| since the drag is now complete. This also calls
+// |-layoutTabs| internally so clients do not need to call it again. When
+// dragging tabs between windows, this should be called *before*
+// |-detachTabView| on the source window since it needs to still be in the
+// source window's tab model for this method to find the information it needs
+// to complete the drop.
+- (void)dropTabView:(NSView*)view
+ fromController:(TabWindowController*)controller;
+
+// Tells the tab strip to forget about this tab in preparation for it being
+// put into a different tab strip, such as during a drop on another window.
+- (void)detachTabView:(NSView*)view;
+
// Number of tabs in the tab strip. Useful, for example, to know if we're
// dragging the only tab in the window.
- (NSInteger)numberOfTabs;
@@ -69,9 +86,6 @@
// Return the view of the selected tab.
- (NSView *)selectedTabView;
-// Drop a given tab view at a new index.
-- (void)dropTabView:(NSView *)view atIndex:(NSUInteger)index;
-
// The title of the selected tab.
- (NSString*)selectedTabTitle;
diff --git a/chrome/browser/cocoa/tab_window_controller.mm b/chrome/browser/cocoa/tab_window_controller.mm
index f7e6079..4a82940 100644
--- a/chrome/browser/cocoa/tab_window_controller.mm
+++ b/chrome/browser/cocoa/tab_window_controller.mm
@@ -99,7 +99,8 @@
return overlayWindow_;
}
-- (void)dropTabView:(NSView *)view atIndex:(NSUInteger)index {
+- (void)dropTabView:(NSView*)view
+ fromController:(TabWindowController*)dragController {
NOTIMPLEMENTED();
}
@@ -131,6 +132,11 @@
NOTIMPLEMENTED();
}
+- (void)detachTabView:(NSView*)view {
+ // subclass must implement
+ NOTIMPLEMENTED();
+}
+
- (NSInteger)numberOfTabs {
// subclass must implement
NOTIMPLEMENTED();