blob: cecf8126b114634dd03f8a0741a533bec4802091 [file] [log] [blame]
/*
* 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.designer.palette;
import com.intellij.designer.componentTree.TreeTransfer;
import com.intellij.designer.designSurface.DesignerEditorPanel;
import com.intellij.ide.dnd.DnDAction;
import com.intellij.ide.dnd.DnDDragStartBean;
import com.intellij.ide.dnd.DnDManager;
import com.intellij.ide.dnd.DnDSource;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.ColoredListCellRenderer;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.ui.components.JBList;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.plaf.basic.BasicListUI;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
/**
* @author Alexander Lobas
*/
public class PaletteItemsComponent extends JBList {
private static final SimpleTextAttributes DEPRECATED_ATTRIBUTES = new SimpleTextAttributes(SimpleTextAttributes.STYLE_STRIKEOUT, null);
private final PaletteGroup myGroup;
private final DesignerEditorPanel myDesigner;
private int myBeforeClickSelectedRow = -1;
private boolean myNeedClearSelection;
private Integer myTempWidth;
public PaletteItemsComponent(PaletteGroup group, @Nullable DesignerEditorPanel designer) {
myGroup = group;
myDesigner = designer;
setModel(new AbstractListModel() {
@Override
public int getSize() {
return myGroup.getItems().size();
}
@Override
public Object getElementAt(int index) {
return myGroup.getItems().get(index);
}
});
ColoredListCellRenderer renderer = new ColoredListCellRenderer() {
@Override
protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) {
clear();
PaletteItem item = (PaletteItem)value;
boolean enabled = item.isEnabled();
setEnabled(enabled);
if (enabled) {
setIcon(item.getIcon());
}
else {
setIcon(IconLoader.getDisabledIcon(item.getIcon()));
}
String title = item.getTitle();
String tooltip = item.getTooltip();
String version = myDesigner.getVersionLabel(item.getVersion());
String deprecatedIn = item.getDeprecatedIn();
boolean deprecated = myDesigner.isDeprecated(deprecatedIn);
append(title, deprecated ? DEPRECATED_ATTRIBUTES : SimpleTextAttributes.REGULAR_ATTRIBUTES);
if (!version.isEmpty()) {
version = "<sup><i>" + version + "</i></sup>";
}
if (tooltip != null) {
String deprecatedMessage = "";
if (deprecated) {
deprecatedMessage =
String.format("<b>This item is deprecated in version \"%1$s\".<br>", myDesigner.getVersionLabel(deprecatedIn));
String hint = item.getDeprecatedHint();
if (!StringUtil.isEmpty(hint)) {
deprecatedMessage += hint;
}
deprecatedMessage += "</b><br><br>";
}
tooltip = "<html><body><center><b>" +
StringUtil.escapeXml(title) +
"</b>" +
version +
"</center><p style='width: 300px'>" +
deprecatedMessage +
tooltip +
"</p></body></html>";
}
setToolTipText(tooltip);
}
};
renderer.getIpad().left = 2 * UIUtil.getTreeLeftChildIndent();
renderer.getIpad().right = UIUtil.getTreeRightChildIndent();
setCellRenderer(renderer);
setVisibleRowCount(0);
setLayoutOrientation(HORIZONTAL_WRAP);
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
addMouseListener(new MouseAdapter() {
@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();
}
}
});
setDragEnabled(true);
setTransferHandler(new TreeTransfer(PaletteItem.class));
DnDManager.getInstance().registerSource(new DnDSource() {
@Override
public boolean canStartDragging(DnDAction action, Point dragOrigin) {
int index = locationToIndex(dragOrigin);
if (index != -1 && myDesigner != null) {
PaletteItem paletteItem = myGroup.getItems().get(index);
myDesigner.activatePaletteItem(paletteItem);
}
return false;
}
@Override
public DnDDragStartBean startDragging(DnDAction action, Point dragOrigin) {
return null;
}
@Nullable
@Override
public Pair<Image, Point> createDraggedImage(DnDAction action, Point dragOrigin) {
return null;
}
@Override
public void dragDropEnd() {
}
@Override
public void dropActionChanged(int gestureModifiers) {
}
}, this);
initActions();
}
@Override
public void updateUI() {
setUI(new BasicListUI() {
MouseListener myListener;
@Override
protected void updateLayoutState() {
super.updateLayoutState();
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() {
addMouseListener(myListener = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
myBeforeClickSelectedRow = list.getSelectedIndex();
}
});
super.installListeners();
}
@Override
protected void uninstallListeners() {
if (myListener != null) {
removeMouseListener(myListener);
}
super.uninstallListeners();
}
});
invalidate();
}
public int getWidth() {
return (myTempWidth == null) ? super.getWidth() : myTempWidth.intValue();
}
public int getPreferredHeight(int width) {
myTempWidth = width;
try {
return getUI().getPreferredSize(this).height;
}
finally {
myTempWidth = null;
}
}
public void takeFocusFrom(int indexToSelect) {
if (indexToSelect == -1) {
indexToSelect = getModel().getSize() - 1;
}
else if (getModel().getSize() == 0) {
indexToSelect = -1;
}
requestFocus();
setSelectedIndex(indexToSelect);
if (indexToSelect >= 0) {
ensureIndexIsVisible(indexToSelect);
}
}
public void restoreSelection(PaletteItem paletteItem) {
if (paletteItem == null) {
clearSelection();
}
else {
int index = myGroup.getItems().indexOf(paletteItem);
if (index == -1) {
clearSelection();
}
else {
takeFocusFrom(index);
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////
//
//
//
//////////////////////////////////////////////////////////////////////////////////////////
private void initActions() {
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));
}
private class MoveFocusAction extends AbstractAction {
private final Action myDefaultAction;
private final boolean myFocusNext;
public MoveFocusAction(Action defaultAction, boolean focusNext) {
myDefaultAction = defaultAction;
myFocusNext = focusNext;
}
public void actionPerformed(ActionEvent e) {
int selIndexBefore = getSelectedIndex();
myDefaultAction.actionPerformed(e);
int selIndexCurrent = getSelectedIndex();
if (selIndexBefore != selIndexCurrent) {
return;
}
if (myFocusNext && selIndexCurrent == 0) {
return;
}
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
Container container = kfm.getCurrentFocusCycleRoot();
FocusTraversalPolicy policy = container.getFocusTraversalPolicy();
if (policy == null) {
policy = kfm.getDefaultFocusTraversalPolicy();
}
Component next = myFocusNext
? policy.getComponentAfter(container, PaletteItemsComponent.this)
: policy.getComponentBefore(container, PaletteItemsComponent.this);
if (next instanceof PaletteGroupComponent) {
clearSelection();
next.requestFocus();
((PaletteGroupComponent)next).scrollRectToVisible(next.getBounds());
}
}
}
private class ChangeColumnAction extends AbstractAction {
private final Action myDefaultAction;
private final boolean mySelectNext;
public ChangeColumnAction(Action defaultAction, boolean selectNext) {
myDefaultAction = defaultAction;
mySelectNext = selectNext;
}
public void actionPerformed(ActionEvent e) {
int selIndexBefore = getSelectedIndex();
myDefaultAction.actionPerformed(e);
int selIndexCurrent = getSelectedIndex();
if (mySelectNext && selIndexBefore < selIndexCurrent || !mySelectNext && selIndexBefore > selIndexCurrent) {
return;
}
if (mySelectNext) {
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));
}
}
}
}