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
;
59 import java
.lang
.reflect
.InvocationTargetException
;
61 import java
.util
.List
;
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))) {
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) {
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());
120 GridConstraints delConstraints
= parent
.getLayoutManager().isGrid() ? component
.getConstraints() : null;
122 int index
= parent
.indexOfComponent(component
);
123 parent
.removeComponent(component
);
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);
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());
143 newSize
.width
= minSize
.width
;
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
)) {
163 catch (Exception e
) {
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;
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) {
207 final Point p
= SwingUtilities
.convertPoint(rootContainer
.getDelegee(), x
, y
, c
);
208 if (Painter
.getResizeMask(component
, p
.x
, p
.y
) != 0) {
221 * @return component which has dragger. There is only one component with the dargger
225 public static RadComponent
getDraggerHost(@NotNull final GuiEditor editor
){
226 final Ref
<RadComponent
> result
= new Ref
<RadComponent
>();
228 editor
.getRootContainer(),
229 new ComponentVisitor
<RadComponent
>() {
230 public boolean visit(final RadComponent component
) {
231 if(component
.hasDragger()){
232 result
.set(component
);
244 public static Cursor
getMoveDropCursor() {
246 return Cursor
.getSystemCustomCursor("MoveDrop.32x32");
248 catch (Exception ex
) {
249 return Cursor
.getDefaultCursor();
253 public static Cursor
getMoveNoDropCursor() {
255 return Cursor
.getSystemCustomCursor("MoveNoDrop.32x32");
257 catch (Exception ex
) {
258 return Cursor
.getDefaultCursor();
262 public static Cursor
getCopyDropCursor() {
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.
278 public static ArrayList
<RadComponent
> getSelectedComponents(@NotNull final GuiEditor editor
){
279 final ArrayList
<RadComponent
> result
= new ArrayList
<RadComponent
>();
280 calcSelectedComponentsImpl(result
, editor
.getRootContainer());
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
);
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
);
298 if (component
.isSelected()) {
299 result
.add(component
);
306 * @return all selected component inside the <code>editor</code>
309 public static ArrayList
<RadComponent
> getAllSelectedComponents(@NotNull final GuiEditor editor
){
310 final ArrayList
<RadComponent
> result
= new ArrayList
<RadComponent
>();
312 editor
.getRootContainer(),
313 new ComponentVisitor
<RadComponent
>(){
314 public boolean visit(final RadComponent component
) {
315 if(component
.isSelected()){
316 result
.add(component
);
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
);
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");
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
>();
358 new ComponentVisitor() {
359 public boolean visit(final IComponent component
) {
360 if(component
!= exceptComponent
&& binding
.equals(component
.getBinding())) {
361 boundComponent
.set(component
);
369 return boundComponent
.get();
373 public static RadContainer
getRadContainerAt(final RadRootContainer rootContainer
, final int x
, final int y
,
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();
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());
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();
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
;
425 shouldContinue
= visitor
.visit(component
);
427 catch (ProcessCanceledException ex
) {
430 if (!shouldContinue
) {
434 if (!(component
instanceof IContainer
)) {
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
)) {
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());
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()) {
483 Runnable runnable
= new Runnable() {
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
);
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
) {
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);
526 * @param rootContainer
528 public static String
generateId(final RadRootContainer rootContainer
) {
530 final String id
= Integer
.toString((int)(Math
.random() * 1024 * 1024), 16);
531 if (findComponent(rootContainer
, id
) == null) {
538 * @return {@link com.intellij.uiDesigner.designSurface.GuiEditor} from the context. Can be <code>null</code>.
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();
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) {
556 final UIDesignerToolWindowManager toolWindowManager
= UIDesignerToolWindowManager
.getInstance(project
);
557 if (toolWindowManager
== null) {
560 return toolWindowManager
.getActiveFormEditor();
565 * @param componentToAssignBinding
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;
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();
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()) {
604 public static Rectangle
getSelectionBounds(List
<RadComponent
> selection
) {
605 int minRow
= Integer
.MAX_VALUE
;
606 int minCol
= Integer
.MAX_VALUE
;
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
)) {
624 component
= component
.getParent();
630 * Selects the component and ensures that the tabbed panes containing the component are
631 * switched to the correct tab.
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
)) {
643 parent
= parent
.getParent();
645 component
.setSelected(true);
646 editor
.setSelectionLead(component
);
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();
661 clearSelection(root
);
662 selectComponent(editor
, component
);
663 editor
.setSelectionAnchor(component
);
664 editor
.scrollComponentInView(component
);
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?
681 builder
.beginUpdateSelection();
683 clearSelection((RadContainer
) getRoot(component
));
684 for(RadComponent aComponent
: components
) {
685 selectComponent(editor
, aComponent
);
689 builder
.endUpdateSelection();
694 public static boolean isDropOnChild(final DraggedComponentList draggedComponentList
,
695 final ComponentDropLocation location
) {
696 if (location
.getContainer() == null) {
700 for(RadComponent component
: draggedComponentList
.getComponents()) {
701 if (isChild(location
.getContainer(), component
)) {
708 private static boolean isChild(RadContainer maybeChild
, RadComponent maybeParent
) {
709 while(maybeChild
!= null) {
710 if (maybeParent
== maybeChild
) {
713 maybeChild
= maybeChild
.getParent();
718 public static PsiMethod
findCreateComponentsMethod(final PsiClass aClass
) {
719 PsiElementFactory factory
= JavaPsiFacade
.getInstance(aClass
.getProject()).getElementFactory();
722 method
= factory
.createMethodFromText("void " + AsmCodeGenerator
.CREATE_COMPONENTS_METHOD_NAME
+ "() {}",
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
;
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
)) {
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
)) {
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
)) {
809 StringDescriptor tabToolTip
= ((ITabbedPane
) component
.getParentContainer()).getTabProperty(component
, ITabbedPane
.TAB_TOOLTIP_PROPERTY
);
810 if (tabToolTip
!= null && !visitor
.visit(component
, tabToolTip
)) {
814 if (component
instanceof IContainer
) {
815 final StringDescriptor borderTitle
= ((IContainer
) component
).getBorderTitle();
816 if (borderTitle
!= null && !visitor
.visit(component
, borderTitle
)) {
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
);
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.
847 public static IComponent
findComponent(@NotNull final IComponent component
, @NotNull final String id
) {
848 if (id
.equals(component
.getId())) {
851 if (!(component
instanceof IContainer
)) {
855 final IContainer uiContainer
= (IContainer
)component
;
856 for (int i
=0; i
< uiContainer
.getComponentCount(); i
++){
857 final IComponent found
= findComponent(uiContainer
.getComponent(i
), id
);
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
);