palette -> idea-ui

This commit is contained in:
Dmitry Jemerov
2009-09-01 19:27:31 +04:00
parent 531a7a28b9
commit c544bf2bb0
5 changed files with 0 additions and 0 deletions
@@ -0,0 +1,384 @@
package com.intellij.ide.palette.impl;
import com.intellij.ide.dnd.*;
import com.intellij.ide.palette.PaletteGroup;
import com.intellij.ide.palette.PaletteItem;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.ActionPopupMenu;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.ui.ColoredListCellRenderer;
import com.intellij.ui.PopupHandler;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.plaf.basic.BasicListUI;
import java.awt.*;
import java.awt.event.*;
/**
* @author yole
*/
public class PaletteComponentList extends JList {
private final Project myProject;
private final PaletteGroup myGroup;
private int myHoverIndex = -1;
private int myBeforeClickSelectedRow = -1;
private int myDropTargetIndex = -1;
private boolean myNeedClearSelection = false;
public PaletteComponentList(Project project, PaletteGroup group) {
myProject = project;
myGroup = group;
setModel(new AbstractListModel() {
public int getSize() {
return myGroup.getItems().length;
}
public Object getElementAt(int index) {
return myGroup.getItems() [index];
}
});
addMouseListener(new MouseAdapter() {
@Override public void mouseEntered(MouseEvent e) {
setHoverIndex(locationToIndex(e.getPoint()));
}
@Override public void mouseExited(MouseEvent e) {
setHoverIndex(-1);
}
@Override public void mousePressed(MouseEvent e) {
myNeedClearSelection = (SwingUtilities.isLeftMouseButton(e) &&
myBeforeClickSelectedRow >= 0 &&
locationToIndex(e.getPoint()) == myBeforeClickSelectedRow &&
!UIUtil.isControlKeyDown(e) && !e.isShiftDown());
}
@Override public void mouseReleased(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e) &&
myBeforeClickSelectedRow >= 0 &&
locationToIndex(e.getPoint()) == myBeforeClickSelectedRow &&
!UIUtil.isControlKeyDown(e) && !e.isShiftDown() && myNeedClearSelection) {
clearSelection();
}
}
});
addMouseListener(new PopupHandler() {
public void invokePopup(final Component comp, final int x, final int y) {
requestFocusInWindow();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
int index = locationToIndex(new Point(x, y));
PaletteItem[] items = myGroup.getItems();
if (index >= 0 && index < items.length) {
if (getSelectedIndex() != index) {
addSelectionInterval(index, index);
}
PaletteItem item = items [index];
ActionGroup group = item.getPopupActionGroup();
if (group != null) {
ActionPopupMenu popupMenu = ActionManager.getInstance().createActionPopupMenu(ActionPlaces.UNKNOWN, group);
popupMenu.getComponent().show(comp, x, y);
}
}
}
});
}
});
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
setHoverIndex(locationToIndex(e.getPoint()));
}
});
addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
PaletteManager.getInstance(myProject).notifyKeyEvent(e);
}
public void keyReleased(KeyEvent e) {
PaletteManager.getInstance(myProject).notifyKeyEvent(e);
}
public void keyTyped(KeyEvent e) {
PaletteManager.getInstance(myProject).notifyKeyEvent(e);
}
});
setCellRenderer(new ComponentCellRenderer());
setVisibleRowCount(0);
setLayoutOrientation(HORIZONTAL_WRAP);
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
final DnDManager dndManager = DnDManager.getInstance();
dndManager.registerSource(new MyDnDSource(), this);
dndManager.registerTarget(new MyDnDTarget(), this);
initActions();
}
private void setHoverIndex(final int index) {
if (index != myHoverIndex) {
if (myHoverIndex >= 0) repaint(getCellBounds(myHoverIndex, myHoverIndex));
myHoverIndex = index;
if (myHoverIndex >= 0) repaint(getCellBounds(myHoverIndex, myHoverIndex));
}
}
private void setDropTargetIndex(final int index) {
if (index != myDropTargetIndex) {
myDropTargetIndex = index;
repaint();
}
}
@Override public void updateUI() {
setUI(new ComponentListUI());
invalidate();
}
private void initActions() {
@NonNls ActionMap map = getActionMap();
map.put( "selectPreviousRow", new MoveFocusAction( map.get( "selectPreviousRow" ), false ) );
map.put( "selectNextRow", new MoveFocusAction( map.get( "selectNextRow" ), true ) );
map.put( "selectPreviousColumn", new MoveFocusAction( new ChangeColumnAction( map.get( "selectPreviousColumn" ), false ), false ) );
map.put( "selectNextColumn", new MoveFocusAction( new ChangeColumnAction( map.get( "selectNextColumn" ), true ), true ) );
}
Integer myTempWidth;
public int getWidth () {
return (myTempWidth == null) ? super.getWidth () : myTempWidth.intValue ();
}
public int getPreferredHeight(final int width) {
myTempWidth = width;
try {
return getUI().getPreferredSize(this).height;
}
finally {
myTempWidth = null;
}
}
public void takeFocusFrom(PaletteGroupHeader paletteGroup, int indexToSelect) {
if (indexToSelect == -1) {
//this is not 'our' CategoryButton so we'll assume it's the one below this category list
indexToSelect = getModel().getSize() - 1;
}
else if (getModel().getSize() == 0) {
indexToSelect = -1;
}
requestFocus();
setSelectedIndex(indexToSelect);
if (indexToSelect >= 0) {
ensureIndexIsVisible(indexToSelect);
}
}
@Override protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (myDropTargetIndex >= 0) {
int dropLineY;
Rectangle rc;
if (myDropTargetIndex == myGroup.getItems().length) {
rc = getCellBounds(myDropTargetIndex-1, myDropTargetIndex-1);
dropLineY = (int)rc.getMaxY()-1;
}
else {
rc = getCellBounds(myDropTargetIndex, myDropTargetIndex);
dropLineY = rc.y;
}
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLUE);
g2d.setStroke(new BasicStroke(2.0f));
g2d.drawLine(rc.x, dropLineY, rc.x+rc.width, dropLineY);
g2d.drawLine(rc.x, dropLineY-2, rc.x, dropLineY+2);
g2d.drawLine(rc.x+rc.width, dropLineY-2, rc.x+rc.width, dropLineY+2);
}
}
class ComponentListUI extends BasicListUI {
private ComponentListListener myListener;
@Override protected void updateLayoutState() {
super.updateLayoutState();
if (list.getLayoutOrientation() == JList.HORIZONTAL_WRAP) {
Insets insets = list.getInsets();
int listWidth = list.getWidth() - (insets.left + insets.right);
if (listWidth >= cellWidth) {
int columnCount = listWidth / cellWidth;
cellWidth = (columnCount == 0) ? 1 : listWidth / columnCount;
}
}
}
@Override protected void installListeners() {
myListener = new ComponentListListener();
addMouseListener(myListener);
super.installListeners();
}
@Override
protected void uninstallListeners() {
if (myListener != null) {
removeMouseListener(myListener);
}
super.uninstallListeners();
}
private class ComponentListListener extends MouseAdapter {
@Override public void mousePressed(MouseEvent e) {
myBeforeClickSelectedRow = list.getSelectedIndex();
}
}
}
private static class ComponentCellRenderer extends ColoredListCellRenderer {
protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) {
PaletteItem paletteItem = (PaletteItem) value;
clear();
paletteItem.customizeCellRenderer(this, selected, hasFocus);
}
}
private class MoveFocusAction extends AbstractAction {
private final Action defaultAction;
private final boolean focusNext;
public MoveFocusAction(Action defaultAction, boolean focusNext) {
this.defaultAction = defaultAction;
this.focusNext = focusNext;
}
public void actionPerformed(ActionEvent e) {
int selIndexBefore = getSelectedIndex();
defaultAction.actionPerformed(e);
int selIndexCurrent = getSelectedIndex();
if (selIndexBefore != selIndexCurrent) return;
if (focusNext && 0 == selIndexCurrent) return;
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
Container container = kfm.getCurrentFocusCycleRoot();
FocusTraversalPolicy policy = container.getFocusTraversalPolicy();
if (null == policy) policy = kfm.getDefaultFocusTraversalPolicy();
Component next = focusNext
? policy.getComponentAfter(container, PaletteComponentList.this)
: policy.getComponentBefore(container, PaletteComponentList.this);
if (null != next && next instanceof PaletteGroupHeader) {
clearSelection();
next.requestFocus();
((PaletteGroupHeader)next).scrollRectToVisible(next.getBounds());
}
}
}
private class ChangeColumnAction extends AbstractAction {
private final Action defaultAction;
private final boolean selectNext;
public ChangeColumnAction(Action defaultAction, boolean selectNext) {
this.defaultAction = defaultAction;
this.selectNext = selectNext;
}
public void actionPerformed(ActionEvent e) {
int selIndexBefore = getSelectedIndex();
defaultAction.actionPerformed(e);
int selIndexCurrent = getSelectedIndex();
if ((selectNext && selIndexBefore < selIndexCurrent) || (!selectNext && selIndexBefore > selIndexCurrent)) return;
if (selectNext) {
if (selIndexCurrent == selIndexBefore + 1) selIndexCurrent++;
if (selIndexCurrent < getModel().getSize() - 1) {
setSelectedIndex(selIndexCurrent + 1);
scrollRectToVisible(getCellBounds(selIndexCurrent + 1, selIndexCurrent + 1));
}
}
else {
if (selIndexCurrent > 0) {
setSelectedIndex(selIndexCurrent - 1);
scrollRectToVisible(getCellBounds(selIndexCurrent - 1, selIndexCurrent - 1));
}
}
}
}
private class MyDnDTarget implements DnDTarget {
public boolean update(DnDEvent aEvent) {
setHoverIndex(-1);
if (aEvent.getAttachedObject() instanceof PaletteItem) {
setDropTargetIndex(locationToTargetIndex(aEvent.getPoint()));
aEvent.setDropPossible(true, null);
}
else {
setDropTargetIndex(-1);
aEvent.setDropPossible(false, null);
}
return false;
}
public void drop(DnDEvent aEvent) {
setDropTargetIndex(-1);
if (aEvent.getAttachedObject() instanceof PaletteItem) {
int index = locationToTargetIndex(aEvent.getPoint());
if (index >= 0) {
myGroup.handleDrop(myProject, (PaletteItem) aEvent.getAttachedObject(), index);
}
}
}
public void cleanUpOnLeave() {
setDropTargetIndex(-1);
}
private int locationToTargetIndex(Point location) {
int row = locationToIndex(location);
if (row < 0) {
return -1;
}
Rectangle rc = getCellBounds(row, row);
return location.y < rc.getCenterY() ? row : row + 1;
}
public void updateDraggedImage(Image image, Point dropPoint, Point imageOffset) {
}
}
private class MyDnDSource implements DnDSource {
public boolean canStartDragging(DnDAction action, Point dragOrigin) {
int index = locationToIndex(dragOrigin);
return index >= 0 && myGroup.getItems() [index].startDragging() != null;
}
public DnDDragStartBean startDragging(DnDAction action, Point dragOrigin) {
int index = locationToIndex(dragOrigin);
if (index < 0) return null;
return myGroup.getItems() [index].startDragging();
}
@Nullable
public Pair<Image, Point> createDraggedImage(DnDAction action, Point dragOrigin) {
return null;
}
public void dragDropEnd() {
}
public void dropActionChanged(final int gestureModifiers) {
PaletteManager.getInstance(myProject).notifyDropActionChanged(gestureModifiers);
}
}
}
@@ -0,0 +1,102 @@
/*
* Copyright (c) 2000-2006 JetBrains s.r.o. All Rights Reserved.
*/
package com.intellij.ide.palette.impl;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
/**
* @author yole
*/
public class PaletteContentWindow extends JPanel implements Scrollable {
public PaletteContentWindow() {
setLayout(new PaletteLayoutManager());
}
public Dimension getPreferredScrollableViewportSize() {
return getPreferredSize();
}
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return 20;
}
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return 100;
}
public boolean getScrollableTracksViewportWidth() {
return true;
}
public boolean getScrollableTracksViewportHeight() {
return false;
}
@Nullable PaletteGroupHeader getLastGroupHeader() {
PaletteGroupHeader result = null;
for(Component comp: getComponents()) {
if (comp instanceof PaletteGroupHeader) {
result = (PaletteGroupHeader) comp;
}
}
return result;
}
private static class PaletteLayoutManager implements LayoutManager {
public void addLayoutComponent(String name, Component comp) {
}
public void layoutContainer(Container parent) {
int width = parent.getWidth();
int height = 0;
for(Component c: parent.getComponents()) {
if (c instanceof PaletteGroupHeader) {
PaletteGroupHeader groupHeader = (PaletteGroupHeader) c;
groupHeader.setLocation(0, height);
if (groupHeader.isVisible()) {
groupHeader.setSize(width, groupHeader.getPreferredSize().height);
height += groupHeader.getPreferredSize().height;
}
else {
groupHeader.setSize(0, 0);
}
if (groupHeader.isSelected() || !groupHeader.isVisible()) {
PaletteComponentList componentList = groupHeader.getComponentList();
componentList.setSize(width, componentList.getPreferredSize().height);
componentList.setLocation(0, height);
height += componentList.getHeight();
}
}
}
}
public Dimension minimumLayoutSize(Container parent) {
return new Dimension(0, 0);
}
public Dimension preferredLayoutSize(Container parent) {
int height = 0;
int width = parent.getWidth();
for(Component c: parent.getComponents()) {
if (c instanceof PaletteGroupHeader) {
PaletteGroupHeader groupHeader = (PaletteGroupHeader) c;
height += groupHeader.getHeight();
if (groupHeader.isSelected()) {
height += groupHeader.getComponentList().getPreferredHeight(width);
}
}
}
return new Dimension(10 /* not used - tracks viewports width*/, height);
}
public void removeLayoutComponent(Component comp) {
}
}
}
@@ -0,0 +1,195 @@
package com.intellij.ide.palette.impl;
import com.intellij.ide.dnd.DnDEvent;
import com.intellij.ide.dnd.DnDManager;
import com.intellij.ide.dnd.DnDTarget;
import com.intellij.ide.palette.PaletteGroup;
import com.intellij.ide.palette.PaletteItem;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.project.Project;
import com.intellij.ui.PopupHandler;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.CompoundBorder;
import java.awt.*;
import java.awt.event.*;
/**
* @author yole
*/
public class PaletteGroupHeader extends JCheckBox implements DataProvider {
private final PaletteWindow myPaletteWindow;
private PaletteComponentList myComponentList;
private final PaletteGroup myGroup;
public PaletteGroupHeader(PaletteWindow paletteWindow, PaletteGroup group) {
myPaletteWindow = paletteWindow;
myGroup = group;
if (group.getName() == null) {
setVisible(false);
}
else {
setText(group.getName());
}
setSelected(true);
addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (myComponentList != null) {
myComponentList.setVisible(isSelected());
}
}
});
addMouseListener(new PopupHandler() {
public void invokePopup(Component comp, int x, int y) {
myPaletteWindow.setLastFocusedGroup(PaletteGroupHeader.this);
showGroupPopupMenu(comp, x, y);
}
});
setIcon(UIUtil.getTreeCollapsedIcon());
setSelectedIcon(UIUtil.getTreeExpandedIcon());
setFont(getFont().deriveFont(Font.BOLD));
setFocusPainted(false);
setMargin(new Insets(0, 3, 0, 3));
if (getBorder() instanceof CompoundBorder) { // from BasicLookAndFeel
Dimension pref = getPreferredSize();
pref.height -= 3;
setPreferredSize(pref);
}
DnDManager.getInstance().registerTarget(new DnDTarget() {
public boolean update(DnDEvent aEvent) {
setBorderPainted(true);
aEvent.setDropPossible(aEvent.getAttachedObject() instanceof PaletteItem, null);
return true;
}
public void drop(DnDEvent aEvent) {
setBorderPainted(false);
if (aEvent.getAttachedObject() instanceof PaletteItem) {
myGroup.handleDrop(myPaletteWindow.getProject(), (PaletteItem) aEvent.getAttachedObject(), -1);
}
}
public void cleanUpOnLeave() {
setBorderPainted(false);
}
public void updateDraggedImage(Image image, Point dropPoint, Point imageOffset) {
}
}, this);
addFocusListener(new FocusAdapter() {
@Override public void focusGained(FocusEvent e) {
myPaletteWindow.setLastFocusedGroup(PaletteGroupHeader.this);
}
});
initActions();
}
public void showGroupPopupMenu(final Component comp, final int x, final int y) {
ActionGroup group = myGroup.getPopupActionGroup();
if (group != null) {
ActionPopupMenu popupMenu = ActionManager.getInstance().createActionPopupMenu(ActionPlaces.UNKNOWN, group);
popupMenu.getComponent().show(comp, x, y);
}
}
private void initActions() {
@NonNls InputMap inputMap = getInputMap(WHEN_FOCUSED);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "moveFocusDown");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "moveFocusUp");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "collapse");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "expand");
@NonNls ActionMap actionMap = getActionMap();
actionMap.put("moveFocusDown", new MoveFocusAction(true));
actionMap.put("moveFocusUp", new MoveFocusAction(false));
actionMap.put("collapse", new ExpandAction(false));
actionMap.put("expand", new ExpandAction(true));
}
@Override public Color getBackground() {
if (isFocusOwner()) {
return UIUtil.getListSelectionBackground();
}
return super.getBackground();
}
@Override public Color getForeground() {
if (isFocusOwner()) {
return UIUtil.getListSelectionForeground();
}
return super.getForeground();
}
public void setComponentList(final PaletteComponentList componentList) {
myComponentList = componentList;
}
public PaletteComponentList getComponentList() {
return myComponentList;
}
public PaletteGroup getGroup() {
return myGroup;
}
@Nullable public Object getData(String dataId) {
Object data = myPaletteWindow.getData(dataId);
if (data != null) return data;
Project project = (Project)myPaletteWindow.getData(DataConstants.PROJECT);
return myGroup.getData(project, dataId);
}
private class MoveFocusAction extends AbstractAction {
private final boolean moveDown;
public MoveFocusAction(boolean moveDown) {
this.moveDown = moveDown;
}
public void actionPerformed(ActionEvent e) {
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
Container container = kfm.getCurrentFocusCycleRoot();
FocusTraversalPolicy policy = container.getFocusTraversalPolicy();
if (null == policy) policy = kfm.getDefaultFocusTraversalPolicy();
Component next =
moveDown ? policy.getComponentAfter(container, PaletteGroupHeader.this) : policy.getComponentBefore(container, PaletteGroupHeader.this);
if (null != next && next instanceof PaletteComponentList) {
final PaletteComponentList list = (PaletteComponentList)next;
if (list.getModel().getSize() != 0) {
list.takeFocusFrom(PaletteGroupHeader.this, list == myComponentList ? 0 : -1);
return;
}
else {
next = moveDown ? policy.getComponentAfter(container, next) : policy.getComponentBefore(container, next);
}
}
if (null != next && next instanceof PaletteGroupHeader) {
next.requestFocus();
}
}
}
private class ExpandAction extends AbstractAction {
private final boolean expand;
public ExpandAction(boolean expand) {
this.expand = expand;
}
public void actionPerformed(ActionEvent e) {
if (expand == isSelected()) return;
setSelected(expand);
if (myComponentList != null) {
myComponentList.setVisible(isSelected());
}
}
}
}
@@ -0,0 +1,196 @@
/*
* Copyright (c) 2000-2006 JetBrains s.r.o. All Rights Reserved.
*/
package com.intellij.ide.palette.impl;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.palette.PaletteDragEventListener;
import com.intellij.ide.palette.PaletteItem;
import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
import com.intellij.openapi.fileEditor.FileEditorManagerListener;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowAnchor;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.update.MergingUpdateQueue;
import com.intellij.util.ui.update.Update;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.List;
/**
* @author yole
*/
public class PaletteManager implements ProjectComponent {
private final Project myProject;
private final FileEditorManager myFileEditorManager;
private PaletteWindow myPaletteWindow;
private ToolWindow myPaletteToolWindow;
private final MyFileEditorManagerListener myListener;
private final List<KeyListener> myKeyListeners = ContainerUtil.createEmptyCOWList();
private final List<PaletteDragEventListener> myDragEventListeners = ContainerUtil.createEmptyCOWList();
private final List<ListSelectionListener> mySelectionListeners = ContainerUtil.createEmptyCOWList();
public PaletteManager(Project project, FileEditorManager fileEditorManager) {
myProject = project;
myFileEditorManager = fileEditorManager;
myListener = new MyFileEditorManagerListener();
}
public void projectOpened() {
StartupManager.getInstance(myProject).registerPostStartupActivity(new Runnable() {
public void run() {
myPaletteWindow = new PaletteWindow(myProject);
myPaletteToolWindow = ToolWindowManager.getInstance(myProject).registerToolWindow(IdeBundle.message("toolwindow.palette"),
myPaletteWindow,
ToolWindowAnchor.RIGHT);
myPaletteToolWindow.setIcon(IconLoader.getIcon("/general/toolWindowPalette.png"));
myPaletteToolWindow.setAvailable(false, null);
myFileEditorManager.addFileEditorManagerListener(myListener);
}
});
}
public void projectClosed() {
if (myPaletteWindow != null) {
ToolWindowManager.getInstance(myProject).unregisterToolWindow(IdeBundle.message("toolwindow.palette"));
myPaletteWindow = null;
}
myFileEditorManager.removeFileEditorManagerListener(myListener);
}
@NotNull
public String getComponentName() {
return "PaletteManager";
}
public void initComponent() {
}
public void disposeComponent() {
}
public static PaletteManager getInstance(final Project project) {
return project.getComponent(PaletteManager.class);
}
public void clearActiveItem() {
if (myPaletteWindow != null) {
myPaletteWindow.clearActiveItem();
}
}
@Nullable
public PaletteItem getActiveItem() {
if (myPaletteWindow != null) {
return myPaletteWindow.getActiveItem();
}
return null;
}
@Nullable
public <T extends PaletteItem> T getActiveItem(Class<T> cls) {
PaletteItem item = getActiveItem();
if (item != null && item.getClass().isInstance(item)) {
//noinspection unchecked
return (T) item;
}
return null;
}
public void addKeyListener(KeyListener l) {
myKeyListeners.add(l);
}
public void removeKeyListener(KeyListener l) {
myKeyListeners.remove(l);
}
public void addDragEventListener(PaletteDragEventListener l) {
myDragEventListeners.add(l);
}
public void removeDragEventListener(PaletteDragEventListener l) {
myDragEventListeners.remove(l);
}
public void addSelectionListener(ListSelectionListener l) {
mySelectionListeners.add(l);
}
public void removeSelectionListener(ListSelectionListener l) {
mySelectionListeners.remove(l);
}
private MergingUpdateQueue myQueue = new MergingUpdateQueue("palette", 200, true, null);
private void processFileEditorChange(@Nullable final VirtualFile selectedFile) {
myQueue.cancelAllUpdates();
myQueue.queue(new Update("update") {
public void run() {
if (myPaletteWindow == null) return;
myPaletteWindow.refreshPaletteIfChanged(selectedFile);
if (myPaletteWindow.getActiveGroupCount() == 0) {
myPaletteToolWindow.setAvailable(false, null);
}
else {
myPaletteToolWindow.setAvailable(true, null);
myPaletteToolWindow.show(null);
}
}
});
}
void notifyKeyEvent(final KeyEvent e) {
for(KeyListener l: myKeyListeners) {
if (e.getID() == KeyEvent.KEY_PRESSED) {
l.keyPressed(e);
}
else if (e.getID() == KeyEvent.KEY_RELEASED) {
l.keyReleased(e);
}
else if (e.getID() == KeyEvent.KEY_TYPED) {
l.keyTyped(e);
}
}
}
void notifyDropActionChanged(int gestureModifiers) {
for(PaletteDragEventListener l: myDragEventListeners) {
l.dropActionChanged(gestureModifiers);
}
}
void notifySelectionChanged(final ListSelectionEvent event) {
for(ListSelectionListener l: mySelectionListeners) {
l.valueChanged(event);
}
}
private class MyFileEditorManagerListener implements FileEditorManagerListener {
public void fileOpened(FileEditorManager source, VirtualFile file) {
processFileEditorChange(file);
}
public void fileClosed(FileEditorManager source, VirtualFile file) {
processFileEditorChange(null);
}
public void selectionChanged(FileEditorManagerEvent event) {
processFileEditorChange(event.getNewFile());
}
}
}
@@ -0,0 +1,265 @@
package com.intellij.ide.palette.impl;
import com.intellij.ide.palette.PaletteGroup;
import com.intellij.ide.palette.PaletteItem;
import com.intellij.ide.palette.PaletteItemProvider;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.PopupHandler;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.*;
/**
* @author yole
*/
public class PaletteWindow extends JPanel implements DataProvider {
private final Project myProject;
private final ArrayList<PaletteGroupHeader> myGroupHeaders = new ArrayList<PaletteGroupHeader>();
private final PaletteItemProvider[] myProviders;
private final PaletteWindow.MyPropertyChangeListener myPropertyChangeListener = new MyPropertyChangeListener();
private final Set<PaletteGroup> myGroups = new HashSet<PaletteGroup>();
private final JTabbedPane myTabbedPane = new JTabbedPane();
private final JScrollPane myScrollPane = new JScrollPane();
private final MyListSelectionListener myListSelectionListener = new MyListSelectionListener();
private PaletteGroupHeader myLastFocusedGroup;
@NonNls private static final String ourHelpID = "guiDesigner.uiTour.palette";
public PaletteWindow(Project project) {
myProject = project;
myProviders = Extensions.getExtensions(PaletteItemProvider.EP_NAME, project);
for(PaletteItemProvider provider: myProviders) {
provider.addListener(myPropertyChangeListener);
}
setLayout(new GridLayout(1, 1));
myScrollPane.addMouseListener(new MyScrollPanePopupHandler());
KeyStroke escStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
new ClearActiveItemAction().registerCustomShortcutSet(new CustomShortcutSet(escStroke), myScrollPane);
refreshPalette();
}
public void refreshPalette() {
refreshPalette(null);
}
public void refreshPalette(@Nullable VirtualFile selectedFile) {
for(PaletteGroupHeader groupHeader: myGroupHeaders) {
groupHeader.getComponentList().removeListSelectionListener(myListSelectionListener);
}
String[] oldTabNames = collectTabNames(myGroups);
myTabbedPane.removeAll();
myGroupHeaders.clear();
myGroups.clear();
final ArrayList<PaletteGroup> currentGroups = collectCurrentGroups(selectedFile);
String[] tabNames = collectTabNames(currentGroups);
if (tabNames.length == 1) {
if (oldTabNames.length != 1) {
remove(myTabbedPane);
add(myScrollPane);
}
PaletteContentWindow contentWindow = new PaletteContentWindow();
myScrollPane.getViewport().setView(contentWindow);
for(PaletteGroup group: currentGroups) {
addGroupToControl(group, contentWindow);
}
final JComponent view = (JComponent)myScrollPane.getViewport().getView();
if (view != null) {
view.revalidate();
for(Component component: view.getComponents()) {
((JComponent) component).revalidate();
}
}
}
else {
if (oldTabNames.length <= 1) {
remove(myScrollPane);
add(myTabbedPane);
}
for(String tabName: tabNames) {
PaletteContentWindow contentWindow = new PaletteContentWindow();
JScrollPane scrollPane = new JScrollPane(contentWindow);
scrollPane.addMouseListener(new MyScrollPanePopupHandler());
myTabbedPane.add(tabName, scrollPane);
for(PaletteGroup group: currentGroups) {
if (group.getTabName().equals(tabName)) {
addGroupToControl(group, contentWindow);
}
}
}
myTabbedPane.revalidate();
}
}
private void addGroupToControl(PaletteGroup group, JComponent control) {
PaletteGroupHeader groupHeader = new PaletteGroupHeader(this, group);
myGroupHeaders.add(groupHeader);
myGroups.add(group);
control.add(groupHeader);
PaletteComponentList componentList = new PaletteComponentList(myProject, group);
control.add(componentList);
groupHeader.setComponentList(componentList);
componentList.addListSelectionListener(myListSelectionListener);
}
private static String[] collectTabNames(final Collection<PaletteGroup> groups) {
Set<String> result = new TreeSet<String>();
for(PaletteGroup group: groups) {
result.add(group.getTabName());
}
return ArrayUtil.toStringArray(result);
}
private ArrayList<PaletteGroup> collectCurrentGroups(@Nullable VirtualFile selectedFile) {
ArrayList<PaletteGroup> result = new ArrayList<PaletteGroup>();
if (selectedFile == null) {
VirtualFile[] editedFiles = FileEditorManager.getInstance(myProject).getSelectedFiles();
if (editedFiles.length > 0) {
selectedFile = editedFiles [0];
}
}
if (selectedFile != null) {
for(PaletteItemProvider provider: myProviders) {
PaletteGroup[] groups = provider.getActiveGroups(selectedFile);
Collections.addAll(result, groups);
}
}
return result;
}
public void refreshPaletteIfChanged(VirtualFile selectedFile) {
Set<PaletteGroup> currentGroups = new HashSet<PaletteGroup>(collectCurrentGroups(selectedFile));
if (!currentGroups.equals(myGroups)) {
refreshPalette(selectedFile);
}
}
public int getActiveGroupCount() {
return myGroups.size();
}
public void clearActiveItem() {
if (getActiveItem() == null) return;
for(PaletteGroupHeader group: myGroupHeaders) {
group.getComponentList().clearSelection();
}
ListSelectionEvent event = new ListSelectionEvent(this, -1, -1, false);
PaletteManager.getInstance(myProject).notifySelectionChanged(event);
}
@Nullable public PaletteItem getActiveItem() {
for(PaletteGroupHeader groupHeader: myGroupHeaders) {
if (groupHeader.isSelected() && groupHeader.getComponentList().getSelectedValue() != null) {
return (PaletteItem) groupHeader.getComponentList().getSelectedValue();
}
}
return null;
}
@Nullable public Object getData(String dataId) {
if (dataId.equals(DataConstants.HELP_ID)) {
return ourHelpID;
}
if (dataId.equals(DataConstants.PROJECT)) {
return myProject;
}
PaletteItem item = getActiveItem();
if (item != null) {
Object data = item.getData(myProject, dataId);
if (data != null) return data;
}
for(PaletteGroupHeader groupHeader: myGroupHeaders) {
if ((groupHeader.isSelected() && groupHeader.getComponentList().getSelectedValue() != null) || groupHeader == myLastFocusedGroup) {
return groupHeader.getGroup().getData(myProject, dataId);
}
}
final int tabCount = collectTabNames(myGroups).length;
if (tabCount > 0) {
JScrollPane activeScrollPane;
if (tabCount == 1) {
activeScrollPane = myScrollPane;
}
else {
activeScrollPane = (JScrollPane) myTabbedPane.getSelectedComponent();
}
PaletteContentWindow activeContentWindow = (PaletteContentWindow) activeScrollPane.getViewport().getView();
PaletteGroupHeader groupHeader = activeContentWindow.getLastGroupHeader();
if (groupHeader != null) {
return groupHeader.getGroup().getData(myProject, dataId);
}
}
return null;
}
public Project getProject() {
return myProject;
}
void setLastFocusedGroup(final PaletteGroupHeader focusedGroup) {
myLastFocusedGroup = focusedGroup;
for(PaletteGroupHeader group: myGroupHeaders) {
group.getComponentList().clearSelection();
}
}
private class MyListSelectionListener implements ListSelectionListener {
public void valueChanged(ListSelectionEvent e) {
PaletteComponentList sourceList = (PaletteComponentList) e.getSource();
for(int i=e.getFirstIndex(); i <= e.getLastIndex(); i++) {
if (sourceList.isSelectedIndex(i)) {
// selection is being added
for(PaletteGroupHeader group: myGroupHeaders) {
if (group.getComponentList() != sourceList) {
group.getComponentList().clearSelection();
}
}
break;
}
}
PaletteManager.getInstance(myProject).notifySelectionChanged(e);
}
}
private class MyPropertyChangeListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
refreshPalette();
}
}
private static class MyScrollPanePopupHandler extends PopupHandler {
public void invokePopup(Component comp, int x, int y) {
JScrollPane scrollPane = (JScrollPane) comp;
PaletteContentWindow contentWindow = (PaletteContentWindow) scrollPane.getViewport().getView();
if (contentWindow != null) {
PaletteGroupHeader groupHeader = contentWindow.getLastGroupHeader();
if (groupHeader != null) {
groupHeader.showGroupPopupMenu(comp, x, y);
}
}
}
}
private class ClearActiveItemAction extends AnAction {
public void actionPerformed(AnActionEvent e) {
clearActiveItem();
}
}
}