/*
* Copyright 2000-2017 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.openapi.wm.impl.status;
import com.intellij.icons.AllIcons;
import com.intellij.ide.IdeEventQueue;
import com.intellij.ide.ui.UISettings;
import com.intellij.ide.ui.UISettingsListener;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.PopupChooserBuilder;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.*;
import com.intellij.openapi.wm.impl.IdeFrameImpl;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBList;
import com.intellij.util.Alarm;
import com.intellij.util.ui.BaseButtonBehavior;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.TimedDeadzone;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author Konstantin Bulenkov
*/
class ToolWindowsWidget extends JLabel implements CustomStatusBarWidget, StatusBarWidget, Disposable, UISettingsListener, PropertyChangeListener {
private final Alarm myAlarm;
private StatusBar myStatusBar;
private JBPopup popup;
private boolean wasExited = false;
ToolWindowsWidget(@NotNull Disposable parent) {
new BaseButtonBehavior(this, TimedDeadzone.NULL) {
@Override
protected void execute(MouseEvent e) {
performAction();
}
}.setActionTrigger(MouseEvent.MOUSE_PRESSED);
IdeEventQueue.getInstance().addDispatcher(e -> {
if (e instanceof MouseEvent) {
MouseEvent mouseEvent = (MouseEvent)e;
if (mouseEvent.getComponent() == null || !SwingUtilities.isDescendingFrom(mouseEvent.getComponent(), SwingUtilities.getWindowAncestor(this))) {
return false;
}
if (e.getID() == MouseEvent.MOUSE_MOVED && isShowing()) {
Point p = mouseEvent.getLocationOnScreen();
Point screen = this.getLocationOnScreen();
if (new Rectangle(screen.x - 4, screen.y - 2, getWidth() + 4, getHeight() + 4).contains(p)) {
mouseEntered();
wasExited = false;
}
else {
if (!wasExited) {
wasExited = mouseExited(p);
}
}
}
else if (e.getID() == MouseEvent.MOUSE_EXITED) {
//mouse exits WND
mouseExited(mouseEvent.getLocationOnScreen());
}
}
return false;
}, parent);
ApplicationManager.getApplication().getMessageBus().connect(this).subscribe(UISettingsListener.TOPIC, this);
KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener("focusOwner", this);
myAlarm = new Alarm(parent);
}
public boolean mouseExited(Point currentLocationOnScreen) {
myAlarm.cancelAllRequests();
if (popup != null && popup.isVisible()) {
final Point screen = popup.getLocationOnScreen();
final Rectangle popupScreenRect = new Rectangle(screen.x, screen.y, popup.getSize().width, popup.getSize().height);
if (!popupScreenRect.contains(currentLocationOnScreen)) {
myAlarm.cancelAllRequests();
myAlarm.addRequest(() -> {
if (popup != null && popup.isVisible()) {
popup.cancel();
}
}, 300);
return true;
}
}
return false;
}
public void mouseEntered() {
final boolean active = ApplicationManager.getApplication().isActive();
if (!active) {
return;
}
if (myAlarm.getActiveRequestCount() == 0) {
myAlarm.addRequest(() -> {
final IdeFrameImpl frame = UIUtil.getParentOfType(IdeFrameImpl.class, this);
if (frame == null) return;
List<ToolWindow> toolWindows = new ArrayList<>();
final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(frame.getProject());
for (String id : toolWindowManager.getToolWindowIds()) {
final ToolWindow tw = toolWindowManager.getToolWindow(id);
if (tw.isAvailable() && tw.isShowStripeButton()) {
toolWindows.add(tw);
}
}
Collections.sort(toolWindows, (o1, o2) -> StringUtil.naturalCompare(o1.getStripeTitle(), o2.getStripeTitle()));
final JBList list = new JBList(toolWindows);
list.setCellRenderer(new ListCellRenderer() {
final JBLabel label = new JBLabel();
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
final ToolWindow toolWindow = (ToolWindow)value;
label.setText(toolWindow.getStripeTitle());
label.setIcon(toolWindow.getIcon());
label.setBorder(JBUI.Borders.empty(4, 10));
label.setForeground(UIUtil.getListForeground(isSelected));
label.setBackground(UIUtil.getListBackground(isSelected));
final JPanel panel = new JPanel(new BorderLayout());
panel.add(label, BorderLayout.CENTER);
panel.setBackground(UIUtil.getListBackground(isSelected));
return panel;
}
});
final Dimension size = list.getPreferredSize();
final JComponent c = this;
final Insets padding = UIUtil.getListViewportPadding();
final RelativePoint point = new RelativePoint(c, new Point(-4, -padding.top - padding.bottom - 4 - size.height + (SystemInfo.isMac ? 2 : 0)));
if (popup != null && popup.isVisible()) {
return;
}
list.setSelectedIndex(list.getItemsCount() - 1);
PopupChooserBuilder builder = JBPopupFactory.getInstance().createListPopupBuilder(list);
popup = builder.setAutoselectOnMouseMove(true).setRequestFocus(false).setItemChoosenCallback(() -> {
if (popup != null) popup.closeOk(null);
final Object value = list.getSelectedValue();
if (value instanceof ToolWindow) {
((ToolWindow)value).activate(null, true, true);
}
}).createPopup();
list.setVisibleRowCount(30); // override default of 15 set when createPopup() is called
popup.show(point);
}, 300);
}
}
@Override
public void addNotify() {
super.addNotify();
//final String key = "toolwindow.stripes.buttons.info.shown";
//if (UISettings.getInstance().HIDE_TOOL_STRIPES && !PropertiesComponent.getInstance().isTrueValue(key)) {
// PropertiesComponent.getInstance().setValue(key, String.valueOf(true));
// final Alarm alarm = new Alarm();
// alarm.addRequest(() -> {
// GotItMessage.createMessage(UIBundle.message("tool.window.quick.access.title"), UIBundle.message(
// "tool.window.quick.access.message"))
// .setDisposable(this)
// .show(new RelativePoint(this, new Point(10, 0)), Balloon.Position.above);
// Disposer.dispose(alarm);
// }, 20000);
//}
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
updateIcon();
}
@Override
public void uiSettingsChanged(UISettings uiSettings) {
updateIcon();
}
private void performAction() {
if (isActive()) {
UISettings.getInstance().setHideToolStripes(!UISettings.getInstance().getHideToolStripes());
UISettings.getInstance().fireUISettingsChanged();
}
}
private void updateIcon() {
setToolTipText(null);
if (isActive()) {
boolean changes = false;
if (!isVisible()) {
setVisible(true);
changes = true;
}
Icon icon = UISettings.getInstance().getHideToolStripes() ? AllIcons.General.TbShown : AllIcons.General.TbHidden;
if (icon != getIcon()) {
setIcon(icon);
changes = true;
}
//Set<Integer> vks = ToolWindowManagerImpl.getActivateToolWindowVKs();
//String text = "Click to show or hide the tool window bars";
//if (vks.size() == 1) {
// Integer stroke = vks.iterator().next();
// String keystrokeText = KeymapUtil.getKeystrokeText(KeyStroke.getKeyStroke(stroke.intValue(), 0));
// text += ".\nDouble-press and hold " + keystrokeText + " to show tool window bars when hidden.";
//}
//if (!text.equals(getToolTipText())) {
// setToolTipText(text);
// changes = true;
//}
if (changes) {
revalidate();
repaint();
}
}
else {
setVisible(false);
setToolTipText(null);
}
}
private boolean isActive() {
return myStatusBar != null &&
myStatusBar.getFrame() != null &&
myStatusBar.getFrame().getProject() != null &&
Registry.is("ide.windowSystem.showTooWindowButtonsSwitcher");
}
@Override
public JComponent getComponent() {
return this;
}
@NotNull
@Override
public String ID() {
return "ToolWindows Widget";
}
@Override
public WidgetPresentation getPresentation(@NotNull PlatformType type) {
return null;
}
@Override
public void install(@NotNull StatusBar statusBar) {
myStatusBar = statusBar;
updateIcon();
}
@Override
public void dispose() {
Disposer.dispose(this);
KeyboardFocusManager.getCurrentKeyboardFocusManager().removePropertyChangeListener("focusOwner", this);
myStatusBar = null;
popup = null;
}
}