blob: 0c7b57ce999c6757a370687741916fd4a810c0dd [file] [log] [blame]
/*
* Copyright 2000-2009 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.ide.palette.impl;
import com.intellij.designer.LightToolWindowContent;
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.application.ApplicationManager;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.PopupHandler;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.components.JBTabbedPane;
import com.intellij.uiDesigner.designSurface.GuiEditor;
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.dnd.DragSource;
import java.awt.dnd.DragSourceAdapter;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.*;
/**
* @author yole
*/
public class PaletteWindow extends JPanel implements LightToolWindowContent, DataProvider {
private final Project myProject;
private final ArrayList<PaletteGroupHeader> myGroupHeaders = new ArrayList<PaletteGroupHeader>();
private final PaletteItemProvider[] myProviders;
private final MyPropertyChangeListener myPropertyChangeListener = new MyPropertyChangeListener();
private final Set<PaletteGroup> myGroups = new HashSet<PaletteGroup>();
private final JTabbedPane myTabbedPane = new JBTabbedPane();
private final JScrollPane myScrollPane = ScrollPaneFactory.createScrollPane();
private final MyListSelectionListener myListSelectionListener = new MyListSelectionListener();
private PaletteGroupHeader myLastFocusedGroup;
@NonNls private static final String ourHelpID = "guiDesigner.uiTour.palette";
private final DragSourceListener myDragSourceListener = new DragSourceAdapter() {
@Override
public void dragDropEnd(DragSourceDropEvent event) {
Component component = event.getDragSourceContext().getComponent();
if (!event.getDropSuccess() &&
component instanceof PaletteComponentList &&
getRootPane() == ((JComponent)component).getRootPane()) {
clearActiveItem();
}
}
};
private GuiEditor myDesigner;
public PaletteWindow(Project project) {
myProject = project;
myProviders = Extensions.getExtensions(PaletteItemProvider.EP_NAME, project);
setLayout(new GridLayout(1, 1));
myScrollPane.addMouseListener(new MyScrollPanePopupHandler());
myScrollPane.setBorder(null);
KeyStroke escStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
new ClearActiveItemAction().registerCustomShortcutSet(new CustomShortcutSet(escStroke), myScrollPane);
if (!ApplicationManager.getApplication().isHeadlessEnvironment()) {
DragSource.getDefaultDragSource().addDragSourceListener(myDragSourceListener);
}
}
public void dispose() {
removePaletteProviderListener();
if (!ApplicationManager.getApplication().isHeadlessEnvironment()) {
DragSource.getDefaultDragSource().removeDragSourceListener(myDragSourceListener);
}
}
private void addPaletteProviderListener() {
for (PaletteItemProvider provider : myProviders) {
provider.addListener(myPropertyChangeListener);
}
}
private void removePaletteProviderListener() {
for (PaletteItemProvider provider : myProviders) {
provider.removeListener(myPropertyChangeListener);
}
}
public void refreshPaletteIfChanged(@Nullable GuiEditor designer) {
removePaletteProviderListener();
myDesigner = designer;
if (designer != null) {
addPaletteProviderListener();
}
VirtualFile file = designer == null ? null : designer.getFile();
Set<PaletteGroup> currentGroups = new HashSet<PaletteGroup>(collectCurrentGroups(file));
if (!currentGroups.equals(myGroups)) {
refreshPalette(file);
}
}
private 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 = ScrollPaneFactory.createScrollPane(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, this, 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) {
for (PaletteItemProvider provider : myProviders) {
PaletteGroup[] groups = provider.getActiveGroups(selectedFile);
Collections.addAll(result, groups);
}
}
return result;
}
public void clearActiveItem() {
if (getActiveItem() == null) return;
for (PaletteGroupHeader group : myGroupHeaders) {
group.getComponentList().clearSelection();
}
ListSelectionEvent event = new ListSelectionEvent(this, -1, -1, false);
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 <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;
}
@Nullable
public Object getData(String dataId) {
if (PlatformDataKeys.HELP_ID.is(dataId)) {
return ourHelpID;
}
if (CommonDataKeys.PROJECT.is(dataId)) {
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();
}
}
void notifyKeyEvent(final KeyEvent e) {
if (myDesigner != null) {
if (e.getID() == KeyEvent.KEY_PRESSED) {
myDesigner.paletteKeyPressed(e);
}
else if (e.getID() == KeyEvent.KEY_RELEASED) {
myDesigner.paletteKeyReleased(e);
}
}
}
void notifyDropActionChanged(int gestureModifiers) {
if (myDesigner != null) {
myDesigner.paletteDropActionChanged(gestureModifiers);
}
}
void notifySelectionChanged(final ListSelectionEvent event) {
if (myDesigner != null) {
myDesigner.paletteValueChanged(event);
}
}
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;
}
}
notifySelectionChanged(e);
}
}
private class MyPropertyChangeListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
refreshPalette(myDesigner.getFile());
}
}
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();
}
}
}