update copyright
[fedora-idea.git] / java / idea-ui / src / com / intellij / ide / palette / impl / PaletteComponentList.java
blob29ea375e0444258bb7d79caa54cf4c7459ef4552
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.ide.palette.impl;
18 import com.intellij.ide.dnd.*;
19 import com.intellij.ide.palette.PaletteGroup;
20 import com.intellij.ide.palette.PaletteItem;
21 import com.intellij.openapi.actionSystem.ActionGroup;
22 import com.intellij.openapi.actionSystem.ActionManager;
23 import com.intellij.openapi.actionSystem.ActionPlaces;
24 import com.intellij.openapi.actionSystem.ActionPopupMenu;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.util.Pair;
27 import com.intellij.ui.ColoredListCellRenderer;
28 import com.intellij.ui.PopupHandler;
29 import com.intellij.util.ui.UIUtil;
30 import org.jetbrains.annotations.NonNls;
31 import org.jetbrains.annotations.Nullable;
33 import javax.swing.*;
34 import javax.swing.plaf.basic.BasicListUI;
35 import java.awt.*;
36 import java.awt.event.*;
38 /**
39 * @author yole
41 public class PaletteComponentList extends JList {
42 private final Project myProject;
43 private final PaletteGroup myGroup;
44 private int myHoverIndex = -1;
45 private int myBeforeClickSelectedRow = -1;
46 private int myDropTargetIndex = -1;
47 private boolean myNeedClearSelection = false;
49 public PaletteComponentList(Project project, PaletteGroup group) {
50 myProject = project;
51 myGroup = group;
52 setModel(new AbstractListModel() {
53 public int getSize() {
54 return myGroup.getItems().length;
57 public Object getElementAt(int index) {
58 return myGroup.getItems() [index];
60 });
62 addMouseListener(new MouseAdapter() {
63 @Override public void mouseEntered(MouseEvent e) {
64 setHoverIndex(locationToIndex(e.getPoint()));
67 @Override public void mouseExited(MouseEvent e) {
68 setHoverIndex(-1);
71 @Override public void mousePressed(MouseEvent e) {
72 myNeedClearSelection = (SwingUtilities.isLeftMouseButton(e) &&
73 myBeforeClickSelectedRow >= 0 &&
74 locationToIndex(e.getPoint()) == myBeforeClickSelectedRow &&
75 !UIUtil.isControlKeyDown(e) && !e.isShiftDown());
78 @Override public void mouseReleased(MouseEvent e) {
79 if (SwingUtilities.isLeftMouseButton(e) &&
80 myBeforeClickSelectedRow >= 0 &&
81 locationToIndex(e.getPoint()) == myBeforeClickSelectedRow &&
82 !UIUtil.isControlKeyDown(e) && !e.isShiftDown() && myNeedClearSelection) {
83 clearSelection();
86 });
88 addMouseListener(new PopupHandler() {
89 public void invokePopup(final Component comp, final int x, final int y) {
90 requestFocusInWindow();
91 SwingUtilities.invokeLater(new Runnable() {
92 public void run() {
93 int index = locationToIndex(new Point(x, y));
94 PaletteItem[] items = myGroup.getItems();
95 if (index >= 0 && index < items.length) {
96 if (getSelectedIndex() != index) {
97 addSelectionInterval(index, index);
99 PaletteItem item = items [index];
100 ActionGroup group = item.getPopupActionGroup();
101 if (group != null) {
102 ActionPopupMenu popupMenu = ActionManager.getInstance().createActionPopupMenu(ActionPlaces.UNKNOWN, group);
103 popupMenu.getComponent().show(comp, x, y);
111 addMouseMotionListener(new MouseMotionAdapter() {
112 public void mouseMoved(MouseEvent e) {
113 setHoverIndex(locationToIndex(e.getPoint()));
117 addKeyListener(new KeyListener() {
118 public void keyPressed(KeyEvent e) {
119 PaletteManager.getInstance(myProject).notifyKeyEvent(e);
122 public void keyReleased(KeyEvent e) {
123 PaletteManager.getInstance(myProject).notifyKeyEvent(e);
126 public void keyTyped(KeyEvent e) {
127 PaletteManager.getInstance(myProject).notifyKeyEvent(e);
131 setCellRenderer(new ComponentCellRenderer());
133 setVisibleRowCount(0);
134 setLayoutOrientation(HORIZONTAL_WRAP);
135 setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
137 final DnDManager dndManager = DnDManager.getInstance();
138 dndManager.registerSource(new MyDnDSource(), this);
139 dndManager.registerTarget(new MyDnDTarget(), this);
141 initActions();
144 private void setHoverIndex(final int index) {
145 if (index != myHoverIndex) {
146 if (myHoverIndex >= 0) repaint(getCellBounds(myHoverIndex, myHoverIndex));
147 myHoverIndex = index;
148 if (myHoverIndex >= 0) repaint(getCellBounds(myHoverIndex, myHoverIndex));
152 private void setDropTargetIndex(final int index) {
153 if (index != myDropTargetIndex) {
154 myDropTargetIndex = index;
155 repaint();
159 @Override public void updateUI() {
160 setUI(new ComponentListUI());
161 invalidate();
164 private void initActions() {
165 @NonNls ActionMap map = getActionMap();
166 map.put( "selectPreviousRow", new MoveFocusAction( map.get( "selectPreviousRow" ), false ) );
167 map.put( "selectNextRow", new MoveFocusAction( map.get( "selectNextRow" ), true ) );
168 map.put( "selectPreviousColumn", new MoveFocusAction( new ChangeColumnAction( map.get( "selectPreviousColumn" ), false ), false ) );
169 map.put( "selectNextColumn", new MoveFocusAction( new ChangeColumnAction( map.get( "selectNextColumn" ), true ), true ) );
172 Integer myTempWidth;
174 public int getWidth () {
175 return (myTempWidth == null) ? super.getWidth () : myTempWidth.intValue ();
178 public int getPreferredHeight(final int width) {
179 myTempWidth = width;
180 try {
181 return getUI().getPreferredSize(this).height;
183 finally {
184 myTempWidth = null;
188 public void takeFocusFrom(PaletteGroupHeader paletteGroup, int indexToSelect) {
189 if (indexToSelect == -1) {
190 //this is not 'our' CategoryButton so we'll assume it's the one below this category list
191 indexToSelect = getModel().getSize() - 1;
193 else if (getModel().getSize() == 0) {
194 indexToSelect = -1;
196 requestFocus();
197 setSelectedIndex(indexToSelect);
198 if (indexToSelect >= 0) {
199 ensureIndexIsVisible(indexToSelect);
203 @Override protected void paintComponent(Graphics g) {
204 super.paintComponent(g);
205 if (myDropTargetIndex >= 0) {
206 int dropLineY;
207 Rectangle rc;
208 if (myDropTargetIndex == myGroup.getItems().length) {
209 rc = getCellBounds(myDropTargetIndex-1, myDropTargetIndex-1);
210 dropLineY = (int)rc.getMaxY()-1;
212 else {
213 rc = getCellBounds(myDropTargetIndex, myDropTargetIndex);
214 dropLineY = rc.y;
216 Graphics2D g2d = (Graphics2D) g;
217 g2d.setColor(Color.BLUE);
218 g2d.setStroke(new BasicStroke(2.0f));
219 g2d.drawLine(rc.x, dropLineY, rc.x+rc.width, dropLineY);
220 g2d.drawLine(rc.x, dropLineY-2, rc.x, dropLineY+2);
221 g2d.drawLine(rc.x+rc.width, dropLineY-2, rc.x+rc.width, dropLineY+2);
225 class ComponentListUI extends BasicListUI {
226 private ComponentListListener myListener;
228 @Override protected void updateLayoutState() {
229 super.updateLayoutState();
231 if (list.getLayoutOrientation() == JList.HORIZONTAL_WRAP) {
232 Insets insets = list.getInsets();
233 int listWidth = list.getWidth() - (insets.left + insets.right);
234 if (listWidth >= cellWidth) {
235 int columnCount = listWidth / cellWidth;
236 cellWidth = (columnCount == 0) ? 1 : listWidth / columnCount;
241 @Override protected void installListeners() {
242 myListener = new ComponentListListener();
243 addMouseListener(myListener);
244 super.installListeners();
247 @Override
248 protected void uninstallListeners() {
249 if (myListener != null) {
250 removeMouseListener(myListener);
252 super.uninstallListeners();
255 private class ComponentListListener extends MouseAdapter {
256 @Override public void mousePressed(MouseEvent e) {
257 myBeforeClickSelectedRow = list.getSelectedIndex();
262 private static class ComponentCellRenderer extends ColoredListCellRenderer {
263 protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) {
264 PaletteItem paletteItem = (PaletteItem) value;
265 clear();
266 paletteItem.customizeCellRenderer(this, selected, hasFocus);
270 private class MoveFocusAction extends AbstractAction {
271 private final Action defaultAction;
272 private final boolean focusNext;
274 public MoveFocusAction(Action defaultAction, boolean focusNext) {
275 this.defaultAction = defaultAction;
276 this.focusNext = focusNext;
279 public void actionPerformed(ActionEvent e) {
280 int selIndexBefore = getSelectedIndex();
281 defaultAction.actionPerformed(e);
282 int selIndexCurrent = getSelectedIndex();
283 if (selIndexBefore != selIndexCurrent) return;
285 if (focusNext && 0 == selIndexCurrent) return;
287 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
288 Container container = kfm.getCurrentFocusCycleRoot();
289 FocusTraversalPolicy policy = container.getFocusTraversalPolicy();
290 if (null == policy) policy = kfm.getDefaultFocusTraversalPolicy();
291 Component next = focusNext
292 ? policy.getComponentAfter(container, PaletteComponentList.this)
293 : policy.getComponentBefore(container, PaletteComponentList.this);
294 if (null != next && next instanceof PaletteGroupHeader) {
295 clearSelection();
296 next.requestFocus();
297 ((PaletteGroupHeader)next).scrollRectToVisible(next.getBounds());
302 private class ChangeColumnAction extends AbstractAction {
303 private final Action defaultAction;
304 private final boolean selectNext;
306 public ChangeColumnAction(Action defaultAction, boolean selectNext) {
307 this.defaultAction = defaultAction;
308 this.selectNext = selectNext;
311 public void actionPerformed(ActionEvent e) {
312 int selIndexBefore = getSelectedIndex();
313 defaultAction.actionPerformed(e);
314 int selIndexCurrent = getSelectedIndex();
315 if ((selectNext && selIndexBefore < selIndexCurrent) || (!selectNext && selIndexBefore > selIndexCurrent)) return;
317 if (selectNext) {
318 if (selIndexCurrent == selIndexBefore + 1) selIndexCurrent++;
319 if (selIndexCurrent < getModel().getSize() - 1) {
320 setSelectedIndex(selIndexCurrent + 1);
321 scrollRectToVisible(getCellBounds(selIndexCurrent + 1, selIndexCurrent + 1));
324 else {
325 if (selIndexCurrent > 0) {
326 setSelectedIndex(selIndexCurrent - 1);
327 scrollRectToVisible(getCellBounds(selIndexCurrent - 1, selIndexCurrent - 1));
333 private class MyDnDTarget implements DnDTarget {
335 public boolean update(DnDEvent aEvent) {
336 setHoverIndex(-1);
337 if (aEvent.getAttachedObject() instanceof PaletteItem) {
338 setDropTargetIndex(locationToTargetIndex(aEvent.getPoint()));
339 aEvent.setDropPossible(true, null);
341 else {
342 setDropTargetIndex(-1);
343 aEvent.setDropPossible(false, null);
345 return false;
348 public void drop(DnDEvent aEvent) {
349 setDropTargetIndex(-1);
350 if (aEvent.getAttachedObject() instanceof PaletteItem) {
351 int index = locationToTargetIndex(aEvent.getPoint());
352 if (index >= 0) {
353 myGroup.handleDrop(myProject, (PaletteItem) aEvent.getAttachedObject(), index);
358 public void cleanUpOnLeave() {
359 setDropTargetIndex(-1);
362 private int locationToTargetIndex(Point location) {
363 int row = locationToIndex(location);
364 if (row < 0) {
365 return -1;
367 Rectangle rc = getCellBounds(row, row);
368 return location.y < rc.getCenterY() ? row : row + 1;
371 public void updateDraggedImage(Image image, Point dropPoint, Point imageOffset) {
375 private class MyDnDSource implements DnDSource {
376 public boolean canStartDragging(DnDAction action, Point dragOrigin) {
377 int index = locationToIndex(dragOrigin);
378 return index >= 0 && myGroup.getItems() [index].startDragging() != null;
381 public DnDDragStartBean startDragging(DnDAction action, Point dragOrigin) {
382 int index = locationToIndex(dragOrigin);
383 if (index < 0) return null;
384 return myGroup.getItems() [index].startDragging();
387 @Nullable
388 public Pair<Image, Point> createDraggedImage(DnDAction action, Point dragOrigin) {
389 return null;
392 public void dragDropEnd() {
395 public void dropActionChanged(final int gestureModifiers) {
396 PaletteManager.getInstance(myProject).notifyDropActionChanged(gestureModifiers);