execute((ItemWrapper)item, executor);
}
});
- listPopup.cancel();
+ listPopup.closeOk(null);
}
}
}
package com.intellij.ide.util.gotoByName;
import com.intellij.Patches;
+import com.intellij.codeInsight.hint.HintManager;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.actions.CopyReferenceAction;
import com.intellij.ide.ui.UISettings;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.openapi.ui.popup.JBPopupListener;
+import com.intellij.openapi.ui.popup.LightweightWindowEvent;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Pair;
public void focusLost(final FocusEvent e) {
myHideAlarm.addRequest(new Runnable() {
public void run() {
- if (!JBPopupFactory.getInstance().isChildPopupFocused(e.getComponent())) {
+ JBPopup popup = JBPopupFactory.getInstance().getChildFocusedPopup(e.getComponent());
+ if (popup != null) {
+ popup.addListener(new JBPopupListener.Adapter() {
+ @Override
+ public void onClosed(LightweightWindowEvent event) {
+ if (event.isOk()) {
+ hideHint();
+ }
+ }
+ });
+ } else {
hideHint();
}
}
import com.intellij.openapi.Disposable;
import com.intellij.ui.awt.RelativePoint;
+import com.intellij.util.ui.PositionTracker;
import javax.swing.*;
import java.awt.*;
public interface Balloon extends Disposable {
+ void show(PositionTracker<Balloon> tracker, Position preferredPosition);
+
void show(RelativePoint target, Position prefferedPosition);
void show(JLayeredPane pane);
void showCenteredInCurrentWindow(@NotNull Project project);
/**
- * Cancels the popup (as if Esc was pressed).
+ * Hides popup as if Enter was pressed or or any other "accept" action
+ */
+
+ void closeOk(@Nullable InputEvent e);
+
+ /**
+ * Cancels the popup as if Esc was pressed or any other "cancel" action
*/
void cancel();
public abstract RelativePoint guessBestPopupLocation(JComponent component);
public boolean isChildPopupFocused(@Nullable Component parent) {
- if (parent == null) return false;
+ return getChildFocusedPopup(parent) != null;
+ }
+
+ public JBPopup getChildFocusedPopup(@Nullable Component parent) {
+ if (parent == null) return null;
List<JBPopup> popups = getChildPopups(parent);
for (JBPopup each : popups) {
- if (each.isFocused()) return true;
+ if (each.isFocused()) return each;
}
- return false;
+ return null;
}
/**
package com.intellij.openapi.ui.popup;
public class LightweightWindowEvent {
+
private final LightweightWindow myWindow;
+ private boolean myOk;
public LightweightWindowEvent(LightweightWindow window) {
+ this(window, false);
+ }
+
+ public LightweightWindowEvent(LightweightWindow window, boolean isOk) {
myWindow = window;
+ myOk = isOk;
+ }
+
+ public boolean isOk() {
+ return myOk;
}
public Balloon asBalloon() {
@Override
public void mousePressed(MouseEvent e) {
if (UIUtil.isActionClick(e) && !isSelectionButtonDown(e) && !e.isConsumed()) {
- closePopup(true, e);
+ closePopup(true, e, true);
}
}
});
if (!shouldPerformAction && myChooserComponent instanceof ListWithFilter) {
if (((ListWithFilter)myChooserComponent).resetFilter()) return;
}
- closePopup(shouldPerformAction, null);
+ closePopup(shouldPerformAction, null, shouldPerformAction);
}
}, keyStroke, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
}
- private void closePopup(boolean shouldPerformAction, MouseEvent e) {
+ private void closePopup(boolean shouldPerformAction, MouseEvent e, boolean isOk) {
if (shouldPerformAction) {
myPopup.setFinalRunnable(myItemChoosenRunnable);
}
- myPopup.cancel(e);
+ if (isOk) {
+ myPopup.closeOk(e);
+ } else {
+ myPopup.cancel(e);
+ }
}
@NotNull
--- /dev/null
+/*
+ * Copyright 2000-2010 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.util.ui;
+
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.ui.awt.RelativePoint;
+
+import java.awt.*;
+import java.awt.event.*;
+
+public abstract class PositionTracker<T> implements Disposable, HierarchyBoundsListener, HierarchyListener, ComponentListener {
+
+ private Component myComponent;
+ private Client<T> myClient;
+
+ public PositionTracker(Component component) {
+ myComponent = component;
+ }
+
+ public final void init(Client<T> client) {
+ myClient = client;
+
+ Disposer.register(client, this);
+
+ myComponent.addHierarchyBoundsListener(this);
+ myComponent.addHierarchyListener(this);
+ myComponent.addComponentListener(this);
+ }
+
+ public final Component getComponent() {
+ return myComponent;
+ }
+
+ public final void ancestorMoved(HierarchyEvent e) {
+ revalidate();
+ }
+
+ public final void ancestorResized(HierarchyEvent e) {
+ revalidate();
+ }
+
+ public final void hierarchyChanged(HierarchyEvent e) {
+ revalidate();
+ }
+
+ public void componentResized(ComponentEvent e) {
+ revalidate();
+ }
+
+ public void componentMoved(ComponentEvent e) {
+ revalidate();
+ }
+
+ public void componentShown(ComponentEvent e) {
+ revalidate();
+ }
+
+ public void componentHidden(ComponentEvent e) {
+ revalidate();
+ }
+
+ protected final void revalidate() {
+ myClient.revalidate(this);
+ }
+
+ public abstract RelativePoint recalculateLocation(T object);
+
+ public final void dispose() {
+ myComponent.removeHierarchyBoundsListener(this);
+ myComponent.removeHierarchyListener(this);
+ myComponent.removeComponentListener(this);
+ }
+
+ public static final class Static<T> extends PositionTracker<T> {
+
+ private RelativePoint myPoint;
+
+ public Static(RelativePoint point) {
+ super(point.getComponent());
+ myPoint = point;
+ }
+
+ @Override
+ public RelativePoint recalculateLocation(Object object) {
+ return myPoint;
+ }
+ }
+
+ public interface Client<T> extends Disposable {
+
+ void revalidate(PositionTracker<T> tracker);
+
+ }
+
+}
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.CollectionFactory;
import com.intellij.util.containers.HashMap;
+import com.intellij.util.ui.PositionTracker;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.update.UiNotifyConnector;
import org.jdom.Element;
Icon actualIcon = icon != null ? icon : type.getDefaultIcon();
final Balloon balloon =
- JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(text.replace("\n", "<br>"), actualIcon, type.getPopupBackground(), listener)
+ JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(text.replace("\n", "<br>"), actualIcon, type.getPopupBackground(), listener).setHideOnClickOutside(false).setHideOnFrameResize(false)
.createBalloon();
Disposer.register(balloon, new Disposable() {
public void dispose() {
stripe.repaint();
}
});
+ Disposer.register(getProject(), balloon);
final StripeButton button = stripe.getButtonFor(toolWindowId);
if (button == null) return;
final Runnable show = new Runnable() {
public void run() {
if (button.isShowing()) {
- final Point point = new Point(button.getBounds().width / 2, button.getHeight() / 2 - 2);
- balloon.show(new RelativePoint(button, point), position.get());
+ PositionTracker tracker = new PositionTracker<Balloon>(button) {
+ @Override
+ public RelativePoint recalculateLocation(Balloon object) {
+ Stripe twStripe = myToolWindowsPane.getStripeFor(toolWindowId);
+ StripeButton twButton = twStripe != null ? twStripe.getButtonFor(toolWindowId) : null;
+
+ if (twButton == null) return null;
+
+ if (getToolWindow(toolWindowId).getAnchor() != anchor) {
+ object.hide();
+ return null;
+ }
+
+ final Point point = new Point(twButton.getBounds().width / 2, twButton.getHeight() / 2 - 2);
+ return new RelativePoint(twButton, point);
+ }
+ };
+ balloon.show(tracker, position.get());
}
else {
final Rectangle bounds = myToolWindowsPane.getBounds();
import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.ui.components.panels.Wrapper;
import com.intellij.util.Alarm;
-import com.intellij.util.ui.Animator;
-import com.intellij.util.ui.BaseButtonBehavior;
-import com.intellij.util.ui.TimedDeadzone;
-import com.intellij.util.ui.UIUtil;
+import com.intellij.util.ui.*;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.util.concurrent.CopyOnWriteArraySet;
-public class BalloonImpl implements Disposable, Balloon, LightweightWindow {
+public class BalloonImpl implements Disposable, Balloon, LightweightWindow, PositionTracker.Client<Balloon> {
private MyComponent myComp;
private JLayeredPane myLayeredPane;
}
}
+ if (event instanceof MouseEvent && UIUtil.isCloseClick((MouseEvent)event)) {
+ hide();
+ return;
+ }
+
if (myHideOnKey && (event.getID() == KeyEvent.KEY_PRESSED)) {
final KeyEvent ke = (KeyEvent)event;
if (SwingUtilities.isDescendingFrom(ke.getComponent(), myComp) || ke.getComponent() == myComp) return;
private final CopyOnWriteArraySet<JBPopupListener> myListeners = new CopyOnWriteArraySet<JBPopupListener>();
private boolean myVisible;
+ private PositionTracker<Balloon> myTracker;
private boolean isInsideBalloon(MouseEvent me) {
if (!me.getComponent().isShowing()) return true;
show(target, pos);
}
+ public void show(PositionTracker<Balloon> tracker, Balloon.Position position) {
+ Position pos = BELOW;
+ switch (position) {
+ case atLeft:
+ pos = AT_LEFT;
+ break;
+ case atRight:
+ pos = AT_RIGHT;
+ break;
+ case below:
+ pos = BELOW;
+ break;
+ case above:
+ pos = ABOVE;
+ break;
+ }
+
+ show(tracker, pos);
+ }
+
+
private void show(RelativePoint target, Position position) {
+ show(new PositionTracker.Static<Balloon>(target), position);
+ }
+
+ private void show(PositionTracker<Balloon> tracker, Position position) {
if (isVisible()) return;
assert !myDisposed : "Balloon is already disposed";
- assert target.getComponent().isShowing() : "Target component is not showing: " + target;
+ assert tracker.getComponent().isShowing() : "Target component is not showing: " + tracker;
+
+ myTracker = tracker;
+ myTracker.init(this);
- final Window window = SwingUtilities.getWindowAncestor(target.getComponent());
+ final Window window = SwingUtilities.getWindowAncestor(tracker.getComponent());
JRootPane root = null;
if (window instanceof JFrame) {
: new EmptyBorder(getNormalInset(), getNormalInset(), getNormalInset(), getNormalInset());
myComp = new MyComponent(myContent, this, border);
- myTargetPoint = target.getPoint(myLayeredPane);
+ myTargetPoint = tracker.recalculateLocation(this).getPoint(myLayeredPane);
myComp.clear();
myComp.myAlpha = 0f;
KeyEvent.KEY_EVENT_MASK);
}
+ public void revalidate(PositionTracker<Balloon> tracker) {
+ RelativePoint newPosition = tracker.recalculateLocation(this);
+
+ if (newPosition != null) {
+ myTargetPoint = newPosition.getPoint(myLayeredPane);
+ myPosition.updateLocation(this);
+ }
+ }
+
public void show(JLayeredPane pane) {
show(pane, null);
}
private Runnable myFinalRunnable;
+ protected boolean myOk;
+
protected final SpeedSearch mySpeedSearch = new SpeedSearch() {
boolean searchFieldShown = false;
protected void update() {
return relativePoint;
}
+ public final void closeOk(@Nullable InputEvent e) {
+ setOk(true);
+ cancel(e);
+ }
+
public final void cancel() {
cancel(null);
}
if (myListeners != null) {
for (JBPopupListener each : myListeners) {
- each.onClosed(new LightweightWindowEvent(this));
+ each.onClosed(new LightweightWindowEvent(this, myOk));
}
}
}
public void setFinalRunnable(Runnable finalRunnable) {
myFinalRunnable = finalRunnable;
}
+
+ public void setOk(boolean ok) {
+ myOk = ok;
+ }
}
getParent().setFinalRunnable(runnable);
}
}
+
+ @Override
+ public void setOk(boolean ok) {
+ if (getParent() == null) {
+ super.setOk(ok);
+ } else {
+ getParent().setOk(ok);
+ }
+ }
}
if (myListModel.getSize() == 0) {
setFinalRunnable(myStep.getFinalRunnable());
+ setOk(true);
disposeAllParents(e);
setIndexForShowingChild(-1);
return true;
return false;
}
else {
+ setOk(true);
setFinalRunnable(myStep.getFinalRunnable());
disposeAllParents(e);
setIndexForShowingChild(-1);
final PopupStep queriedStep = myStep.onChosen(userObject, handleFinalChoices);
if (queriedStep == PopupStep.FINAL_CHOICE || !hasNextStep) {
setFinalRunnable(myStep.getFinalRunnable());
+ setOk(true);
disposeAllParents(e);
}
else {