blob: f2443b264b78099be00b60af5629f1a51bd9e6f2 [file] [log] [blame]
/*
* Copyright 2000-2013 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.uiDesigner;
import com.intellij.lang.properties.PropertiesReferenceManager;
import com.intellij.lang.properties.psi.PropertiesFile;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.*;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.uiDesigner.compiler.AsmCodeGenerator;
import com.intellij.uiDesigner.componentTree.ComponentTreeBuilder;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.designSurface.ComponentDropLocation;
import com.intellij.uiDesigner.designSurface.DraggedComponentList;
import com.intellij.uiDesigner.designSurface.GuiEditor;
import com.intellij.uiDesigner.designSurface.Painter;
import com.intellij.uiDesigner.editor.UIFormEditor;
import com.intellij.uiDesigner.lw.*;
import com.intellij.uiDesigner.palette.ComponentItem;
import com.intellij.uiDesigner.palette.Palette;
import com.intellij.uiDesigner.propertyInspector.DesignerToolWindowManager;
import com.intellij.uiDesigner.propertyInspector.properties.BindingProperty;
import com.intellij.uiDesigner.propertyInspector.properties.IntroComponentProperty;
import com.intellij.uiDesigner.radComponents.RadAbstractGridLayoutManager;
import com.intellij.uiDesigner.radComponents.RadComponent;
import com.intellij.uiDesigner.radComponents.RadContainer;
import com.intellij.uiDesigner.radComponents.RadRootContainer;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.List;
/**
* @author Anton Katilin
* @author Vladimir Kondratyev
*/
public final class FormEditingUtil {
private FormEditingUtil() {
}
public static boolean canDeleteSelection(final GuiEditor editor) {
final ArrayList<RadComponent> selection = getSelectedComponents(editor);
if (selection.isEmpty()) return false;
final RadRootContainer rootContainer = editor.getRootContainer();
if (rootContainer.getComponentCount() > 0 && selection.contains(rootContainer.getComponent(0))) {
return false;
}
return true;
}
/**
* <b>This method must be executed in command</b>
*
* @param editor the editor in which the selection is deleted.
*/
public static void deleteSelection(final GuiEditor editor) {
final List<RadComponent> selection = getSelectedComponents(editor);
deleteComponents(selection, true);
editor.refreshAndSave(true);
}
public static void deleteComponents(final Collection<? extends RadComponent> selection, boolean deleteEmptyCells) {
if (selection.size() == 0) {
return;
}
final RadRootContainer rootContainer = (RadRootContainer)getRoot(selection.iterator().next());
final Set<String> deletedComponentIds = new HashSet<String>();
for (final RadComponent component : selection) {
boolean wasSelected = component.isSelected();
final RadContainer parent = component.getParent();
boolean wasPackedHorz = false;
boolean wasPackedVert = false;
if (parent.getParent() != null && parent.getParent().isXY()) {
final Dimension minSize = parent.getMinimumSize();
wasPackedHorz = parent.getWidth() == minSize.width;
wasPackedVert = parent.getHeight() == minSize.height;
}
iterate(component, new ComponentVisitor() {
public boolean visit(final IComponent c) {
RadComponent rc = (RadComponent)c;
BindingProperty.checkRemoveUnusedField(rootContainer, rc.getBinding(), null);
deletedComponentIds.add(rc.getId());
return true;
}
});
GridConstraints delConstraints = parent.getLayoutManager().isGrid() ? component.getConstraints() : null;
int index = parent.indexOfComponent(component);
parent.removeComponent(component);
if (wasSelected) {
if (parent.getComponentCount() > index) {
parent.getComponent(index).setSelected(true);
}
else if (index > 0 && parent.getComponentCount() == index) {
parent.getComponent(index - 1).setSelected(true);
}
else {
parent.setSelected(true);
}
}
if (delConstraints != null && deleteEmptyCells) {
deleteEmptyGridCells(parent, delConstraints);
}
if (wasPackedHorz || wasPackedVert) {
final Dimension minSize = parent.getMinimumSize();
Dimension newSize = new Dimension(parent.getWidth(), parent.getHeight());
if (wasPackedHorz) {
newSize.width = minSize.width;
}
if (wasPackedVert) {
newSize.height = minSize.height;
}
parent.setSize(newSize);
}
}
iterate(rootContainer, new ComponentVisitor() {
public boolean visit(final IComponent component) {
RadComponent rc = (RadComponent)component;
for (IProperty p : component.getModifiedProperties()) {
if (p instanceof IntroComponentProperty) {
IntroComponentProperty icp = (IntroComponentProperty)p;
final String value = icp.getValue(rc);
if (deletedComponentIds.contains(value)) {
try {
icp.resetValue(rc);
}
catch (Exception e) {
// ignore
}
}
}
}
return true;
}
});
}
public static void deleteEmptyGridCells(final RadContainer parent, final GridConstraints delConstraints) {
deleteEmptyGridCells(parent, delConstraints, true);
deleteEmptyGridCells(parent, delConstraints, false);
}
private static void deleteEmptyGridCells(final RadContainer parent, final GridConstraints delConstraints, final boolean isRow) {
final RadAbstractGridLayoutManager layoutManager = parent.getGridLayoutManager();
for (int cell = delConstraints.getCell(isRow) + delConstraints.getSpan(isRow) - 1; cell >= delConstraints.getCell(isRow); cell--) {
if (cell < parent.getGridCellCount(isRow) && GridChangeUtil.canDeleteCell(parent, cell, isRow) == GridChangeUtil.CellStatus.Empty &&
!layoutManager.isGapCell(parent, isRow, cell)) {
layoutManager.deleteGridCells(parent, cell, isRow);
}
}
}
public static final int EMPTY_COMPONENT_SIZE = 5;
private static Component getDeepestEmptyComponentAt(JComponent parent, Point location) {
int size = parent.getComponentCount();
for (int i = 0; i < size; i++) {
Component child = parent.getComponent(i);
if (child.isShowing()) {
if (child.getWidth() < EMPTY_COMPONENT_SIZE || child.getHeight() < EMPTY_COMPONENT_SIZE) {
Point childLocation = child.getLocationOnScreen();
Rectangle bounds = new Rectangle();
bounds.x = childLocation.x;
bounds.y = childLocation.y;
bounds.width = child.getWidth();
bounds.height = child.getHeight();
bounds.grow(child.getWidth() < EMPTY_COMPONENT_SIZE ? EMPTY_COMPONENT_SIZE : 0,
child.getHeight() < EMPTY_COMPONENT_SIZE ? EMPTY_COMPONENT_SIZE : 0);
if (bounds.contains(location)) {
return child;
}
}
if (child instanceof JComponent) {
Component result = getDeepestEmptyComponentAt((JComponent)child, location);
if (result != null) {
return result;
}
}
}
}
return null;
}
/**
* @param x in editor pane coordinates
* @param y in editor pane coordinates
*/
public static RadComponent getRadComponentAt(final RadRootContainer rootContainer, final int x, final int y) {
Point location = new Point(x, y);
SwingUtilities.convertPointToScreen(location, rootContainer.getDelegee());
Component c = getDeepestEmptyComponentAt(rootContainer.getDelegee(), location);
if (c == null) {
c = SwingUtilities.getDeepestComponentAt(rootContainer.getDelegee(), x, y);
}
RadComponent result = null;
while (c != null) {
if (c instanceof JComponent) {
final RadComponent component = (RadComponent)((JComponent)c).getClientProperty(RadComponent.CLIENT_PROP_RAD_COMPONENT);
if (component != null) {
if (result == null) {
result = component;
}
else {
final Point p = SwingUtilities.convertPoint(rootContainer.getDelegee(), x, y, c);
if (Painter.getResizeMask(component, p.x, p.y) != 0) {
result = component;
}
}
}
}
c = c.getParent();
}
return result;
}
/**
* @return component which has dragger. There is only one component with the dargger
* at a time.
*/
@Nullable
public static RadComponent getDraggerHost(@NotNull final GuiEditor editor) {
final Ref<RadComponent> result = new Ref<RadComponent>();
iterate(
editor.getRootContainer(),
new ComponentVisitor<RadComponent>() {
public boolean visit(final RadComponent component) {
if (component.hasDragger()) {
result.set(component);
return false;
}
return true;
}
}
);
return result.get();
}
public static Cursor getMoveDropCursor() {
try {
return Cursor.getSystemCustomCursor("MoveDrop.32x32");
}
catch (Exception ex) {
return Cursor.getDefaultCursor();
}
}
public static Cursor getMoveNoDropCursor() {
try {
return Cursor.getSystemCustomCursor("MoveNoDrop.32x32");
}
catch (Exception ex) {
return Cursor.getDefaultCursor();
}
}
public static Cursor getCopyDropCursor() {
try {
return Cursor.getSystemCustomCursor("CopyDrop.32x32");
}
catch (Exception ex) {
return Cursor.getDefaultCursor();
}
}
/**
* @return currently selected components. Method returns the minimal amount of
* selected component which contains all selected components. It means that if the
* selected container contains some selected children then only this container
* will be added to the returned array.
*/
@NotNull
public static ArrayList<RadComponent> getSelectedComponents(@NotNull final GuiEditor editor) {
final ArrayList<RadComponent> result = new ArrayList<RadComponent>();
calcSelectedComponentsImpl(result, editor.getRootContainer());
return result;
}
private static void calcSelectedComponentsImpl(final ArrayList<RadComponent> result, final RadContainer container) {
if (container.isSelected()) {
if (container.getParent() != null) { // ignore RadRootContainer
result.add(container);
return;
}
}
for (int i = 0; i < container.getComponentCount(); i++) {
final RadComponent component = container.getComponent(i);
if (component instanceof RadContainer) {
calcSelectedComponentsImpl(result, (RadContainer)component);
}
else {
if (component.isSelected()) {
result.add(component);
}
}
}
}
/**
* @return all selected component inside the <code>editor</code>
*/
@NotNull
public static ArrayList<RadComponent> getAllSelectedComponents(@NotNull final GuiEditor editor) {
final ArrayList<RadComponent> result = new ArrayList<RadComponent>();
iterate(
editor.getRootContainer(),
new ComponentVisitor<RadComponent>() {
public boolean visit(final RadComponent component) {
if (component.isSelected()) {
result.add(component);
}
return true;
}
}
);
return result;
}
public static String getExceptionMessage(Throwable ex) {
if (ex instanceof RuntimeException) {
final Throwable cause = ex.getCause();
if (cause != null && cause != ex) {
return getExceptionMessage(cause);
}
}
else if (ex instanceof InvocationTargetException) {
final Throwable target = ((InvocationTargetException)ex).getTargetException();
if (target != null && target != ex) {
return getExceptionMessage(target);
}
}
String message = ex.getMessage();
if (ex instanceof ClassNotFoundException) {
message =
message != null ? UIDesignerBundle.message("error.class.not.found.N", message) : UIDesignerBundle.message("error.class.not.found");
}
else if (ex instanceof NoClassDefFoundError) {
message = message != null
? UIDesignerBundle.message("error.required.class.not.found.N", message)
: UIDesignerBundle.message("error.required.class.not.found");
}
return message;
}
public static IComponent findComponentWithBinding(IComponent component, final String binding) {
return findComponentWithBinding(component, binding, null);
}
public static IComponent findComponentWithBinding(IComponent component,
final String binding,
@Nullable final IComponent exceptComponent) {
// Check that binding is unique
final Ref<IComponent> boundComponent = new Ref<IComponent>();
iterate(
component,
new ComponentVisitor() {
public boolean visit(final IComponent component) {
if (component != exceptComponent && binding.equals(component.getBinding())) {
boundComponent.set(component);
return false;
}
return true;
}
}
);
return boundComponent.get();
}
@Nullable
public static RadContainer getRadContainerAt(final RadRootContainer rootContainer, final int x, final int y,
int epsilon) {
RadComponent component = getRadComponentAt(rootContainer, x, y);
if (isNullOrRoot(component) && epsilon > 0) {
// try to find component near specified location
component = getRadComponentAt(rootContainer, x - epsilon, y - epsilon);
if (isNullOrRoot(component)) component = getRadComponentAt(rootContainer, x - epsilon, y + epsilon);
if (isNullOrRoot(component)) component = getRadComponentAt(rootContainer, x + epsilon, y - epsilon);
if (isNullOrRoot(component)) component = getRadComponentAt(rootContainer, x + epsilon, y + epsilon);
}
if (component != null) {
return component instanceof RadContainer
? (RadContainer)component
: component.getParent();
}
return null;
}
private static boolean isNullOrRoot(final RadComponent component) {
return component == null || component instanceof RadRootContainer;
}
public static GridConstraints getDefaultConstraints(final RadComponent component) {
final Palette palette = Palette.getInstance(component.getProject());
final ComponentItem item = palette.getItem(component.getComponentClassName());
if (item != null) {
return item.getDefaultConstraints();
}
return new GridConstraints();
}
public static IRootContainer getRoot(IComponent component) {
while (component != null) {
if (component.getParentContainer() instanceof IRootContainer) {
return (IRootContainer)component.getParentContainer();
}
component = component.getParentContainer();
}
return null;
}
/**
* Iterates component and its children (if any)
*/
public static void iterate(final IComponent component, final ComponentVisitor visitor) {
iterateImpl(component, visitor);
}
private static boolean iterateImpl(final IComponent component, final ComponentVisitor visitor) {
final boolean shouldContinue;
try {
shouldContinue = visitor.visit(component);
}
catch (ProcessCanceledException ex) {
return false;
}
if (!shouldContinue) {
return false;
}
if (!(component instanceof IContainer)) {
return true;
}
final IContainer container = (IContainer)component;
for (int i = 0; i < container.getComponentCount(); i++) {
final IComponent c = container.getComponent(i);
if (!iterateImpl(c, visitor)) {
return false;
}
}
return true;
}
public static Set<String> collectUsedBundleNames(final IRootContainer rootContainer) {
final Set<String> bundleNames = new HashSet<String>();
iterateStringDescriptors(rootContainer, new StringDescriptorVisitor<IComponent>() {
public boolean visit(final IComponent component, final StringDescriptor descriptor) {
if (descriptor.getBundleName() != null && !bundleNames.contains(descriptor.getBundleName())) {
bundleNames.add(descriptor.getBundleName());
}
return true;
}
});
return bundleNames;
}
public static Locale[] collectUsedLocales(final Module module, final IRootContainer rootContainer) {
final Set<Locale> locales = new HashSet<Locale>();
final PropertiesReferenceManager propManager = PropertiesReferenceManager.getInstance(module.getProject());
for (String bundleName : collectUsedBundleNames(rootContainer)) {
List<PropertiesFile> propFiles = propManager.findPropertiesFiles(module, bundleName.replace('/', '.'));
for (PropertiesFile propFile : propFiles) {
locales.add(propFile.getLocale());
}
}
return locales.toArray(new Locale[locales.size()]);
}
public static void deleteRowOrColumn(final GuiEditor editor, final RadContainer container,
final int[] cellsToDelete, final boolean isRow) {
Arrays.sort(cellsToDelete);
final int[] cells = ArrayUtil.reverseArray(cellsToDelete);
if (!editor.ensureEditable()) {
return;
}
Runnable runnable = new Runnable() {
public void run() {
if (!GridChangeUtil.canDeleteCells(container, cells, isRow)) {
Set<RadComponent> componentsInColumn = new HashSet<RadComponent>();
for (RadComponent component : container.getComponents()) {
GridConstraints c = component.getConstraints();
for (int cell : cells) {
if (c.contains(isRow, cell)) {
componentsInColumn.add(component);
break;
}
}
}
if (componentsInColumn.size() > 0) {
String message = isRow
? UIDesignerBundle.message("delete.row.nonempty", componentsInColumn.size(), cells.length)
: UIDesignerBundle.message("delete.column.nonempty", componentsInColumn.size(), cells.length);
final int rc = Messages.showYesNoDialog(editor, message,
isRow ? UIDesignerBundle.message("delete.row.title")
: UIDesignerBundle.message("delete.column.title"), Messages.getQuestionIcon());
if (rc != Messages.YES) {
return;
}
deleteComponents(componentsInColumn, false);
}
}
for (int cell : cells) {
container.getGridLayoutManager().deleteGridCells(container, cell, isRow);
}
editor.refreshAndSave(true);
}
};
CommandProcessor.getInstance().executeCommand(editor.getProject(), runnable,
isRow ? UIDesignerBundle.message("command.delete.row")
: UIDesignerBundle.message("command.delete.column"), null);
}
/**
* @param rootContainer
* @return id
*/
public static String generateId(final RadRootContainer rootContainer) {
while (true) {
final String id = Integer.toString((int)(Math.random() * 1024 * 1024), 16);
if (findComponent(rootContainer, id) == null) {
return id;
}
}
}
/**
* @return {@link com.intellij.uiDesigner.designSurface.GuiEditor} from the context. Can be <code>null</code>.
*/
@Nullable
public static GuiEditor getEditorFromContext(@NotNull final DataContext context) {
final FileEditor editor = PlatformDataKeys.FILE_EDITOR.getData(context);
if (editor instanceof UIFormEditor) {
return ((UIFormEditor)editor).getEditor();
}
else {
return GuiEditor.DATA_KEY.getData(context);
}
}
@Nullable
public static GuiEditor getActiveEditor(final DataContext context) {
Project project = CommonDataKeys.PROJECT.getData(context);
if (project == null) {
return null;
}
final DesignerToolWindowManager toolWindowManager = DesignerToolWindowManager.getInstance(project);
if (toolWindowManager == null) {
return null;
}
return toolWindowManager.getActiveFormEditor();
}
/**
* @param componentToAssignBinding
* @param binding
* @param component topmost container where to find duplicate binding. In most cases
* it should be {@link com.intellij.uiDesigner.designSurface.GuiEditor#getRootContainer()}
*/
public static boolean isBindingUnique(
final IComponent componentToAssignBinding,
final String binding,
final IComponent component
) {
return findComponentWithBinding(component, binding, componentToAssignBinding) == null;
}
@Nullable
public static String buildResourceName(final PsiFile file) {
PsiDirectory directory = file.getContainingDirectory();
if (directory != null) {
PsiPackage pkg = JavaDirectoryService.getInstance().getPackage(directory);
String packageName = pkg != null ? pkg.getQualifiedName() : "";
if (packageName.length() == 0) {
return file.getName();
}
return packageName.replace('.', '/') + '/' + file.getName();
}
return null;
}
@Nullable
public static RadContainer getSelectionParent(final List<RadComponent> selection) {
RadContainer parent = null;
for (RadComponent c : selection) {
if (parent == null) {
parent = c.getParent();
}
else if (parent != c.getParent()) {
parent = null;
break;
}
}
return parent;
}
public static Rectangle getSelectionBounds(List<RadComponent> selection) {
int minRow = Integer.MAX_VALUE;
int minCol = Integer.MAX_VALUE;
int maxRow = 0;
int maxCol = 0;
for (RadComponent c : selection) {
minRow = Math.min(minRow, c.getConstraints().getRow());
minCol = Math.min(minCol, c.getConstraints().getColumn());
maxRow = Math.max(maxRow, c.getConstraints().getRow() + c.getConstraints().getRowSpan());
maxCol = Math.max(maxCol, c.getConstraints().getColumn() + c.getConstraints().getColSpan());
}
return new Rectangle(minCol, minRow, maxCol - minCol, maxRow - minRow);
}
public static boolean isComponentSwitchedInView(@NotNull RadComponent component) {
while (component.getParent() != null) {
if (!component.getParent().getLayoutManager().isSwitchedToChild(component.getParent(), component)) {
return false;
}
component = component.getParent();
}
return true;
}
/**
* Selects the component and ensures that the tabbed panes containing the component are
* switched to the correct tab.
*
* @param editor
* @param component the component to select. @return true if the component is enclosed in at least one tabbed pane, false otherwise.
*/
public static boolean selectComponent(final GuiEditor editor, @NotNull final RadComponent component) {
boolean hasTab = false;
RadComponent parent = component;
while (parent.getParent() != null) {
if (parent.getParent().getLayoutManager().switchContainerToChild(parent.getParent(), parent)) {
hasTab = true;
}
parent = parent.getParent();
}
component.setSelected(true);
editor.setSelectionLead(component);
return hasTab;
}
public static void selectSingleComponent(final GuiEditor editor, final RadComponent component) {
final RadContainer root = (RadContainer)getRoot(component);
if (root == null) return;
ComponentTreeBuilder builder = DesignerToolWindowManager.getInstance(editor).getComponentTreeBuilder();
// this can return null if the click to select the control also requested to grab the focus -
// the component tree will be instantiated after the event has been processed completely
if (builder != null) {
builder.beginUpdateSelection();
}
try {
clearSelection(root);
selectComponent(editor, component);
editor.setSelectionAnchor(component);
editor.scrollComponentInView(component);
}
finally {
if (builder != null) {
builder.endUpdateSelection();
}
}
}
public static void selectComponents(final GuiEditor editor, List<RadComponent> components) {
if (components.size() > 0) {
RadComponent component = components.get(0);
ComponentTreeBuilder builder = DesignerToolWindowManager.getInstance(editor).getComponentTreeBuilder();
if (builder == null) {
// race condition when handling event?
return;
}
builder.beginUpdateSelection();
try {
clearSelection((RadContainer)getRoot(component));
for (RadComponent aComponent : components) {
selectComponent(editor, aComponent);
}
}
finally {
builder.endUpdateSelection();
}
}
}
public static boolean isDropOnChild(final DraggedComponentList draggedComponentList,
final ComponentDropLocation location) {
if (location.getContainer() == null) {
return false;
}
for (RadComponent component : draggedComponentList.getComponents()) {
if (isChild(location.getContainer(), component)) {
return true;
}
}
return false;
}
private static boolean isChild(RadContainer maybeChild, RadComponent maybeParent) {
while (maybeChild != null) {
if (maybeParent == maybeChild) {
return true;
}
maybeChild = maybeChild.getParent();
}
return false;
}
public static PsiMethod findCreateComponentsMethod(final PsiClass aClass) {
PsiElementFactory factory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory();
PsiMethod method;
try {
method = factory.createMethodFromText("void " + AsmCodeGenerator.CREATE_COMPONENTS_METHOD_NAME + "() {}",
aClass);
}
catch (IncorrectOperationException e) {
throw new RuntimeException(e);
}
return aClass.findMethodBySignature(method, true);
}
public static Object getNextSaveUndoGroupId(final Project project) {
final GuiEditor guiEditor = DesignerToolWindowManager.getInstance(project).getActiveFormEditor();
return guiEditor == null ? null : guiEditor.getNextSaveGroupId();
}
public static int adjustForGap(final RadContainer container, final int cellIndex, final boolean isRow, final int delta) {
if (container.getGridLayoutManager().isGapCell(container, isRow, cellIndex)) {
return cellIndex + delta;
}
return cellIndex;
}
public static int prevRow(final RadContainer container, final int row) {
return adjustForGap(container, row - 1, true, -1);
}
public static int nextRow(final RadContainer container, final int row) {
return adjustForGap(container, row + 1, true, 1);
}
public static int prevCol(final RadContainer container, final int col) {
return adjustForGap(container, col - 1, false, -1);
}
public static int nextCol(final RadContainer container, final int col) {
return adjustForGap(container, col + 1, false, 1);
}
@Nullable
public static IButtonGroup findGroupForComponent(final IRootContainer radRootContainer, @NotNull final IComponent component) {
for (IButtonGroup group : radRootContainer.getButtonGroups()) {
for (String id : group.getComponentIds()) {
if (component.getId().equals(id)) {
return group;
}
}
}
return null;
}
public static void remapToActionTargets(final List<RadComponent> selection) {
for (int i = 0; i < selection.size(); i++) {
final RadComponent c = selection.get(i);
if (c.getParent() != null) {
selection.set(i, c.getParent().getActionTargetComponent(c));
}
}
}
public static void showPopupUnderComponent(final JBPopup popup, final RadComponent selectedComponent) {
// popup.showUnderneathOf() doesn't work on invisible components
Rectangle rc = selectedComponent.getBounds();
Point pnt = new Point(rc.x, rc.y + rc.height);
popup.show(new RelativePoint(selectedComponent.getDelegee().getParent(), pnt));
}
public interface StringDescriptorVisitor<T extends IComponent> {
boolean visit(T component, StringDescriptor descriptor);
}
public static void iterateStringDescriptors(final IComponent component,
final StringDescriptorVisitor<IComponent> visitor) {
iterate(component, new ComponentVisitor<IComponent>() {
public boolean visit(final IComponent component) {
for (IProperty prop : component.getModifiedProperties()) {
Object value = prop.getPropertyValue(component);
if (value instanceof StringDescriptor) {
if (!visitor.visit(component, (StringDescriptor)value)) {
return false;
}
}
}
if (component.getParentContainer() instanceof ITabbedPane) {
StringDescriptor tabTitle =
((ITabbedPane)component.getParentContainer()).getTabProperty(component, ITabbedPane.TAB_TITLE_PROPERTY);
if (tabTitle != null && !visitor.visit(component, tabTitle)) {
return false;
}
StringDescriptor tabToolTip =
((ITabbedPane)component.getParentContainer()).getTabProperty(component, ITabbedPane.TAB_TOOLTIP_PROPERTY);
if (tabToolTip != null && !visitor.visit(component, tabToolTip)) {
return false;
}
}
if (component instanceof IContainer) {
final StringDescriptor borderTitle = ((IContainer)component).getBorderTitle();
if (borderTitle != null && !visitor.visit(component, borderTitle)) {
return false;
}
}
return true;
}
});
}
public static void clearSelection(@NotNull final RadContainer container) {
container.setSelected(false);
for (int i = 0; i < container.getComponentCount(); i++) {
final RadComponent c = container.getComponent(i);
if (c instanceof RadContainer) {
clearSelection((RadContainer)c);
}
else {
c.setSelected(false);
}
}
}
/**
* Finds component with the specified <code>id</code> starting from the
* <code>container</code>. The method goes recursively through the hierarchy
* of components. Note, that if <code>container</code> itself has <code>id</code>
* then the method immediately retuns it.
*
* @return the found component.
*/
@Nullable
public static IComponent findComponent(@NotNull final IComponent component, @NotNull final String id) {
if (id.equals(component.getId())) {
return component;
}
if (!(component instanceof IContainer)) {
return null;
}
final IContainer uiContainer = (IContainer)component;
for (int i = 0; i < uiContainer.getComponentCount(); i++) {
final IComponent found = findComponent(uiContainer.getComponent(i), id);
if (found != null) {
return found;
}
}
return null;
}
@Nullable
public static PsiClass findClassToBind(@NotNull final Module module, @NotNull final String classToBindName) {
return JavaPsiFacade.getInstance(module.getProject())
.findClass(classToBindName.replace('$', '.'), module.getModuleWithDependenciesScope());
}
public interface ComponentVisitor<Type extends IComponent> {
/**
* @return true if iteration should continue
*/
boolean visit(Type component);
}
}