drag and drop for runner toolwindow
authorDennis Ushakov <dennis.ushakov@gmail.com>
Tue, 24 Jan 2012 12:47:22 +0000 (16:47 +0400)
committerDennis Ushakov <dennis.ushakov@gmail.com>
Thu, 26 Jan 2012 18:10:46 +0000 (22:10 +0400)
15 files changed:
platform/lang-api/src/com/intellij/execution/ui/actions/BaseViewAction.java
platform/lang-api/src/com/intellij/execution/ui/layout/CellTransform.java
platform/lang-api/src/com/intellij/execution/ui/layout/GridCell.java
platform/lang-api/src/com/intellij/execution/ui/layout/View.java
platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java
platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java
platform/lang-impl/src/com/intellij/execution/ui/layout/actions/MinimizeViewAction.java
platform/lang-impl/src/com/intellij/execution/ui/layout/impl/DockableGridContainerFactory.java [new file with mode: 0644]
platform/lang-impl/src/com/intellij/execution/ui/layout/impl/GridCellImpl.java
platform/lang-impl/src/com/intellij/execution/ui/layout/impl/GridImpl.java
platform/lang-impl/src/com/intellij/execution/ui/layout/impl/JBRunnerTabs.java
platform/lang-impl/src/com/intellij/execution/ui/layout/impl/RunnerContentUi.java
platform/lang-impl/src/com/intellij/execution/ui/layout/impl/ViewContextEx.java
platform/lang-impl/src/com/intellij/execution/ui/layout/impl/ViewImpl.java
platform/platform-resources/src/idea/LangActions.xml

index 869491c8a685f3ab1ac7a258a9495c93ae5a0702..06c8cd55a7d7b75de4ac13cc04308b9490686fe2 100644 (file)
@@ -17,7 +17,6 @@
 package com.intellij.execution.ui.actions;
 
 import com.intellij.execution.ui.layout.Grid;
-import com.intellij.execution.ui.layout.GridCell;
 import com.intellij.execution.ui.layout.Tab;
 import com.intellij.execution.ui.layout.ViewContext;
 import com.intellij.openapi.actionSystem.AnActionEvent;
@@ -74,11 +73,6 @@ public abstract class BaseViewAction extends DumbAwareAction {
     return e.getData(ViewContext.CONTENT_KEY);
   }
 
-  protected static boolean isDetached(ViewContext context, Content content) {
-    final GridCell cell = context.findCellFor(content);
-    return cell != null && cell.isDetached();
-  }
-
   @Nullable
   protected static Tab getTabFor(final ViewContext context, final Content[] content) {
     Grid grid = context.findGridFor(content[0]);
index e37c46a19083b023b35c54715caea1c40a671dc7..b9c7b21da1975db15fe5cd10cab5eba2472b7a6e 100644 (file)
@@ -72,12 +72,6 @@ public interface CellTransform {
 
   interface Facade {
     void minimize(Content content, Restore restore);
-
-    void moveToTab(final Content content);
-
-    void moveToGrid(final Content content);
-
-    Restore detach(final Content[] content);
   }
  
 }
index 2201bd8d6699a34d927bfae9273f4e30863e8095..ebcbdd6a2a512b97766f0995caf63f4b588af4f4 100644 (file)
 
 package com.intellij.execution.ui.layout;
 
-import com.intellij.openapi.util.ActionCallback;
 import com.intellij.ui.content.Content;
 
 public interface GridCell {
-  boolean isDetached();
-
   int getContentCount();
 
-  void attach();
-
   void minimize(final Content content);
-
-  ActionCallback detach();
 }
\ No newline at end of file
index 761a1b50225047179244daf8f005c206ec6b58e5..c81532e8105fba6e9e2992c89b70ed4fe8c0662d 100644 (file)
@@ -32,4 +32,8 @@ public interface View {
   void assignTab(Tab tab);
 
   void setTabIndex(int tabIndex);
+
+  int getWindow();
+
+  void setWindow(int windowNumber);
 }
\ No newline at end of file
index c78850c2ca401febd5daa7fbd2cae1280108a509..d2672ff88fc1a292573569d6dbe87dd27b2f310d 100644 (file)
@@ -35,6 +35,7 @@ import com.intellij.openapi.extensions.Extensions;
 import com.intellij.openapi.project.DumbService;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.Disposer;
+import com.intellij.ui.docking.DockManager;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -76,7 +77,7 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom
 
   public RunContentManager getContentManager() {
     if (myContentManager == null) {
-      myContentManager = new RunContentManagerImpl(myProject);
+      myContentManager = new RunContentManagerImpl(myProject, DockManager.getInstance(myProject));
       Disposer.register(myProject, myContentManager);
     }
     return myContentManager;
index 7a42e42487ac3aac466588f32e013806299a3dbb..0a6f6b508feb346be8a7adf453ed766da98def00 100644 (file)
@@ -23,6 +23,7 @@ import com.intellij.execution.process.ProcessAdapter;
 import com.intellij.execution.process.ProcessEvent;
 import com.intellij.execution.process.ProcessHandler;
 import com.intellij.execution.runners.GenericProgramRunner;
+import com.intellij.execution.ui.layout.impl.DockableGridContainerFactory;
 import com.intellij.ide.DataManager;
 import com.intellij.ide.impl.ContentManagerWatcher;
 import com.intellij.openapi.Disposable;
@@ -47,6 +48,7 @@ import com.intellij.openapi.wm.ToolWindowManager;
 import com.intellij.openapi.wm.ex.ToolWindowManagerAdapter;
 import com.intellij.openapi.wm.ex.ToolWindowManagerEx;
 import com.intellij.ui.content.*;
+import com.intellij.ui.docking.DockManager;
 import com.intellij.util.concurrency.Semaphore;
 import com.intellij.util.containers.ContainerUtil;
 import com.intellij.util.containers.HashMap;
@@ -65,13 +67,17 @@ public class RunContentManagerImpl implements RunContentManager, Disposable {
   private static final Key<RunContentDescriptor> DESCRIPTOR_KEY = new Key<RunContentDescriptor>("Descriptor");
 
   private final Project myProject;
+  private DockableGridContainerFactory myContentFactory;
   private final Map<String, ContentManager> myToolwindowIdToContentManagerMap = new HashMap<String, ContentManager>();
 
   private final Map<RunContentListener, Disposable> myListeners = new HashMap<RunContentListener, Disposable>();
   private final LinkedList<String> myToolwindowIdZbuffer = new LinkedList<String>();
 
-  public RunContentManagerImpl(Project project) {
+  public RunContentManagerImpl(Project project, DockManager dockManager) {
     myProject = project;
+    myContentFactory = new DockableGridContainerFactory();
+    dockManager.register(DockableGridContainerFactory.TYPE, myContentFactory);
+    Disposer.register(myProject, myContentFactory);
   }
 
   public void init() {
index 79982fb99f8b023b10eb0578e797e958d2f4927d..fc16369ed6885fd7082a000594caefaa93047215 100644 (file)
@@ -39,19 +39,15 @@ public class MinimizeViewAction extends BaseViewAction {
       return false;
     }
 
-    if (isDetached(context, content[0])) {
-      return false;
-    }
-
     if (ViewContext.TAB_TOOLBAR_PLACE.equals(place) || ViewContext.TAB_POPUP_PLACE.equals(place)) {
-      return false;
-    }
-    else {
       Tab tab = getTabFor(context, content);
       if (tab == null) {
         return false;
       }
-      return tab.isDefault();
+      return !tab.isDefault();
+    }
+    else {
+      return getTabFor(context, content) != null;
     }
   }
 }
diff --git a/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/DockableGridContainerFactory.java b/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/DockableGridContainerFactory.java
new file mode 100644 (file)
index 0000000..4e9c694
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.execution.ui.layout.impl;
+
+import com.intellij.ui.docking.DockContainer;
+import com.intellij.ui.docking.DockContainerFactory;
+import com.intellij.ui.docking.DockableContent;
+
+/**
+ * @author Dennis.Ushakov
+ */
+public class DockableGridContainerFactory implements DockContainerFactory {
+  public static final String TYPE = "runner-grid";
+
+  @Override
+  public DockContainer createContainer(DockableContent content) {
+    final RunnerContentUi.DockableGrid dockableGrid = (RunnerContentUi.DockableGrid)content;
+    return new RunnerContentUi(dockableGrid.getRunnerUi(), dockableGrid.getOriginalRunnerUi(), dockableGrid.getWindow());
+  }
+
+  @Override
+  public void dispose() {}
+}
index f479bc7860e9b6b40932c5a8d1cc539298ee2157..0393f7ada11a4a778c6eaf402b5448c8cb7c2413 100644 (file)
@@ -18,18 +18,16 @@ package com.intellij.execution.ui.layout.impl;
 
 import com.intellij.execution.ui.layout.*;
 import com.intellij.execution.ui.layout.actions.MinimizeViewAction;
-import com.intellij.openapi.Disposable;
 import com.intellij.openapi.actionSystem.ActionGroup;
 import com.intellij.openapi.actionSystem.DataProvider;
-import com.intellij.openapi.ui.popup.ComponentPopupBuilder;
 import com.intellij.openapi.ui.popup.JBPopup;
-import com.intellij.openapi.ui.popup.JBPopupFactory;
-import com.intellij.openapi.util.*;
-import com.intellij.openapi.wm.IdeFrame;
-import com.intellij.openapi.wm.WindowManager;
+import com.intellij.openapi.util.ActionCallback;
+import com.intellij.openapi.util.DimensionService;
+import com.intellij.openapi.util.MutualMap;
 import com.intellij.ui.components.panels.NonOpaquePanel;
-import com.intellij.ui.components.panels.Wrapper;
 import com.intellij.ui.content.Content;
+import com.intellij.ui.docking.DockContainer;
+import com.intellij.ui.docking.DockManager;
 import com.intellij.ui.switcher.SwitchTarget;
 import com.intellij.ui.tabs.JBTabs;
 import com.intellij.ui.tabs.TabInfo;
@@ -43,14 +41,15 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import javax.swing.*;
-import javax.swing.border.EmptyBorder;
 import java.awt.*;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.util.ArrayList;
+import java.util.List;
 import java.util.Set;
 
-public class GridCellImpl implements GridCell, Disposable {
+public class GridCellImpl implements GridCell {
+  static final String CELL_KEY = "runner-grid-cell";
 
   private final GridImpl myContainer;
 
@@ -62,16 +61,12 @@ public class GridCellImpl implements GridCell, Disposable {
   private final PlaceInGrid myPlaceInGrid;
 
   private final ViewContextEx myContext;
-  private CellTransform.Restore.List myRestoreFromDetach;
   private JBPopup myPopup;
-  private boolean myDisposed;
 
   public GridCellImpl(ViewContextEx context, @NotNull GridImpl container, GridImpl.Placeholder placeholder, PlaceInGrid placeInGrid) {
     myContext = context;
     myContainer = container;
 
-    Disposer.register(container, this);
-
     myPlaceInGrid = placeInGrid;
     myPlaceholder = placeholder;
     myTabs = new JBTabsImpl(myContext.getProject(), myContext.getActionManager(), myContext.getFocusManager(), container).setDataProvider(new DataProvider() {
@@ -97,18 +92,12 @@ public class GridCellImpl implements GridCell, Disposable {
       }
     }).setSideComponentVertical(!context.getLayoutSettings().isToolbarHorizontal())
       .setStealthTabMode(true)
-      .setFocusCycle(false).setPaintFocus(true).setProvideSwitchTargets(false);
+      .setFocusCycle(false).setPaintFocus(true).setProvideSwitchTargets(false).setTabDraggingEnabled(true);
 
     myTabs.addTabMouseListener(new MouseAdapter() {
       public void mousePressed(final MouseEvent e) {
         if (UIUtil.isCloseClick(e)) {
-          if (isDetached()) {
-            myPopup.cancel();
-            myPopup = null;
-          }
-          else {
             minimize(e);
-          }
         }
       }
     });
@@ -181,7 +170,7 @@ public class GridCellImpl implements GridCell, Disposable {
       }
     }
     else {
-      if (myPlaceholder.isNull() && !isDetached()) {
+      if (myPlaceholder.isNull()) {
         myPlaceholder.setContent(myTabs.getComponent());
       }
 
@@ -211,7 +200,7 @@ public class GridCellImpl implements GridCell, Disposable {
 
     ActionGroup group = (ActionGroup)myContext.getActionManager().getAction(RunnerContentUi.VIEW_TOOLBAR);
     tabInfo.setTabLabelActions(group, ViewContext.CELL_TOOLBAR_PLACE);
-
+    tabInfo.setDragOutDelegate(((RunnerContentUi)myContext).myDragOutDelegate);
     return tabInfo;
   }
 
@@ -248,7 +237,7 @@ public class GridCellImpl implements GridCell, Disposable {
     return myMinimizedContents.contains(content);
   }
 
-  public java.util.List<SwitchTarget> getTargets(boolean onlyVisible) {
+  public List<SwitchTarget> getTargets(boolean onlyVisible) {
     if (myTabs.getPresentation().isHideTabs()) return new ArrayList<SwitchTarget>();
 
     return myTabs.getTargets(onlyVisible, false);
@@ -271,6 +260,7 @@ public class GridCellImpl implements GridCell, Disposable {
       myContent = content;
       myContext = context;
       setLayout(new BorderLayout());
+      putClientProperty(CELL_KEY, Boolean.TRUE);
       add(content.getComponent(), BorderLayout.CENTER);
     }
 
@@ -287,7 +277,7 @@ public class GridCellImpl implements GridCell, Disposable {
   }
 
   @Nullable
-  private TabInfo getTabFor(Content content) {
+  TabInfo getTabFor(Content content) {
     return myContents.getValue(content);
   }
 
@@ -306,14 +296,21 @@ public class GridCellImpl implements GridCell, Disposable {
     restoreProportions();
 
     Content[] contents = getContents();
+    int window = 0;
     for (Content each : contents) {
-      if (myContainer.getStateFor(each).isMinimizedInGrid()) {
+      final View view = myContainer.getStateFor(each);
+      if (view.isMinimizedInGrid()) {
         minimize(each);
       }
+      window = view.getWindow();
     }
-
-    if (!isRestoringFromDetach() && myContainer.getTab().isDetached(myPlaceInGrid) && contents.length > 0) {
-      _detach(!myContext.isStateBeingRestored()).notifyWhenDone(result);
+    final Tab tab = myContainer.getTab();
+    final boolean detached = (tab != null && tab.isDetached(myPlaceInGrid)) || window != myContext.getWindow();
+    if (detached && contents.length > 0) {
+      if (tab != null) {
+        tab.setDetached(myPlaceInGrid, false);
+      }
+      _detach(window).notifyWhenDone(result);
     } else {
       result.setDone();
     }
@@ -321,7 +318,7 @@ public class GridCellImpl implements GridCell, Disposable {
     return result;
   }
 
-  private Content[] getContents() {
+  Content[] getContents() {
     return myContents.getKeys().toArray(new Content[myContents.size()]);
   }
 
@@ -339,6 +336,14 @@ public class GridCellImpl implements GridCell, Disposable {
     for (Content each : myMinimizedContents) {
       saveState(each, true);
     }
+
+    final DimensionService service = DimensionService.getInstance();
+    final Dimension size = myContext.getContentManager().getComponent().getSize();
+    service.setSize(getDimensionKey(), size, myContext.getProject());
+    if (myContext.getWindow() != 0) {
+      final JFrame frame = (JFrame)DockManager.getInstance(myContext.getProject()).getIdeFrame((DockContainer)myContext);
+      service.setLocation(getDimensionKey(), frame.getLocationOnScreen());
+    }
   }
 
   public void saveProportions() {
@@ -350,8 +355,7 @@ public class GridCellImpl implements GridCell, Disposable {
     state.setMinimizedInGrid(minimized);
     state.setPlaceInGrid(myPlaceInGrid);
     state.assignTab(myContainer.getTabIndex());
-
-    state.getTab().setDetached(myPlaceInGrid, isDetached());
+    state.setWindow(myContext.getWindow());
   }
 
   public void restoreProportions() {
@@ -362,7 +366,7 @@ public class GridCellImpl implements GridCell, Disposable {
     for (Content each : myContents.getKeys()) {
       final TabInfo eachTab = getTabFor(each);
       boolean isSelected = eachTab != null && myTabs.getSelectedInfo() == eachTab;
-      if (isSelected && (isShowing || isDetached())) {
+      if (isSelected && isShowing) {
         myContext.getContentManager().addSelectedContent(each);
       }
       else {
@@ -391,147 +395,27 @@ public class GridCellImpl implements GridCell, Disposable {
     }
   }
 
-  public ActionCallback detach() {
-    return _detach(true);
-  }
-
-  private ActionCallback _detach(final boolean requestFocus) {
+  private ActionCallback _detach(final int window) {
     myContext.saveUiState();
-
-    final DimensionService dimService = DimensionService.getInstance();
-    Point storedLocation = dimService.getLocation(getDimensionKey(), myContext.getProject());
-    Dimension storedSize = dimService.getSize(getDimensionKey(), myContext.getProject());
-
-    final IdeFrame frame = WindowManager.getInstance().getIdeFrame(myContext.getProject());
-    final Rectangle targetBounds = frame.suggestChildFrameBounds();
-
-
-    if (storedLocation != null && storedSize != null) {
-      targetBounds.setLocation(storedLocation);
-      targetBounds.setSize(storedSize);
-    }
-
-    final ActionCallback result = new ActionCallback();
-
-    if (storedLocation == null || storedSize == null) {
-      if (myContents.size() > 0) {
-        myContext.validate(myContents.getKeys().iterator().next(), new ActiveRunnable() {
-          public ActionCallback run() {
-            if (!myTabs.getComponent().isShowing()) {
-              detachTo(targetBounds.getLocation(), targetBounds.getSize(), false, requestFocus).notifyWhenDone(result);
-            } else {
-              detachForShowingTabs(requestFocus).notifyWhenDone(result);
-            }
-
-            return new ActionCallback.Done();
-          }
-        });
-
-        return result;
-      }
-    }
-
-    detachTo(targetBounds.getLocation(), targetBounds.getSize(), false, requestFocus).notifyWhenDone(result);
-
-    return result;
-  }
-
-  private ActionCallback detachForShowingTabs(boolean requestFocus) {
-    return detachTo(myTabs.getComponent().getLocationOnScreen(), myTabs.getComponent().getSize(), false, requestFocus);
+    return myContext.detachTo(window, this);
   }
 
-  private ActionCallback detachTo(Point screenPoint, Dimension size, boolean dragging, final boolean requestFocus) {
-    if (isDetached()) {
-      if (myPopup != null) {
-        return new ActionCallback.Done();
-      }
-    }
-
-    final Content[] contents = getContents();
-
-    myRestoreFromDetach = new CellTransform.Restore.List();
-
-    myRestoreFromDetach.add(myPlaceholder.detach());
-    myRestoreFromDetach.add(myContainer.detach(contents));
-    myRestoreFromDetach.add(new CellTransform.Restore() {
-      public ActionCallback restoreInGrid() {
-        ensureVisible();
-        return new ActionCallback.Done();
-      }
-    });
-
-    myPopup = createPopup(dragging, requestFocus);
-    myPopup.setSize(size);
-    myPopup.setLocation(screenPoint);
-    myPopup.show(myContext.getContentManager().getComponent());
-
-    myContext.saveUiState();
-
-    myTabs.updateTabActions(true);
-
-    return new ActionCallback.Done();
-  }
-
-  private void ensureVisible() {
-    if (myTabs.getSelectedInfo() != null) {
-      myContext.select(getContentFor(myTabs.getSelectedInfo()), true);
-    }
-  }
-
-  private JBPopup createPopup(boolean dragging, final boolean requestFocus) {
-    Wrapper wrapper = new Wrapper(myTabs.getComponent());
-    wrapper.setBorder(new EmptyBorder(1, 0, 0, 0));
-    final ComponentPopupBuilder builder = JBPopupFactory.getInstance().createComponentPopupBuilder(wrapper, myTabs.getComponent())
-      .setTitle(myContainer.getSessionName())
-      .setMovable(true)
-      .setRequestFocus(requestFocus)
-      .setFocusable(true)
-      .setResizable(true)
-      .setDimensionServiceKey(myContext.getProject(), getDimensionKey(), true)
-      .setCancelOnOtherWindowOpen(false)
-      .setCancelOnClickOutside(false)
-      .setCancelKeyEnabled(true)
-      .setLocateByContent(dragging)
-      .setLocateWithinScreenBounds(!dragging)
-      .setCancelKeyEnabled(false)
-      .setBelongsToGlobalPopupStack(false)
-      .setModalContext(false)
-      .setCancelCallback(new Computable<Boolean>() {
-        public Boolean compute() {
-          if (myDisposed || myContents.size() == 0) return Boolean.TRUE;
-          myRestoreFromDetach.restoreInGrid();
-          myRestoreFromDetach = null;
-          myContext.saveUiState();
-          myTabs.updateTabActions(true);
-          return Boolean.TRUE;
-        }
-      });
-
-    return builder.createPopup();
-  }
-
-  public void attach() {
-    if (isDetached()) {
-      myPopup.cancel();
-      myPopup = null;
-    }
-  }
-
-
-  public boolean isDetached() {
-    return myRestoreFromDetach != null && !myRestoreFromDetach.isRestoringNow();
+  @Nullable
+  public Point getLocation() {
+    return DimensionService.getInstance().getLocation(getDimensionKey(), myContext.getProject());
   }
 
-  public boolean isRestoringFromDetach() {
-    return myRestoreFromDetach != null && myRestoreFromDetach.isRestoringNow();
+  @Nullable
+  public Dimension getSize() {
+    return DimensionService.getInstance().getSize(getDimensionKey(), myContext.getProject());
   }
-
+  
   private String getDimensionKey() {
     return "GridCell.Tab." + myContainer.getTab().getIndex() + "." + myPlaceInGrid.name();
   }
 
-  public boolean isValidForCalculatePropertions() {
-    return !isDetached() && getContentCount() > 0;
+  public boolean isValidForCalculateProportions() {
+    return getContentCount() > 0;
   }
 
   public void minimize(Content content) {
@@ -553,13 +437,4 @@ public class GridCellImpl implements GridCell, Disposable {
     updateSelection(myTabs.getComponent().getRootPane() != null);
     return new ActionCallback.Done();
   }
-
-  public void dispose() {
-    myDisposed = true;
-
-    if (myPopup != null) {
-      myPopup.cancel();
-      myPopup = null;
-    }
-  }
 }
index dfb6659f6c1aced2a8a77c668b014e32e2e7b86b..f023d86d3a9b29a542380e1f59f4b09cd59f96e2 100644 (file)
@@ -35,7 +35,7 @@ import java.awt.*;
 import java.util.*;
 import java.util.List;
 
-public class GridImpl extends Wrapper implements Grid, Disposable, CellTransform.Facade, DataProvider {
+public class GridImpl extends Wrapper implements Grid, Disposable, DataProvider {
   private final ThreeComponentsSplitter myTopSplit = new ThreeComponentsSplitter();
   private final Splitter mySplitter = new Splitter(true);
 
@@ -152,8 +152,7 @@ public class GridImpl extends Wrapper implements Grid, Disposable, CellTransform
 
   public boolean updateGridUI() {
     for (final GridCellImpl cell : myPlaceInGrid2Cell.values()) {
-      final boolean eachToHide = myContents.size() == 1 && !cell.isDetached();
-      cell.setHideTabs(eachToHide);
+      cell.setHideTabs(myContents.size() == 1);
     }
 
     final Content onlyContent = myContents.get(0);
@@ -252,7 +251,7 @@ public class GridImpl extends Wrapper implements Grid, Disposable, CellTransform
 
     final GridCellImpl cell = myPlaceInGrid2Cell.get(placeInGrid);
 
-    if (!cell.isValidForCalculatePropertions()) return;
+    if (!cell.isValidForCalculateProportions()) return;
 
     final TabImpl tab = (TabImpl)getTab();
 
@@ -335,19 +334,12 @@ public class GridImpl extends Wrapper implements Grid, Disposable, CellTransform
     ArrayList<Content> result = new ArrayList<Content>();
 
     for (Content each : getContents()) {
-      if (!isDetached(each)) {
-        result.add(each);
-      }
+      result.add(each);
     }
 
     return result;
   }
 
-
-  public boolean isDetached(Content content) {
-    return getCellFor(content).isDetached();
-  }
-
   public List<Content> getContents() {
     return myContents;
   }
@@ -360,28 +352,6 @@ public class GridImpl extends Wrapper implements Grid, Disposable, CellTransform
     });
   }
 
-  public void moveToTab(final Content content) {
-    myViewContext.getCellTransform().moveToTab(content);
-  }
-
-  public void moveToGrid(final Content content) {
-    myViewContext.getCellTransform().moveToGrid(content);
-  }
-
-  public CellTransform.Restore detach(final Content[] content) {
-    final CellTransform.Restore.List restore = new CellTransform.Restore.List();
-    restore.add(myViewContext.getCellTransform().detach(content));
-    restore.add(new CellTransform.Restore() {
-      public ActionCallback restoreInGrid() {
-        revalidate();
-        repaint();
-        return new ActionCallback.Done();
-      }
-    });
-
-    return restore;
-  }
-
   @Nullable
   public Object getData(@NonNls final String dataId) {
     if (ViewContext.CONTEXT_KEY.is(dataId)) {
@@ -394,10 +364,6 @@ public class GridImpl extends Wrapper implements Grid, Disposable, CellTransform
     return null;
   }
 
-  public String getSessionName() {
-    return mySessionName;
-  }
-
   @Nullable
   public SwitchTarget getCellFor(Component c) {
     Component eachParent = c;
@@ -419,9 +385,7 @@ public class GridImpl extends Wrapper implements Grid, Disposable, CellTransform
     Collection<GridCellImpl> cells = myPlaceInGrid2Cell.values();
     ArrayList<SwitchTarget> result = new ArrayList<SwitchTarget>();
     for (GridCellImpl each : cells) {
-      if (!each.isDetached()) {
-        result.addAll(each.getTargets(onlyVisible));
-      }
+      result.addAll(each.getTargets(onlyVisible));
     }
     return result;
   }
index e25153e2543f9876e80d4c242e13d1296f6f3687..33125c2ddf340bfb76fb7c1e659c2d1debc88122 100644 (file)
@@ -39,7 +39,8 @@ import java.util.List;
 /**
  * @author Dennis.Ushakov
  */
-public class JBRunnerTabs extends JBTabsImpl {
+public class
+  JBRunnerTabs extends JBTabsImpl {
   public JBRunnerTabs(@Nullable Project project, ActionManager actionManager, IdeFocusManager focusManager, @NotNull Disposable parent) {
     super(project, actionManager, focusManager, parent);
   }
@@ -211,7 +212,7 @@ public class JBRunnerTabs extends JBTabsImpl {
   protected TabLabel createTabLabel(TabInfo info) {
     return new MyTabLabel(this, info);
   }
-  
+
   private static class MyTabLabel extends TabLabel {
     public MyTabLabel(JBTabsImpl tabs, final TabInfo info) {
       super(tabs, info);
index b2732529f4f69e8a1c5247c147acb940adc80346..72367679832fcc7e30063e54704c689b4fe11d6d 100644 (file)
@@ -28,21 +28,28 @@ import com.intellij.openapi.util.ActiveRunnable;
 import com.intellij.openapi.util.Disposer;
 import com.intellij.openapi.util.Ref;
 import com.intellij.openapi.wm.IdeFocusManager;
+import com.intellij.openapi.wm.IdeFrame;
 import com.intellij.openapi.wm.ToolWindow;
 import com.intellij.ui.UIBundle;
+import com.intellij.ui.awt.RelativePoint;
+import com.intellij.ui.awt.RelativeRectangle;
 import com.intellij.ui.components.panels.NonOpaquePanel;
 import com.intellij.ui.components.panels.Wrapper;
 import com.intellij.ui.content.*;
+import com.intellij.ui.docking.DockContainer;
+import com.intellij.ui.docking.DockManager;
+import com.intellij.ui.docking.DockableContent;
+import com.intellij.ui.docking.DragSession;
+import com.intellij.ui.docking.impl.DockManagerImpl;
 import com.intellij.ui.switcher.QuickActionProvider;
 import com.intellij.ui.switcher.SwitchProvider;
 import com.intellij.ui.switcher.SwitchTarget;
 import com.intellij.ui.tabs.JBTabs;
 import com.intellij.ui.tabs.TabInfo;
 import com.intellij.ui.tabs.TabsListener;
-import com.intellij.ui.tabs.UiDecorator;
-import com.intellij.ui.tabs.impl.JBTabsImpl;
 import com.intellij.util.containers.ContainerUtil;
 import com.intellij.util.ui.AbstractLayoutManager;
+import com.intellij.util.ui.UIUtil;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -50,13 +57,15 @@ import org.jetbrains.annotations.Nullable;
 import javax.swing.*;
 import javax.swing.border.EmptyBorder;
 import java.awt.*;
+import java.awt.event.MouseEvent;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.util.*;
 import java.util.List;
+import java.util.concurrent.CopyOnWriteArraySet;
 
 public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Facade, ViewContextEx, PropertyChangeListener, SwitchProvider,
-                                        QuickActionProvider {
+                                        QuickActionProvider, DockContainer {
 
   @NonNls public static final String LAYOUT = "Runner.Layout";
   @NonNls public static final String VIEW_POPUP = "Runner.View.Popup";
@@ -70,8 +79,9 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
   MyComponent myComponent = new MyComponent();
 
   private final Wrapper myToolbar = new Wrapper();
+  final MyDragOutDelegate myDragOutDelegate = new MyDragOutDelegate();
 
-  JBTabs myTabs;
+  JBRunnerTabs myTabs;
   private final Comparator<TabInfo> myTabsComparator = new Comparator<TabInfo>() {
     public int compare(final TabInfo o1, final TabInfo o2) {
       //noinspection ConstantConditions
@@ -110,6 +120,15 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
   private int myAttractionCount;
   private ActionGroup myLeftToolbarActions;
 
+  private JBTabs myCurrentOver;
+  private Image myCurrentOverImg;
+  private TabInfo myCurrentOverInfo;
+  private RunnerContentUi myOriginal;
+  private CopyOnWriteArraySet<Listener> myDockingListeners = new CopyOnWriteArraySet<Listener>();
+  private List<RunnerContentUi> myChildren = new ArrayList<RunnerContentUi>(); 
+  private int myWindow;
+  private int ourWindowCounter;
+
   public RunnerContentUi(Project project,
                          RunnerLayoutUi ui,
                          ActionManager actionManager,
@@ -124,6 +143,12 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
     myFocusManager = focusManager;
   }
 
+  public RunnerContentUi(RunnerContentUi ui, RunnerContentUi original, int window) {
+    this(ui.myProject, ui.myRunnerUi, ui.myActionManager, ui.myFocusManager, ui.myLayoutSettings, ui.mySessionName);
+    myOriginal = original;
+    original.myChildren.add(this);
+    myWindow = window == 0 ? original.findFreeWindow() : window;
+  }
 
   public void setTopActions(@NotNull final ActionGroup topActions, @NotNull String place) {
     myTopActions = topActions;
@@ -150,32 +175,27 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
   public void initUi() {
     if (myTabs != null) return;
 
-    myTabs = new JBTabsImpl(myProject, myActionManager, myFocusManager, this)
-      .setDataProvider(new DataProvider() {
-        public Object getData(@NonNls final String dataId) {
-          if (ViewContext.CONTENT_KEY.is(dataId)) {
-            TabInfo info = myTabs.getTargetInfo();
-            if (info != null) {
-              return getGridFor(info).getData(dataId);
-            }
-          }
-          else if (ViewContext.CONTEXT_KEY.is(dataId)) {
-            return RunnerContentUi.this;
+    myTabs = (JBRunnerTabs)new JBRunnerTabs(myProject, myActionManager, myFocusManager, this).setDataProvider(new DataProvider() {
+      public Object getData(@NonNls final String dataId) {
+        if (ViewContext.CONTENT_KEY.is(dataId)) {
+          TabInfo info = myTabs.getTargetInfo();
+          if (info != null) {
+            return getGridFor(info).getData(dataId);
           }
-          return null;
         }
-      }).setProvideSwitchTargets(false).setInnerInsets(new Insets(1, 0, 0, 0)).setToDrawBorderIfTabsHidden(false)
-      .setUiDecorator(new UiDecorator() {
-        @NotNull
-        public UiDecoration getDecoration() {
-          return new UiDecoration(null, new Insets(1, 8, 1, 8));
+        else if (ViewContext.CONTEXT_KEY.is(dataId)) {
+          return RunnerContentUi.this;
         }
-      }).getJBTabs();
+        return null;
+      }
+    }).setTabLabelActionsAutoHide(false).setProvideSwitchTargets(false).setInnerInsets(new Insets(0, 0, 0, 0))
+      .setToDrawBorderIfTabsHidden(false).setTabDraggingEnabled(isMoveToGridActionEnabled()).setUiDecorator(null).getJBTabs();
     rebuildTabPopup();
 
-
-    myTabs.getPresentation().setPaintBorder(0, 0, 0, 0).setTabSidePaintBorder(2).setPaintFocus(false)
+    myTabs.getPresentation().setPaintBorder(0, 0, 0, 0).setPaintFocus(false)
       .setRequestFocusOnLastFocusedComponent(true);
+    myTabs.getComponent().setBackground(myToolbar.getBackground());
+    myTabs.getComponent().setBorder(new EmptyBorder(0, 2, 0, 0));
 
     final NonOpaquePanel wrappper = new NonOpaquePanel(new BorderLayout(0, 0));
     wrappper.add(myToolbar, BorderLayout.WEST);
@@ -207,6 +227,14 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
         }
       }
     });
+
+    if (myOriginal != null) {
+      final ContentManager manager = ContentFactory.SERVICE.getInstance().createContentManager(this, false, myProject);
+      Disposer.register((Disposable)myRunnerUi, manager);
+      manager.getComponent();
+    } else {
+      DockManager.getInstance(myProject).register(this);
+    }
   }
 
   private void rebuildTabPopup() {
@@ -249,10 +277,15 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
     return group;
   }
 
-  public void doWhenInitialized(final Runnable runnable) {
-    myInitialized.doWhenDone(runnable);
+  @Override
+  public boolean isOriginal() {
+    return myOriginal == null;
   }
 
+  @Override
+  public int getWindow() {
+    return myWindow;
+  }
 
   public void propertyChange(final PropertyChangeEvent evt) {
     Content content = (Content)evt.getSource();
@@ -302,11 +335,191 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
     }
   }
 
+  @Override
+  public ActionCallback detachTo(int window, GridCell cell) {
+    if (myOriginal != null) {
+      return myOriginal.detachTo(window, cell);
+    }
+    RunnerContentUi target = null;
+    if (window > 0) {
+      for (RunnerContentUi child : myChildren) {
+        if (child.myWindow == window) {
+          target = child;
+          break;
+        }
+      }
+    }
+    final GridCellImpl gridCell = (GridCellImpl)cell;
+    final Content[] contents = gridCell.getContents();
+    Dimension size = gridCell.getSize();
+    if (size == null) {
+      size = new Dimension(200, 200);
+    }
+    final DockableGrid content = new DockableGrid(null, null, size, Arrays.asList(contents), window);
+    if (target != null) {
+      target.add(content, null);
+    } else {
+      final Point location = gridCell.getLocation();
+      location.translate(size.width / 2, size.height / 2);
+      getDockManager().createNewDockContainerFor(content, new RelativePoint(location));
+    }
+    return new ActionCallback.Done();
+  }
+
+  @Override
+  public RelativeRectangle getAcceptArea() {
+    return new RelativeRectangle(myTabs.getComponent());
+  }
+
+  @Override
+  public boolean canAccept(DockableContent content, RelativePoint point) {
+    if (!(content instanceof DockableGrid)) {
+      return false;
+    }
+    final RunnerContentUi ui = ((DockableGrid)content).getOriginalRunnerUi();
+    return ui.getProject() == myProject && ui.mySessionName.equals(mySessionName);
+  }
+
+  @Override
   public JComponent getComponent() {
     initUi();
     return myComponent;
   }
 
+  @Override
+  public JComponent getContainerComponent() {
+    initUi();
+    return myManager.getComponent();
+  }
+
+  @Override
+  public void add(DockableContent dockable, RelativePoint dropTarget) {
+    saveUiState();
+
+    final DockableGrid dockableGrid = (DockableGrid)dockable;
+    final List<Content> contents = dockableGrid.getContents();
+    final boolean wasRestoring = myOriginal != null && myOriginal.isStateBeingRestored();
+    setStateIsBeingRestored(true, this);
+    try {
+      final Point point = dropTarget != null ? dropTarget.getPoint(myComponent) : null;
+      JComponent component = point != null ? (JComponent)SwingUtilities.getDeepestComponentAt(myComponent, point.x, point.y) : null;
+      boolean hadGrid = false;
+      while (component != null && !(component instanceof JBTabs)) {
+        if (component.getClientProperty(GridCellImpl.CELL_KEY) == Boolean.TRUE) {
+          hadGrid = true;
+          break;
+        }
+        component = (JComponent)component.getParent();
+      }
+
+      for (Content content : contents) {
+        dockableGrid.getRunnerUi().myManager.removeContent(content, false);
+        myManager.removeContent(content, false);
+        if (hadGrid && contents.size() == 1 && !wasRestoring) {
+          getStateFor(content).assignTab(getTabFor(getSelectedGrid()));
+          getStateFor(content).setPlaceInGrid(myLayoutSettings.getDefaultGridPlace(content));
+        } else if (contents.size() == 1 && !wasRestoring) {
+          getStateFor(content).assignTab(myLayoutSettings.createNewTab());
+          getStateFor(content).setPlaceInGrid(myLayoutSettings.getDefaultGridPlace(content));
+        }
+        getStateFor(content).setWindow(myWindow);
+        myManager.addContent(content);
+      }
+    } finally {
+      setStateIsBeingRestored(false, this);
+    }
+
+    saveUiState();
+
+    updateTabsUI(true);
+  }
+
+  @Override
+  public void closeAll() {
+    final Content[] contents = myManager.getContents();
+    for (Content content : contents) {
+      getStateFor(content).setWindow(0);
+    }
+    myManager.removeAllContents(false);
+    for (Content content : contents) {
+      myOriginal.myManager.addContent(content);
+      myOriginal.findCellFor(content).minimize(content);
+    }
+  }
+
+  @Override
+  public void addListener(final Listener listener, Disposable parent) {
+    myDockingListeners.add(listener);
+    Disposer.register(parent, new Disposable() {
+      @Override
+      public void dispose() {
+        myDockingListeners.remove(listener);
+      }
+    });
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return myTabs.isEmptyVisible();
+  }
+
+  @Override
+  public Image startDropOver(DockableContent content, RelativePoint point) {
+    return null;
+  }
+
+  @Override
+  public Image processDropOver(DockableContent content, RelativePoint point) {
+    JBTabs current = getTabsAt(content, point);
+
+    if (myCurrentOver != null && myCurrentOver != current) {
+      resetDropOver(content);
+    }
+
+    if (myCurrentOver == null && current != null) {
+      myCurrentOver = current;
+      Presentation presentation = content.getPresentation();
+      myCurrentOverInfo = new TabInfo(new JLabel("")).setText(presentation.getText()).setIcon(presentation.getIcon());
+      myCurrentOverImg = myCurrentOver.startDropOver(myCurrentOverInfo, point);
+    }
+
+    if (myCurrentOver != null) {
+      myCurrentOver.processDropOver(myCurrentOverInfo, point);
+    }
+
+    return myCurrentOverImg;
+  }
+
+  @Nullable
+  private JBTabs getTabsAt(DockableContent content, RelativePoint point) {
+    if (content instanceof DockableGrid) {
+      final Point p = point.getPoint(getComponent());
+      Component c = SwingUtilities.getDeepestComponentAt(getComponent(), p.x, p.y);
+      while (c != null) {
+        if (c instanceof JBTabs) {
+          return (JBTabs)c;
+        }
+        c = c.getParent();
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public void resetDropOver(DockableContent content) {
+    if (myCurrentOver != null) {
+      myCurrentOver.resetDropOver(myCurrentOverInfo);
+      myCurrentOver = null;
+      myCurrentOverInfo = null;
+      myCurrentOverImg = null;
+    }
+  }
+
+  @Override
+  public boolean isDisposeWhenEmpty() {
+    return true;
+  }
+
   public boolean isCycleRoot() {
     return false;
   }
@@ -337,6 +550,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
 
 
         event.getContent().addPropertyChangeListener(RunnerContentUi.this);
+        fireContentOpened(event.getContent());
       }
 
       public void contentRemoved(final ContentManagerEvent event) {
@@ -349,6 +563,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
           removeGridIfNeeded(grid);
         }
         updateTabsUI(false);
+        fireContentClosed(event.getContent());
       }
 
       public void contentRemoveQuery(final ContentManagerEvent event) {
@@ -498,9 +713,6 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
     for (TabInfo each : tabs) {
       hasToolbarContent |= updateTabUI(each);
     }
-
-    myTabs.getPresentation().setHideTabs(!hasToolbarContent && tabs.size() <= 1);
-
     myTabs.updateTabActions(validateNow);
 
     if (validateNow) {
@@ -508,7 +720,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
     }
   }
 
-  private static boolean updateTabUI(TabInfo tab) {
+  private boolean updateTabUI(TabInfo tab) {
     TabImpl t = getTabFor(tab);
     if (t == null) {
       return false;
@@ -534,9 +746,11 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
     }
 
     if (icon == null && contents.size() == 1) {
+      tab.setHidden(grid.isMinimized(contents.get(0)));
       icon = contents.get(0).getIcon();
     }
 
+    tab.setDragOutDelegate(myTabs.getTabs().size() > 1 || !isOriginal() ? myDragOutDelegate : null);
 
     Tab gridTab = grid.getTab();
     tab.setText(title).setIcon(gridTab != null && gridTab.isDefault() ? null : icon);
@@ -573,6 +787,10 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
       GridImpl eachGrid = getGridFor(each);
       eachGrid.saveUiState();
     }
+
+    for (RunnerContentUi child : myChildren) {
+      child.saveUiState();
+    }
   }
 
   @Nullable
@@ -581,6 +799,20 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
     return getTabFor(info);
   }
 
+  @Override
+  public void showNotify() {
+    final Window window = SwingUtilities.getWindowAncestor(myComponent);
+    if (window instanceof IdeFrame.Child) {
+      ((IdeFrame.Child)window).setFrameTitle(mySessionName);
+      //final Dimension size = DimensionService.getInstance().getSize("GridCell.Tab.0.center");
+      //final Rectangle bounds = window.getBounds();
+      //window.setBounds(bounds.x, bounds.y, size.width, size.height);
+    }
+  }
+
+  @Override
+  public void hideNotify() {}
+
   @Nullable
   private static TabImpl getTabFor(@Nullable final TabInfo tab) {
     if (tab == null) {
@@ -640,6 +872,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
     if (myComponent.getRootPane() != null) {
       saveUiState();
     }
+    myManager.removeAllContents(true);
   }
 
   public boolean canChangeSelectionTo(Content content, boolean implicit) {
@@ -674,14 +907,25 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
   }
 
   public void dispose() {
-
+    if (myOriginal != null) {
+      myOriginal.myChildren.remove(this);
+    }
   }
 
   public void restoreLayout() {
-    Content[] all = myManager.getContents();
+    final RunnerContentUi[] children = myChildren.toArray(new RunnerContentUi[myChildren.size()]);
+    final List<Content> contents = new ArrayList<Content>();
+    Collections.addAll(contents, myManager.getContents());
+    for (RunnerContentUi child : children) {
+      Collections.addAll(contents, child.myManager.getContents());
+    }
+    Content[] all = contents.toArray(new Content[contents.size()]);
 
     setStateIsBeingRestored(true, this);
     try {
+      for (RunnerContentUi child : children) {
+        child.myManager.removeAllContents(false);
+      }
       myManager.removeAllContents(false);
       myMinimizedViewActions.removeAll();
     }
@@ -730,7 +974,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
   }
 
   public boolean isMinimizeActionEnabled() {
-    return myMinimizeActionEnabled;
+    return myMinimizeActionEnabled && myOriginal == null;
   }
 
   public boolean isMoveToGridActionEnabled() {
@@ -820,12 +1064,12 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
     public void addNotify() {
       super.addNotify();
 
-      if (!myUiLastStateWasRestored) {
+      if (!myUiLastStateWasRestored && myOriginal == null) {
         myUiLastStateWasRestored = true;
 
-        //noinspection SSBasedInspection
         // [kirillk] this is done later since restoreUiState doesn't work properly in the addNotify call chain
         //todo to investigate and to fix (may cause extra flickering)
+        //noinspection SSBasedInspection
         SwingUtilities.invokeLater(new Runnable() {
           public void run() {
             restoreLastUiState().doWhenDone(new Runnable() {
@@ -946,90 +1190,6 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
     updateTabsUI(false);
   }
 
-  private static boolean willBeEmptyOnRemove(GridImpl grid, List<Content> toRemove) {
-    List<Content> attachedToGrid = grid.getAttachedContents();
-    for (Content each : attachedToGrid) {
-      if (!toRemove.contains(each)) return false;
-    }
-
-    return true;
-  }
-
-
-  public CellTransform.Restore detach(final Content[] content) {
-    List<Content> contents = Arrays.asList(content);
-
-    for (Content each : content) {
-      GridImpl eachGrid = getGridFor(each, false);
-      if (willBeEmptyOnRemove(eachGrid, contents)) {
-        TabInfo info = myTabs.findInfo(eachGrid);
-        if (info != null) {
-          info.setHidden(true);
-        }
-      }
-    }
-
-    updateTabsUI(true);
-
-    return new CellTransform.Restore() {
-      public ActionCallback restoreInGrid() {
-        showHiddenTabs();
-        updateTabsUI(true);
-        return new ActionCallback.Done();
-      }
-    };
-  }
-
-  private void showHiddenTabs() {
-    List<TabInfo> tabs = myTabs.getTabs();
-    for (TabInfo eachInfos : tabs) {
-      GridImpl eachGrid = (GridImpl)eachInfos.getComponent();
-      if (!eachGrid.getAttachedContents().isEmpty()) {
-        eachInfos.setHidden(false);
-      }
-    }
-  }
-
-  public void moveToTab(final Content content) {
-    saveUiState();
-
-    setStateIsBeingRestored(true, this);
-    try {
-      myManager.removeContent(content, false);
-      getStateFor(content).assignTab(myLayoutSettings.createNewTab());
-      getStateFor(content).setPlaceInGrid(PlaceInGrid.center);
-      myManager.addContent(content);
-    }
-    finally {
-      setStateIsBeingRestored(false, this);
-    }
-
-    saveUiState();
-  }
-
-  public void moveToGrid(final Content content) {
-    saveUiState();
-
-    setStateIsBeingRestored(true, this);
-
-    try {
-      myManager.removeContent(content, false);
-      getStateFor(content).assignTab(myLayoutSettings.getDefaultTab());
-      getStateFor(content).setPlaceInGrid(myLayoutSettings.getDefaultGridPlace(content));
-      myManager.addContent(content);
-    }
-    finally {
-      setStateIsBeingRestored(false, this);
-    }
-
-    select(content, true).doWhenDone(new Runnable() {
-      public void run() {
-        saveUiState();
-      }
-    });
-  }
-
-
   public Project getProject() {
     return myProject;
   }
@@ -1055,7 +1215,7 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
   }
 
   public boolean isHorizontalToolbar() {
-    return myLayoutSettings.isToolbarHorizontal();
+    return false;
   }
 
   public ActionCallback select(final Content content, final boolean requestFocus) {
@@ -1068,18 +1228,12 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
 
 
     final ActionCallback result = new ActionCallback();
-    if (grid.isDetached(content)) {
-      if (requestFocus) {
+    myTabs.select(info, false).doWhenDone(new Runnable() {
+      public void run() {
         grid.select(content, requestFocus).notifyWhenDone(result);
       }
-    }
-    else {
-      myTabs.select(info, false).doWhenDone(new Runnable() {
-        public void run() {
-          grid.select(content, requestFocus).notifyWhenDone(result);
-        }
-      });
-    }
+    });
+
 
     return result;
   }
@@ -1233,4 +1387,140 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
 
     return result;
   }
+
+
+  private int findFreeWindow() {
+    int i;
+    for (i = 1; i < Integer.MAX_VALUE; i++) {
+      if (!isUsed(i)) {
+        return i;
+      }
+    }
+    return i;
+  }
+
+  private boolean isUsed(int i) {
+    for (RunnerContentUi child : myChildren) {
+      if (child.getWindow() == i) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private DockManagerImpl getDockManager() {
+    return (DockManagerImpl)DockManager.getInstance(myProject);
+  }
+  
+  class MyDragOutDelegate implements TabInfo.DragOutDelegate {
+    private DragSession mySession;
+
+    @Override
+    public void dragOutStarted(MouseEvent mouseEvent, TabInfo info) {
+      final JComponent component = info.getComponent();
+      final Content[] data = CONTENT_KEY.getData((DataProvider)component);
+      final List<Content> contents = Arrays.asList(data);
+
+      final Dimension size = info.getComponent().getSize();
+      final Image image = myTabs.getComponentImage(info);
+      if (component instanceof Grid) {
+        info.setHidden(true);
+      }
+
+      Presentation presentation = new Presentation(info.getText());
+      presentation.setIcon(info.getIcon());
+      mySession = getDockManager().createDragSession(mouseEvent, new DockableGrid(image, presentation,
+                                                                                  size,
+                                                                                  contents, 0));
+    }
+
+    @Override
+    public void processDragOut(MouseEvent event, TabInfo source) {
+      mySession.process(event);
+    }
+
+    @Override
+    public void dragOutFinished(MouseEvent event, TabInfo source) {
+      final Component component = event.getComponent();
+      final IdeFrame window = UIUtil.getParentOfType(IdeFrame.class, component);
+      if (window != null) {
+        
+      }
+      mySession.process(event);
+      mySession = null;
+    }
+  }
+
+  class DockableGrid implements DockableContent<List<Content>> {
+    final Image myImg;
+    private Presentation myPresentation;
+    private final Dimension myPreferredSize;
+    private final List<Content> myContents;
+    private final int myWindow;
+
+    public DockableGrid(Image img, Presentation presentation, final Dimension size, List<Content> contents, int window) {
+      myImg = img;
+      myPresentation = presentation;
+      myPreferredSize = size;
+      myContents = contents;
+      myWindow = window;
+    }
+
+    @Override
+    public List<Content> getKey() {
+      return myContents;
+    }
+
+    @Override
+    public Image getPreviewImage() {
+      return myImg;
+    }
+
+    @Override
+    public Dimension getPreferredSize() {
+      return myPreferredSize;
+    }
+
+    @Override
+    public String getDockContainerType() {
+      return DockableGridContainerFactory.TYPE;
+    }
+
+    @Override
+    public Presentation getPresentation() {
+      return myPresentation;
+    }
+
+    public RunnerContentUi getRunnerUi() {
+      return RunnerContentUi.this;
+    }
+
+    public RunnerContentUi getOriginalRunnerUi() {
+      return myOriginal != null ? myOriginal : RunnerContentUi.this;
+    }
+
+    public List<Content> getContents() {
+      return myContents;
+    }
+
+    @Override
+    public void close() {
+    }
+
+    public int getWindow() {
+      return myWindow;
+    }
+  }
+
+  void fireContentOpened(Content content) {
+    for (Listener each : myDockingListeners) {
+      each.contentAdded(content);
+    }
+  }
+
+  void fireContentClosed(Content content) {
+    for (Listener each : myDockingListeners) {
+      each.contentRemoved(content);
+    }
+  }
 }
index 13d0e593c255312aa4ed63b0fb626f2511894c76..84282337391b230eb87abda9bf450dd77083ac08 100644 (file)
 
 package com.intellij.execution.ui.layout.impl;
 
+import com.intellij.execution.ui.layout.GridCell;
 import com.intellij.execution.ui.layout.ViewContext;
 import com.intellij.openapi.actionSystem.ActionGroup;
+import com.intellij.openapi.util.ActionCallback;
 
 public interface ViewContextEx extends ViewContext {
   RunnerLayout getLayoutSettings();
 
   ActionGroup getCellPopupGroup(String place);
 
-  void doWhenInitialized(Runnable runnable);
+  boolean isOriginal();
+  
+  int getWindow();
 
+  ActionCallback detachTo(int window, GridCell cell);
 }
\ No newline at end of file
index 89673d9d600dcf8db7ce33bb22faa7f5b9852998..83b8d083382718f67823dab2381f0e0cd8c0cb97 100644 (file)
@@ -31,16 +31,19 @@ public class ViewImpl implements View {
 
   private Tab myTab;
   private int myTabIndex;
+  
+  private int myWindow;
 
   private PlaceInGrid myPlaceInGrid;
 
   private boolean myMinimizedInGrid;
 
-  public ViewImpl(String id, TabImpl tab, final PlaceInGrid placeInGrid, boolean minimizedInGrid) {
+  public ViewImpl(String id, TabImpl tab, final PlaceInGrid placeInGrid, boolean minimizedInGrid, int window) {
     myID = id;
     myTab = tab;
     myPlaceInGrid = placeInGrid;
     myMinimizedInGrid = minimizedInGrid;
+    myWindow = window;
   }
 
   public ViewImpl(RunnerLayout settings, Element element) {
@@ -94,6 +97,16 @@ public class ViewImpl implements View {
     myTabIndex = tabIndex;
   }
 
+  @Override
+  public int getWindow() {
+    return myWindow;
+  }
+
+  @Override
+  public void setWindow(int windowNumber) {
+    myWindow = windowNumber;
+  }
+
   public static class Default {
 
     private final String myID;
@@ -110,7 +123,7 @@ public class ViewImpl implements View {
 
     public ViewImpl createView(RunnerLayout settings) {
       final TabImpl tab = myTabID == Integer.MAX_VALUE ? settings.createNewTab() : settings.getOrCreateTab(myTabID);
-      return new ViewImpl(myID, tab, myPlaceInGrid, myMinimizedInGrid);
+      return new ViewImpl(myID, tab, myPlaceInGrid, myMinimizedInGrid, 0);
     }
 
     public PlaceInGrid getPlaceInGrid() {
index 58da8434f90c464f426a49571004c9b5e560b920..4f5ec9700bbf39d7cbfc283a33fe0d4a63eb7962 100644 (file)
     </group>
 
     <group id="RunnerLayoutActions">
-      <group id="Runner.Layout" icon="/debugger/restoreLayout.png" popup="true">
-        <action id="Runner.RestoreLayout" class="com.intellij.execution.ui.layout.actions.RestoreLayoutAction"/>
+      <group id="Runner.Layout" icon="/debugger/restoreLayout.png">
+        <action id="Runner.RestoreLayout" class="com.intellij.execution.ui.layout.actions.RestoreLayoutAction"
+                icon="/debugger/restoreLayout.png"/>
         <!--action id="Runner.ToggleToolbarLayout" class="com.intellij.execution.ui.layout.actions.ToggleToolbarLayoutAction"/-->
       </group>