update copyright
[fedora-idea.git] / plugins / ui-designer / src / com / intellij / uiDesigner / FormEditingUtil.java
blobb0692f86dff98e37eceddf136d0dfca72dbd98f9
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.uiDesigner;
18 import com.intellij.lang.properties.PropertiesReferenceManager;
19 import com.intellij.lang.properties.psi.PropertiesFile;
20 import com.intellij.openapi.actionSystem.DataContext;
21 import com.intellij.openapi.actionSystem.PlatformDataKeys;
22 import com.intellij.openapi.command.CommandProcessor;
23 import com.intellij.openapi.fileEditor.FileEditor;
24 import com.intellij.openapi.module.Module;
25 import com.intellij.openapi.progress.ProcessCanceledException;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.openapi.ui.DialogWrapper;
28 import com.intellij.openapi.ui.Messages;
29 import com.intellij.openapi.ui.popup.JBPopup;
30 import com.intellij.openapi.util.Ref;
31 import com.intellij.psi.*;
32 import com.intellij.ui.awt.RelativePoint;
33 import com.intellij.uiDesigner.compiler.AsmCodeGenerator;
34 import com.intellij.uiDesigner.componentTree.ComponentTreeBuilder;
35 import com.intellij.uiDesigner.core.GridConstraints;
36 import com.intellij.uiDesigner.designSurface.ComponentDropLocation;
37 import com.intellij.uiDesigner.designSurface.DraggedComponentList;
38 import com.intellij.uiDesigner.designSurface.GuiEditor;
39 import com.intellij.uiDesigner.designSurface.Painter;
40 import com.intellij.uiDesigner.editor.UIFormEditor;
41 import com.intellij.uiDesigner.lw.*;
42 import com.intellij.uiDesigner.palette.ComponentItem;
43 import com.intellij.uiDesigner.palette.Palette;
44 import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
45 import com.intellij.uiDesigner.propertyInspector.properties.BindingProperty;
46 import com.intellij.uiDesigner.propertyInspector.properties.IntroComponentProperty;
47 import com.intellij.uiDesigner.radComponents.RadAbstractGridLayoutManager;
48 import com.intellij.uiDesigner.radComponents.RadComponent;
49 import com.intellij.uiDesigner.radComponents.RadContainer;
50 import com.intellij.uiDesigner.radComponents.RadRootContainer;
51 import com.intellij.util.ArrayUtil;
52 import com.intellij.util.IncorrectOperationException;
53 import com.intellij.util.containers.HashSet;
54 import org.jetbrains.annotations.NotNull;
55 import org.jetbrains.annotations.Nullable;
57 import javax.swing.*;
58 import java.awt.*;
59 import java.lang.reflect.InvocationTargetException;
60 import java.util.*;
61 import java.util.List;
63 /**
64 * @author Anton Katilin
65 * @author Vladimir Kondratyev
67 public final class FormEditingUtil {
68 private FormEditingUtil() {
71 public static boolean canDeleteSelection(final GuiEditor editor){
72 final ArrayList<RadComponent> selection = getSelectedComponents(editor);
73 if (selection.isEmpty()) return false;
74 final RadRootContainer rootContainer = editor.getRootContainer();
75 if (rootContainer.getComponentCount() > 0 && selection.contains(rootContainer.getComponent(0))) {
76 return false;
78 return true;
81 /**
82 * <b>This method must be executed in command</b>
84 * @param editor the editor in which the selection is deleted.
86 public static void deleteSelection(final GuiEditor editor){
87 final List<RadComponent> selection = getSelectedComponents(editor);
88 deleteComponents(selection, true);
89 editor.refreshAndSave(true);
92 public static void deleteComponents(final Collection<? extends RadComponent> selection, boolean deleteEmptyCells) {
93 if (selection.size() == 0) {
94 return;
96 final RadRootContainer rootContainer = (RadRootContainer) getRoot(selection.iterator().next());
97 final Set<String> deletedComponentIds = new HashSet<String>();
98 for (final RadComponent component : selection) {
99 boolean wasSelected = component.isSelected();
100 final RadContainer parent = component.getParent();
102 boolean wasPackedHorz = false;
103 boolean wasPackedVert = false;
104 if (parent.getParent() != null && parent.getParent().isXY()) {
105 final Dimension minSize = parent.getMinimumSize();
106 wasPackedHorz = parent.getWidth() == minSize.width;
107 wasPackedVert = parent.getHeight() == minSize.height;
110 FormEditingUtil.iterate(component, new ComponentVisitor() {
111 public boolean visit(final IComponent c) {
112 RadComponent rc = (RadComponent) c;
113 BindingProperty.checkRemoveUnusedField(rootContainer, rc.getBinding(), null);
114 deletedComponentIds.add(rc.getId());
115 return true;
120 GridConstraints delConstraints = parent.getLayoutManager().isGrid() ? component.getConstraints() : null;
122 int index = parent.indexOfComponent(component);
123 parent.removeComponent(component);
124 if (wasSelected) {
125 if (parent.getComponentCount() > index) {
126 parent.getComponent(index).setSelected(true);
128 else if (index > 0 && parent.getComponentCount() == index) {
129 parent.getComponent(index-1).setSelected(true);
131 else {
132 parent.setSelected(true);
135 if (delConstraints != null && deleteEmptyCells) {
136 deleteEmptyGridCells(parent, delConstraints);
139 if (wasPackedHorz || wasPackedVert) {
140 final Dimension minSize = parent.getMinimumSize();
141 Dimension newSize = new Dimension(parent.getWidth(), parent.getHeight());
142 if (wasPackedHorz) {
143 newSize.width = minSize.width;
145 if (wasPackedVert) {
146 newSize.height = minSize.height;
148 parent.setSize(newSize);
152 FormEditingUtil.iterate(rootContainer, new ComponentVisitor() {
153 public boolean visit(final IComponent component) {
154 RadComponent rc = (RadComponent) component;
155 for(IProperty p: component.getModifiedProperties()) {
156 if (p instanceof IntroComponentProperty) {
157 IntroComponentProperty icp = (IntroComponentProperty) p;
158 final String value = icp.getValue(rc);
159 if (deletedComponentIds.contains(value)) {
160 try {
161 icp.resetValue(rc);
163 catch (Exception e) {
164 // ignore
169 return true;
174 public static void deleteEmptyGridCells(final RadContainer parent, final GridConstraints delConstraints) {
175 deleteEmptyGridCells(parent, delConstraints, true);
176 deleteEmptyGridCells(parent, delConstraints, false);
179 private static void deleteEmptyGridCells(final RadContainer parent, final GridConstraints delConstraints, final boolean isRow) {
180 final RadAbstractGridLayoutManager layoutManager = parent.getGridLayoutManager();
181 for(int cell=delConstraints.getCell(isRow) + delConstraints.getSpan(isRow)-1; cell>= delConstraints.getCell(isRow); cell--) {
182 if (cell < parent.getGridCellCount(isRow) && GridChangeUtil.canDeleteCell(parent, cell, isRow) == GridChangeUtil.CellStatus.Empty &&
183 !layoutManager.isGapCell(parent, isRow, cell)) {
184 layoutManager.deleteGridCells(parent, cell, isRow);
190 * @param x in editor pane coordinates
191 * @param y in editor pane coordinates
193 public static RadComponent getRadComponentAt(final RadRootContainer rootContainer, final int x, final int y){
194 Component c = SwingUtilities.getDeepestComponentAt(rootContainer.getDelegee(), x, y);
196 RadComponent result = null;
198 while (c != null) {
199 if (c instanceof JComponent){
200 final RadComponent component = (RadComponent)((JComponent)c).getClientProperty(RadComponent.CLIENT_PROP_RAD_COMPONENT);
201 if (component != null) {
203 if (result == null) {
204 result = component;
206 else {
207 final Point p = SwingUtilities.convertPoint(rootContainer.getDelegee(), x, y, c);
208 if (Painter.getResizeMask(component, p.x, p.y) != 0) {
209 result = component;
214 c = c.getParent();
217 return result;
221 * @return component which has dragger. There is only one component with the dargger
222 * at a time.
224 @Nullable
225 public static RadComponent getDraggerHost(@NotNull final GuiEditor editor){
226 final Ref<RadComponent> result = new Ref<RadComponent>();
227 iterate(
228 editor.getRootContainer(),
229 new ComponentVisitor<RadComponent>() {
230 public boolean visit(final RadComponent component) {
231 if(component.hasDragger()){
232 result.set(component);
233 return false;
235 return true;
240 return result.get();
244 public static Cursor getMoveDropCursor() {
245 try {
246 return Cursor.getSystemCustomCursor("MoveDrop.32x32");
248 catch (Exception ex) {
249 return Cursor.getDefaultCursor();
253 public static Cursor getMoveNoDropCursor() {
254 try {
255 return Cursor.getSystemCustomCursor("MoveNoDrop.32x32");
257 catch (Exception ex) {
258 return Cursor.getDefaultCursor();
262 public static Cursor getCopyDropCursor() {
263 try {
264 return Cursor.getSystemCustomCursor("CopyDrop.32x32");
266 catch (Exception ex) {
267 return Cursor.getDefaultCursor();
272 * @return currently selected components. Method returns the minimal amount of
273 * selected component which contains all selected components. It means that if the
274 * selected container contains some selected children then only this container
275 * will be added to the returned array.
277 @NotNull
278 public static ArrayList<RadComponent> getSelectedComponents(@NotNull final GuiEditor editor){
279 final ArrayList<RadComponent> result = new ArrayList<RadComponent>();
280 calcSelectedComponentsImpl(result, editor.getRootContainer());
281 return result;
284 private static void calcSelectedComponentsImpl(final ArrayList<RadComponent> result, final RadContainer container){
285 if (container.isSelected()) {
286 if (container.getParent() != null) { // ignore RadRootContainer
287 result.add(container);
288 return;
292 for (int i = 0; i < container.getComponentCount(); i++) {
293 final RadComponent component = container.getComponent(i);
294 if (component instanceof RadContainer) {
295 calcSelectedComponentsImpl(result, (RadContainer)component);
297 else {
298 if (component.isSelected()) {
299 result.add(component);
306 * @return all selected component inside the <code>editor</code>
308 @NotNull
309 public static ArrayList<RadComponent> getAllSelectedComponents(@NotNull final GuiEditor editor){
310 final ArrayList<RadComponent> result = new ArrayList<RadComponent>();
311 iterate(
312 editor.getRootContainer(),
313 new ComponentVisitor<RadComponent>(){
314 public boolean visit(final RadComponent component) {
315 if(component.isSelected()){
316 result.add(component);
318 return true;
322 return result;
325 public static String getExceptionMessage(Throwable ex) {
326 if (ex instanceof RuntimeException) {
327 final Throwable cause = ex.getCause();
328 if (cause != null && cause != ex) {
329 return getExceptionMessage(cause);
332 else
333 if (ex instanceof InvocationTargetException) {
334 final Throwable target = ((InvocationTargetException)ex).getTargetException();
335 if (target != null && target != ex) {
336 return getExceptionMessage(target);
339 String message = ex.getMessage();
340 if (ex instanceof ClassNotFoundException) {
341 message = message != null? UIDesignerBundle.message("error.class.not.found.N", message) : UIDesignerBundle.message("error.class.not.found");
343 else if (ex instanceof NoClassDefFoundError) {
344 message = message != null? UIDesignerBundle.message("error.required.class.not.found.N", message) : UIDesignerBundle.message("error.required.class.not.found");
346 return message;
349 public static IComponent findComponentWithBinding(IComponent component, final String binding) {
350 return findComponentWithBinding(component, binding, null);
353 public static IComponent findComponentWithBinding(IComponent component, final String binding, @Nullable final IComponent exceptComponent) {
354 // Check that binding is unique
355 final Ref<IComponent> boundComponent = new Ref<IComponent>();
356 iterate(
357 component,
358 new ComponentVisitor() {
359 public boolean visit(final IComponent component) {
360 if(component != exceptComponent && binding.equals(component.getBinding())) {
361 boundComponent.set(component);
362 return false;
364 return true;
369 return boundComponent.get();
372 @Nullable
373 public static RadContainer getRadContainerAt(final RadRootContainer rootContainer, final int x, final int y,
374 int epsilon) {
375 RadComponent component = getRadComponentAt(rootContainer, x, y);
376 if (isNullOrRoot(component) && epsilon > 0) {
377 // try to find component near specified location
378 component = getRadComponentAt(rootContainer, x-epsilon, y-epsilon);
379 if (isNullOrRoot(component)) component = getRadComponentAt(rootContainer, x-epsilon, y+epsilon);
380 if (isNullOrRoot(component)) component = getRadComponentAt(rootContainer, x+epsilon, y-epsilon);
381 if (isNullOrRoot(component)) component = getRadComponentAt(rootContainer, x+epsilon, y+epsilon);
384 if (component != null) {
385 return component instanceof RadContainer
386 ? (RadContainer)component
387 : component.getParent();
389 return null;
392 private static boolean isNullOrRoot(final RadComponent component) {
393 return component == null || component instanceof RadRootContainer;
396 public static GridConstraints getDefaultConstraints(final RadComponent component) {
397 final Palette palette = Palette.getInstance(component.getModule().getProject());
398 final ComponentItem item = palette.getItem(component.getComponentClassName());
399 if (item != null) {
400 return item.getDefaultConstraints();
402 return new GridConstraints();
405 public static IRootContainer getRoot(IComponent component) {
406 while(component != null) {
407 if (component.getParentContainer() instanceof IRootContainer) {
408 return (IRootContainer) component.getParentContainer();
410 component = component.getParentContainer();
412 return null;
416 * Iterates component and its children (if any)
418 public static void iterate(final IComponent component, final ComponentVisitor visitor){
419 iterateImpl(component, visitor);
422 private static boolean iterateImpl(final IComponent component, final ComponentVisitor visitor) {
423 final boolean shouldContinue;
424 try {
425 shouldContinue = visitor.visit(component);
427 catch (ProcessCanceledException ex) {
428 return false;
430 if (!shouldContinue) {
431 return false;
434 if (!(component instanceof IContainer)) {
435 return true;
438 final IContainer container = (IContainer)component;
440 for (int i = 0; i < container.getComponentCount(); i++) {
441 final IComponent c = container.getComponent(i);
442 if (!iterateImpl(c, visitor)) {
443 return false;
447 return true;
450 public static Set<String> collectUsedBundleNames(final IRootContainer rootContainer) {
451 final Set<String> bundleNames = new HashSet<String>();
452 iterateStringDescriptors(rootContainer, new StringDescriptorVisitor<IComponent>() {
453 public boolean visit(final IComponent component, final StringDescriptor descriptor) {
454 if (descriptor.getBundleName() != null && !bundleNames.contains(descriptor.getBundleName())) {
455 bundleNames.add(descriptor.getBundleName());
457 return true;
460 return bundleNames;
463 public static Locale[] collectUsedLocales(final Module module, final IRootContainer rootContainer) {
464 final Set<Locale> locales = new HashSet<Locale>();
465 final PropertiesReferenceManager propManager = PropertiesReferenceManager.getInstance(module.getProject());
466 for(String bundleName: collectUsedBundleNames(rootContainer)) {
467 List<PropertiesFile> propFiles = propManager.findPropertiesFiles(module, bundleName.replace('/', '.'));
468 for(PropertiesFile propFile: propFiles) {
469 locales.add(propFile.getLocale());
472 return locales.toArray(new Locale[locales.size()]);
475 public static void deleteRowOrColumn(final GuiEditor editor, final RadContainer container,
476 final int[] cellsToDelete, final boolean isRow) {
477 Arrays.sort(cellsToDelete);
478 final int[] cells = ArrayUtil.reverseArray(cellsToDelete);
479 if (!editor.ensureEditable()) {
480 return;
483 Runnable runnable = new Runnable() {
484 public void run() {
485 if (!GridChangeUtil.canDeleteCells(container, cells, isRow)) {
486 Set<RadComponent> componentsInColumn = new HashSet<RadComponent>();
487 for(RadComponent component: container.getComponents()) {
488 GridConstraints c = component.getConstraints();
489 for(int cell: cells) {
490 if (c.contains(isRow, cell)) {
491 componentsInColumn.add(component);
492 break;
497 if (componentsInColumn.size() > 0) {
498 String message = isRow
499 ? UIDesignerBundle.message("delete.row.nonempty", componentsInColumn.size(), cells.length)
500 : UIDesignerBundle.message("delete.column.nonempty", componentsInColumn.size(), cells.length);
502 final int rc = Messages.showYesNoDialog(editor, message,
503 isRow ? UIDesignerBundle.message("delete.row.title")
504 : UIDesignerBundle.message("delete.column.title"), Messages.getQuestionIcon());
505 if (rc != DialogWrapper.OK_EXIT_CODE) {
506 return;
509 deleteComponents(componentsInColumn, false);
513 for(int cell: cells) {
514 container.getGridLayoutManager().deleteGridCells(container, cell, isRow);
516 editor.refreshAndSave(true);
519 CommandProcessor.getInstance().executeCommand(editor.getProject(), runnable,
520 isRow ? UIDesignerBundle.message("command.delete.row")
521 : UIDesignerBundle.message("command.delete.column"), null);
525 * @return id
526 * @param rootContainer
528 public static String generateId(final RadRootContainer rootContainer) {
529 while (true) {
530 final String id = Integer.toString((int)(Math.random() * 1024 * 1024), 16);
531 if (findComponent(rootContainer, id) == null) {
532 return id;
538 * @return {@link com.intellij.uiDesigner.designSurface.GuiEditor} from the context. Can be <code>null</code>.
540 @Nullable
541 public static GuiEditor getEditorFromContext(@NotNull final DataContext context){
542 final FileEditor editor = PlatformDataKeys.FILE_EDITOR.getData(context);
543 if(editor instanceof UIFormEditor){
544 return ((UIFormEditor)editor).getEditor();
546 else {
547 return (GuiEditor) context.getData(GuiEditor.class.getName());
551 @Nullable public static GuiEditor getActiveEditor(final DataContext context){
552 Project project = PlatformDataKeys.PROJECT.getData(context);
553 if (project == null) {
554 return null;
556 final UIDesignerToolWindowManager toolWindowManager = UIDesignerToolWindowManager.getInstance(project);
557 if (toolWindowManager == null) {
558 return null;
560 return toolWindowManager.getActiveFormEditor();
565 * @param componentToAssignBinding
566 * @param binding
567 * @param component topmost container where to find duplicate binding. In most cases
568 * it should be {@link com.intellij.uiDesigner.designSurface.GuiEditor#getRootContainer()}
570 public static boolean isBindingUnique(
571 final IComponent componentToAssignBinding,
572 final String binding,
573 final IComponent component
575 return findComponentWithBinding(component, binding, componentToAssignBinding) == null;
578 @Nullable
579 public static String buildResourceName(final PsiFile file) {
580 PsiDirectory directory = file.getContainingDirectory();
581 if (directory != null) {
582 PsiPackage pkg = JavaDirectoryService.getInstance().getPackage(directory);
583 String packageName = pkg != null ? pkg.getQualifiedName() : "";
584 return packageName.replace('.', '/') + '/' + file.getName();
586 return null;
589 @Nullable
590 public static RadContainer getSelectionParent(final List<RadComponent> selection) {
591 RadContainer parent = null;
592 for(RadComponent c: selection) {
593 if (parent == null) {
594 parent = c.getParent();
596 else if (parent != c.getParent()) {
597 parent = null;
598 break;
601 return parent;
604 public static Rectangle getSelectionBounds(List<RadComponent> selection) {
605 int minRow = Integer.MAX_VALUE;
606 int minCol = Integer.MAX_VALUE;
607 int maxRow = 0;
608 int maxCol = 0;
610 for(RadComponent c: selection) {
611 minRow = Math.min(minRow, c.getConstraints().getRow());
612 minCol = Math.min(minCol, c.getConstraints().getColumn());
613 maxRow = Math.max(maxRow, c.getConstraints().getRow() + c.getConstraints().getRowSpan());
614 maxCol = Math.max(maxCol, c.getConstraints().getColumn() + c.getConstraints().getColSpan());
616 return new Rectangle(minCol, minRow, maxCol-minCol, maxRow-minRow);
619 public static boolean isComponentSwitchedInView(@NotNull RadComponent component) {
620 while(component.getParent() != null) {
621 if (!component.getParent().getLayoutManager().isSwitchedToChild(component.getParent(), component)) {
622 return false;
624 component = component.getParent();
626 return true;
630 * Selects the component and ensures that the tabbed panes containing the component are
631 * switched to the correct tab.
633 * @param editor
634 * @param component the component to select. @return true if the component is enclosed in at least one tabbed pane, false otherwise.
636 public static boolean selectComponent(final GuiEditor editor, @NotNull final RadComponent component) {
637 boolean hasTab = false;
638 RadComponent parent = component;
639 while(parent.getParent() != null) {
640 if (parent.getParent().getLayoutManager().switchContainerToChild(parent.getParent(), parent)) {
641 hasTab = true;
643 parent = parent.getParent();
645 component.setSelected(true);
646 editor.setSelectionLead(component);
647 return hasTab;
650 public static void selectSingleComponent(final GuiEditor editor, final RadComponent component) {
651 final RadContainer root = (RadContainer)getRoot(component);
652 if (root == null) return;
654 ComponentTreeBuilder builder = UIDesignerToolWindowManager.getInstance(component.getProject()).getComponentTreeBuilder();
655 // this can return null if the click to select the control also requested to grab the focus -
656 // the component tree will be instantiated after the event has been processed completely
657 if (builder != null) {
658 builder.beginUpdateSelection();
660 try {
661 clearSelection(root);
662 selectComponent(editor, component);
663 editor.setSelectionAnchor(component);
664 editor.scrollComponentInView(component);
666 finally {
667 if (builder != null) {
668 builder.endUpdateSelection();
673 public static void selectComponents(final GuiEditor editor, List<RadComponent> components) {
674 if (components.size() > 0) {
675 RadComponent component = components.get(0);
676 ComponentTreeBuilder builder = UIDesignerToolWindowManager.getInstance(component.getProject()).getComponentTreeBuilder();
677 if (builder == null) {
678 // race condition when handling event?
679 return;
681 builder.beginUpdateSelection();
682 try {
683 clearSelection((RadContainer) getRoot(component));
684 for(RadComponent aComponent: components) {
685 selectComponent(editor, aComponent);
688 finally {
689 builder.endUpdateSelection();
694 public static boolean isDropOnChild(final DraggedComponentList draggedComponentList,
695 final ComponentDropLocation location) {
696 if (location.getContainer() == null) {
697 return false;
700 for(RadComponent component: draggedComponentList.getComponents()) {
701 if (isChild(location.getContainer(), component)) {
702 return true;
705 return false;
708 private static boolean isChild(RadContainer maybeChild, RadComponent maybeParent) {
709 while(maybeChild != null) {
710 if (maybeParent == maybeChild) {
711 return true;
713 maybeChild = maybeChild.getParent();
715 return false;
718 public static PsiMethod findCreateComponentsMethod(final PsiClass aClass) {
719 PsiElementFactory factory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory();
720 PsiMethod method;
721 try {
722 method = factory.createMethodFromText("void " + AsmCodeGenerator.CREATE_COMPONENTS_METHOD_NAME + "() {}",
723 aClass);
725 catch (IncorrectOperationException e) {
726 throw new RuntimeException(e);
728 return aClass.findMethodBySignature(method, true);
731 public static Object getNextSaveUndoGroupId(final Project project) {
732 final GuiEditor guiEditor = UIDesignerToolWindowManager.getInstance(project).getActiveFormEditor();
733 return guiEditor == null ? null : guiEditor.getNextSaveGroupId();
736 public static int adjustForGap(final RadContainer container, final int cellIndex, final boolean isRow, final int delta) {
737 if (container.getGridLayoutManager().isGapCell(container, isRow, cellIndex)) {
738 return cellIndex+delta;
740 return cellIndex;
743 public static int prevRow(final RadContainer container, final int row) {
744 return adjustForGap(container, row-1, true, -1);
747 public static int nextRow(final RadContainer container, final int row) {
748 return adjustForGap(container, row+1, true, 1);
751 public static int prevCol(final RadContainer container, final int col) {
752 return adjustForGap(container, col-1, false, -1);
755 public static int nextCol(final RadContainer container, final int col) {
756 return adjustForGap(container, col+1, false, 1);
759 @Nullable public static IButtonGroup findGroupForComponent(final IRootContainer radRootContainer, @NotNull final IComponent component) {
760 for(IButtonGroup group: radRootContainer.getButtonGroups()) {
761 for(String id: group.getComponentIds()) {
762 if (component.getId().equals(id)) {
763 return group;
767 return null;
770 public static void remapToActionTargets(final List<RadComponent> selection) {
771 for(int i=0; i<selection.size(); i++) {
772 final RadComponent c = selection.get(i);
773 if (c.getParent() != null) {
774 selection.set(i, c.getParent().getActionTargetComponent(c));
779 public static void showPopupUnderComponent(final JBPopup popup, final RadComponent selectedComponent) {
780 // popup.showUnderneathOf() doesn't work on invisible components
781 Rectangle rc = selectedComponent.getBounds();
782 Point pnt = new Point(rc.x, rc.y + rc.height);
783 popup.show(new RelativePoint(selectedComponent.getDelegee().getParent(), pnt));
786 public static interface StringDescriptorVisitor<T extends IComponent> {
787 boolean visit(T component, StringDescriptor descriptor);
791 public static void iterateStringDescriptors(final IComponent component,
792 final StringDescriptorVisitor<IComponent> visitor) {
793 iterate(component, new ComponentVisitor<IComponent>() {
795 public boolean visit(final IComponent component) {
796 for(IProperty prop: component.getModifiedProperties()) {
797 Object value = prop.getPropertyValue(component);
798 if (value instanceof StringDescriptor) {
799 if (!visitor.visit(component, (StringDescriptor) value)) {
800 return false;
804 if (component.getParentContainer() instanceof ITabbedPane) {
805 StringDescriptor tabTitle = ((ITabbedPane) component.getParentContainer()).getTabProperty(component, ITabbedPane.TAB_TITLE_PROPERTY);
806 if (tabTitle != null && !visitor.visit(component, tabTitle)) {
807 return false;
809 StringDescriptor tabToolTip = ((ITabbedPane) component.getParentContainer()).getTabProperty(component, ITabbedPane.TAB_TOOLTIP_PROPERTY);
810 if (tabToolTip != null && !visitor.visit(component, tabToolTip)) {
811 return false;
814 if (component instanceof IContainer) {
815 final StringDescriptor borderTitle = ((IContainer) component).getBorderTitle();
816 if (borderTitle != null && !visitor.visit(component, borderTitle)) {
817 return false;
820 return true;
825 public static void clearSelection(@NotNull final RadContainer container){
826 container.setSelected(false);
828 for (int i = 0; i < container.getComponentCount(); i++) {
829 final RadComponent c = container.getComponent(i);
830 if (c instanceof RadContainer) {
831 clearSelection((RadContainer)c);
833 else {
834 c.setSelected(false);
840 * Finds component with the specified <code>id</code> starting from the
841 * <code>container</code>. The method goes recursively through the hierarchy
842 * of components. Note, that if <code>container</code> itself has <code>id</code>
843 * then the method immediately retuns it.
844 * @return the found component.
846 @Nullable
847 public static IComponent findComponent(@NotNull final IComponent component, @NotNull final String id) {
848 if (id.equals(component.getId())) {
849 return component;
851 if (!(component instanceof IContainer)) {
852 return null;
855 final IContainer uiContainer = (IContainer)component;
856 for (int i=0; i < uiContainer.getComponentCount(); i++){
857 final IComponent found = findComponent(uiContainer.getComponent(i), id);
858 if (found != null){
859 return found;
862 return null;
865 @Nullable
866 public static PsiClass findClassToBind(@NotNull final Module module, @NotNull final String classToBindName) {
867 return JavaPsiFacade.getInstance(module.getProject())
868 .findClass(classToBindName.replace('$', '.'), module.getModuleWithDependenciesScope());
871 public static interface ComponentVisitor <Type extends IComponent>{
873 * @return true if iteration should continue
875 boolean visit(Type component);