EA-36364 (dispose module after external modify project structure)
[idea/community.git] / plugins / ui-designer / src / com / intellij / uiDesigner / radComponents / RadComponent.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.intellij.uiDesigner.radComponents;
17
18 import com.intellij.openapi.diagnostic.Logger;
19 import com.intellij.openapi.module.Module;
20 import com.intellij.openapi.project.Project;
21 import com.intellij.uiDesigner.*;
22 import com.intellij.uiDesigner.compiler.Utils;
23 import com.intellij.uiDesigner.core.GridConstraints;
24 import com.intellij.uiDesigner.core.Util;
25 import com.intellij.uiDesigner.designSurface.EventProcessor;
26 import com.intellij.uiDesigner.designSurface.GuiEditor;
27 import com.intellij.uiDesigner.designSurface.InsertComponentProcessor;
28 import com.intellij.uiDesigner.lw.*;
29 import com.intellij.uiDesigner.palette.ComponentItem;
30 import com.intellij.uiDesigner.palette.Palette;
31 import com.intellij.uiDesigner.propertyInspector.IntrospectedProperty;
32 import com.intellij.uiDesigner.propertyInspector.Property;
33 import com.intellij.uiDesigner.propertyInspector.properties.ClientPropertiesProperty;
34 import com.intellij.uiDesigner.propertyInspector.properties.ClientPropertyProperty;
35 import com.intellij.uiDesigner.propertyInspector.properties.IntroStringProperty;
36 import com.intellij.uiDesigner.snapShooter.SnapshotContext;
37 import com.intellij.util.ArrayUtil;
38 import org.jetbrains.annotations.NonNls;
39 import org.jetbrains.annotations.NotNull;
40 import org.jetbrains.annotations.Nullable;
41
42 import javax.swing.*;
43 import java.awt.Dimension;
44 import java.awt.Point;
45 import java.awt.Rectangle;
46 import java.awt.event.MouseEvent;
47 import java.beans.PropertyChangeListener;
48 import java.beans.PropertyChangeSupport;
49 import java.lang.reflect.Constructor;
50 import java.util.ArrayList;
51 import java.util.HashSet;
52
53 /**
54  * @author Anton Katilin
55  * @author Vladimir Kondratyev
56  */
57 public abstract class RadComponent implements IComponent {
58   private static final Logger LOG = Logger.getInstance("#com.intellij.uiDesigner.radComponents.RadComponent");
59
60   /**
61    * Shared instance of empty array of RadComponenets
62    */
63   public static final RadComponent[] EMPTY_ARRAY = new RadComponent[]{};
64   /**
65    * Using this constant as client property of the Swing component
66    * you can find corresponding <code>RadComponent</code>
67    */
68   @NonNls
69   public static final String CLIENT_PROP_RAD_COMPONENT = "radComponent";
70
71   @NonNls
72   public static final String CLIENT_PROP_LOAD_TIME_LOCALE = "LoadTimeLocaleKey";
73
74   /**
75    * Whether the component selected or not. Value is java.lang.Boolean
76    */
77   @NonNls public static final String PROP_SELECTED = "selected";
78
79   /**
80    * Change notification for this property is fired when the constraints of a component
81    * change.
82    */
83   @NonNls public static final String PROP_CONSTRAINTS = "constraints";
84
85   /**
86    * Component id is unique per RadRootContainer.
87    */
88   @NotNull private final String myId;
89   /**
90    * @see #getBinding()
91    */
92   private String myBinding;
93   private boolean myCustomCreate = false;
94   private boolean myLoadingProperties = false;
95
96   private final ModuleProvider myModule;
97
98   @NotNull private final Class myClass;
99   /**
100    * Delegee is the JComponent which really represents the
101    * component in UI.
102    */
103   @NotNull private final JComponent myDelegee;
104   /**
105    * Parent RadContainer. This field is always not <code>null</code>
106    * is the component is in hierarchy. But the root of hierarchy
107    * has <code>null</code> parent indeed.
108    */
109   private RadContainer myParent;
110   /**
111    * Defines whether the component selected or not.
112    */
113   private boolean mySelected;
114
115   @NotNull private final GridConstraints myConstraints;
116
117   private Object myCustomLayoutConstraints;
118
119   private final PropertyChangeSupport myChangeSupport;
120
121   private final HashSet<String> myModifiedPropertyNames;
122
123   private Palette myPalette;
124
125   private boolean myHasDragger;
126   private boolean myResizing;
127   private boolean myDragging;
128   private boolean myDragBorder;
129   private boolean myDefaultBinding;
130
131   /**
132    * Creates new <code>RadComponent</code> with the specified
133    * class of delegee and specified ID.
134    *
135    * @param aClass class of the compoent's delegee
136    * @param id     id of the compoent inside the form. <code>id</code>
137    *               should be a unique atring inside the form.
138    */
139   public RadComponent(final ModuleProvider module, @NotNull final Class aClass, @NotNull final String id) {
140     myModule = module;
141     myClass = aClass;
142     myId = id;
143
144     myChangeSupport = new PropertyChangeSupport(this);
145     myConstraints = new GridConstraints();
146     myModifiedPropertyNames = new HashSet<String>();
147
148     Constructor constructor;
149     try {
150       constructor = myClass.getConstructor(ArrayUtil.EMPTY_CLASS_ARRAY);
151     }
152     catch (NoSuchMethodException e) {
153       try {
154         constructor = Utils.suggestReplacementClass(myClass).getConstructor(ArrayUtil.EMPTY_CLASS_ARRAY);
155       }
156       catch (NoSuchMethodException e1) {
157         throw new RuntimeException(e1);
158       }
159       setCustomCreate(true);
160     }
161
162     constructor.setAccessible(true);
163     try {
164       myDelegee = (JComponent)constructor.newInstance(ArrayUtil.EMPTY_OBJECT_ARRAY);
165     }
166     catch (Exception e) {
167       throw new RuntimeException(e);
168     }
169
170     myDelegee.putClientProperty(CLIENT_PROP_RAD_COMPONENT, this);
171   }
172
173   public RadComponent(final ModuleProvider module, @NotNull final Class aClass, @NotNull final String id, final Palette palette) {
174     this(module, aClass, id);
175     myPalette = palette;
176   }
177
178   /**
179    * @return module for the component.
180    */
181   public final Module getModule() {
182     return myModule == null ? null : myModule.getModule();
183   }
184
185   public final Project getProject() {
186     return myModule == null ? null : myModule.getProject();
187   }
188
189   public boolean isLoadingProperties() {
190     return myLoadingProperties;
191   }
192
193   public Palette getPalette() {
194     if (myPalette == null) {
195       return Palette.getInstance(getProject());
196     }
197     return myPalette;
198   }
199
200   public void setPalette(final Palette palette) {
201     myPalette = palette;
202   }
203
204   /**
205    * Initializes introspected properties into default values and
206    * sets default component's constraints.
207    */
208   public void init(final GuiEditor editor, @NotNull final ComponentItem item) {
209     initDefaultProperties(item);
210   }
211
212   public void initDefaultProperties(@NotNull final ComponentItem item) {
213     final IntrospectedProperty[] properties = getPalette().getIntrospectedProperties(this);
214     for (final IntrospectedProperty property : properties) {
215       final Object initialValue = item.getInitialValue(property);
216       if (initialValue != null) {
217         try {
218           //noinspection unchecked
219           property.setValue(this, initialValue);
220         }
221         catch (Exception e) {
222           throw new RuntimeException(e);
223         }
224       }
225     }
226
227     myConstraints.restore(item.getDefaultConstraints());
228   }
229
230   /**
231    * @return the component's id. It is unique within the form.
232    */
233   @NotNull
234   public final String getId() {
235     return myId;
236   }
237
238   public final String getBinding() {
239     return myBinding;
240   }
241
242   public final void setBinding(final String binding) {
243     //TODO[anton,vova]: check that binding is a valid java identifier!!!
244     myBinding = binding;
245   }
246
247   public boolean isCustomCreate() {
248     return myCustomCreate;
249   }
250
251   public void setCustomCreate(final boolean customCreate) {
252     myCustomCreate = customCreate;
253   }
254
255   public boolean isCustomCreateRequired() {
256     return !getDelegee().getClass().equals(getComponentClass());
257   }
258
259   /**
260    * @return Swing delegee component. The <code>RadComponent</code> has the same
261    *         delegee during all its life.
262    */
263   @NotNull
264   public final JComponent getDelegee() {
265     return myDelegee;
266   }
267
268   /**
269    * Sometime bounds of the inplace editor depends on the point where
270    * user invoked inplace editor.
271    *
272    * @param x x in delegee coordinate system
273    * @param y y in delegee coordinate system
274    * @return inplace property for the <code>RadComponent</code> if any.
275    *         The method returns <code>null</code> if the component doesn't have
276    *         any inplace property. Please not the method can return different
277    *         instances of the property for each invokation.
278    */
279   @Nullable
280   public Property getInplaceProperty(final int x, final int y) {
281     return getDefaultInplaceProperty();
282   }
283
284   @Nullable
285   public Property getDefaultInplaceProperty() {
286     return getPalette().getInplaceProperty(this);
287   }
288
289   @Nullable
290   public Rectangle getDefaultInplaceEditorBounds() {
291     return null;
292   }
293
294   /**
295    * Sometime bounds of the inplace editor depends on the point where
296    * user invoked inplace editor.
297    *
298    * @param x x in delegee coordinate system
299    * @param y y in delegee coordinate system
300    * @return area where editor component is located. This is the hint to the
301    *         designer.  Designer can use or not this rectangle.
302    */
303   @Nullable
304   public Rectangle getInplaceEditorBounds(@NotNull final Property property, final int x, final int y) {
305     return null;
306   }
307
308   @NotNull
309   public final Class getComponentClass() {
310     return myClass;
311   }
312
313   @NotNull
314   public String getComponentClassName() {
315     return myClass.getName();
316   }
317
318   public final Object getCustomLayoutConstraints() {
319     return myCustomLayoutConstraints;
320   }
321
322   public final void setCustomLayoutConstraints(final Object customConstraints) {
323     myCustomLayoutConstraints = customConstraints;
324   }
325
326   public void changeCustomLayoutConstraints(final Object constraints) {
327     setCustomLayoutConstraints(constraints);
328     // update constraints in CardLayout
329     final JComponent parent = getParent().getDelegee();
330     for (int i = 0; i < parent.getComponentCount(); i++) {
331       if (parent.getComponent(i) == getDelegee()) {
332         parent.remove(i);
333         parent.add(getDelegee(), constraints, i);
334         break;
335       }
336     }
337   }
338
339   public final boolean hasDragger() {
340     return myHasDragger;
341   }
342
343   public final void setDragger(final boolean hasDragger) {
344     myHasDragger = hasDragger;
345   }
346
347   public boolean isResizing() {
348     return myResizing;
349   }
350
351   public void setResizing(final boolean resizing) {
352     myResizing = resizing;
353   }
354
355   public boolean isDragging() {
356     return myDragging;
357   }
358
359   public void setDragging(final boolean dragging) {
360     myDragging = dragging;
361     RadContainer parent = getParent();
362     if (parent != null) {
363       parent.getLayoutManager().setChildDragging(this, dragging);
364     }
365   }
366
367   public void setDragBorder(final boolean dragging) {
368     myDragging = dragging;
369     myDragBorder = dragging;
370   }
371
372   public boolean isDragBorder() {
373     return myDragBorder;
374   }
375
376   public boolean isDefaultBinding() {
377     return myDefaultBinding;
378   }
379
380   public void setDefaultBinding(final boolean defaultBinding) {
381     myDefaultBinding = defaultBinding;
382   }
383
384   public final void addPropertyChangeListener(final PropertyChangeListener l) {
385     final PropertyChangeListener[] propertyChangeListeners = myChangeSupport.getPropertyChangeListeners();
386     for (PropertyChangeListener listener : propertyChangeListeners) {
387       assert listener != l;
388     }
389     myChangeSupport.addPropertyChangeListener(l);
390   }
391
392   public final void removePropertyChangeListener(final PropertyChangeListener l) {
393     myChangeSupport.removePropertyChangeListener(l);
394   }
395
396   protected final void firePropertyChanged(
397     @NotNull final String propertyName,
398     final Object oldValue,
399     final Object newValue
400   ) {
401     myChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
402   }
403
404   /**
405    * @return component's constarints.
406    */
407   @NotNull
408   public final GridConstraints getConstraints() {
409     return myConstraints;
410   }
411
412   public final RadContainer getParent() {
413     return myParent;
414   }
415
416   public final void setParent(final RadContainer parent) {
417     myParent = parent;
418   }
419
420   public boolean isSelected() {
421     return mySelected;
422   }
423
424   public void setSelected(final boolean selected) {
425     if (mySelected != selected) {
426       mySelected = selected;
427       firePropertyChanged(PROP_SELECTED, !mySelected, mySelected);
428       GuiEditor.repaintLayeredPane(this);
429     }
430   }
431
432   /**
433    * @see JComponent#getClientProperty(Object)
434    */
435   public final Object getClientProperty(@NotNull final Object key) {
436     return myDelegee.getClientProperty(key);
437   }
438
439   /**
440    * @see JComponent#putClientProperty(Object, Object)
441    */
442   public final void putClientProperty(@NotNull final Object key, final Object value) {
443     myDelegee.putClientProperty(key, value);
444   }
445
446   public final int getX() {
447     return myDelegee.getX();
448   }
449
450   public final int getY() {
451     return myDelegee.getY();
452   }
453
454   public final void setLocation(final Point location) {
455     myDelegee.setLocation(location);
456   }
457
458   public final void shift(final int dx, final int dy) {
459     myDelegee.setLocation(myDelegee.getX() + dx, myDelegee.getY() + dy);
460   }
461
462   public final int getWidth() {
463     return myDelegee.getWidth();
464   }
465
466   public final int getHeight() {
467     return myDelegee.getHeight();
468   }
469
470   public final Dimension getSize() {
471     return myDelegee.getSize();
472   }
473
474   public final void setSize(final Dimension size) {
475     myDelegee.setSize(size);
476   }
477
478   /**
479    * @return bounds of the delegee in the parent container
480    */
481   public final Rectangle getBounds() {
482     return myDelegee.getBounds();
483   }
484
485   public final void setBounds(final Rectangle bounds) {
486     myDelegee.setBounds(bounds);
487   }
488
489   public final Dimension getMinimumSize() {
490     return Util.getMinimumSize(myDelegee, myConstraints, false);
491   }
492
493   public final Dimension getPreferredSize() {
494     return Util.getPreferredSize(myDelegee, myConstraints, false);
495   }
496
497   public void refresh() {
498   }
499
500   public final void revalidate() {
501     RadContainer theContainer = null;
502
503     for (RadContainer container = this instanceof RadContainer ? (RadContainer)this : getParent();
504          container != null;
505          container = container.getParent()) {
506       final RadContainer parent = container.getParent();
507       if (parent != null && parent.isXY()) {
508         final Dimension size = container.getSize();
509         final Dimension minimumSize = container.getMinimumSize();
510         if (size.width < minimumSize.width || size.height < minimumSize.height) {
511           theContainer = container;
512         }
513       }
514     }
515
516     if (theContainer != null) {
517       final Dimension minimumSize = theContainer.getMinimumSize();
518
519       minimumSize.width = Math.max(minimumSize.width, theContainer.getWidth());
520       minimumSize.height = Math.max(minimumSize.height, theContainer.getHeight());
521
522       theContainer.getDelegee().setSize(minimumSize);
523     }
524
525     myDelegee.revalidate();
526   }
527
528   public final boolean isMarkedAsModified(final Property property) {
529     return myModifiedPropertyNames.contains(property.getName());
530   }
531
532   public final void markPropertyAsModified(final Property property) {
533     myModifiedPropertyNames.add(property.getName());
534   }
535
536   public final void removeModifiedProperty(final Property property) {
537     myModifiedPropertyNames.remove(property.getName());
538   }
539
540   public RadComponent getComponentToDrag(final Point pnt) {
541     return this;
542   }
543
544   public void processMouseEvent(final MouseEvent event) {
545   }
546
547   @Nullable
548   public EventProcessor getEventProcessor(final MouseEvent event) {
549     return null;
550   }
551
552   /**
553    * Serializes component into the passed <code>writer</code>
554    */
555   public abstract void write(XmlWriter writer);
556
557   /**
558    * Serializes component's ID
559    */
560   protected final void writeId(final XmlWriter writer) {
561     writer.addAttribute("id", getId());
562   }
563
564   /**
565    * Serializes component's class
566    */
567   protected final void writeClass(final XmlWriter writer) {
568     writer.addAttribute(UIFormXmlConstants.ATTRIBUTE_CLASS, getComponentClass().getName());
569   }
570
571   protected final void writeClassIfDifferent(final XmlWriter writer, String defaultClassName) {
572     if (!getComponentClassName().equals(defaultClassName)) {
573       writer.addAttribute(UIFormXmlConstants.ATTRIBUTE_CLASS, getComponentClass().getName());
574     }
575   }
576
577   protected final void writeBinding(final XmlWriter writer) {
578     // Binding
579     if (getBinding() != null) {
580       writer.addAttribute(UIFormXmlConstants.ATTRIBUTE_BINDING, getBinding());
581     }
582     if (isCustomCreate()) {
583       writer.addAttribute(UIFormXmlConstants.ATTRIBUTE_CUSTOM_CREATE, Boolean.TRUE.toString());
584     }
585     if (isDefaultBinding()) {
586       writer.addAttribute(UIFormXmlConstants.ATTRIBUTE_DEFAULT_BINDING, Boolean.TRUE.toString());
587     }
588   }
589
590   protected void writeConstraints(final XmlWriter writer) {
591     writer.startElement("constraints");
592     try {
593       if (getParent() != null) {
594         getParent().getLayoutManager().writeChildConstraints(writer, this);
595       }
596     }
597     finally {
598       writer.endElement(); // constraints
599     }
600   }
601
602   protected final void writeProperties(final XmlWriter writer) {
603     writer.startElement(UIFormXmlConstants.ELEMENT_PROPERTIES);
604     try {
605       final IntrospectedProperty[] introspectedProperties =
606         getPalette().getIntrospectedProperties(this);
607       for (final IntrospectedProperty property : introspectedProperties) {
608         if (isMarkedAsModified(property)) {
609           final Object value = property.getValue(this);
610           if (value != null) {
611             writer.startElement(property.getName());
612             try {
613               //noinspection unchecked
614               property.write(value, writer);
615             }
616             finally {
617               writer.endElement();
618             }
619           }
620         }
621       }
622     }
623     finally {
624       writer.endElement(); // properties
625     }
626     writeClientProperties(writer);
627   }
628
629   private void writeClientProperties(final XmlWriter writer) {
630     if (myModule == null) {
631       return;
632     }
633     boolean haveClientProperties = false;
634     try {
635       ClientPropertiesProperty cpp = ClientPropertiesProperty.getInstance(getProject());
636       for (Property prop : cpp.getChildren(this)) {
637         ClientPropertyProperty clientProp = (ClientPropertyProperty)prop;
638         final Object value = getDelegee().getClientProperty(clientProp.getName());
639         if (value != null) {
640           if (!haveClientProperties) {
641             writer.startElement(UIFormXmlConstants.ELEMENT_CLIENT_PROPERTIES);
642             haveClientProperties = true;
643           }
644           writer.startElement(clientProp.getName());
645           writer.addAttribute(UIFormXmlConstants.ATTRIBUTE_CLASS, value.getClass().getName());
646           writer.addAttribute(UIFormXmlConstants.ATTRIBUTE_VALUE, value.toString());
647           writer.endElement();
648         }
649       }
650     }
651     finally {
652       if (haveClientProperties) {
653         writer.endElement();
654       }
655     }
656   }
657
658   public void fireConstraintsChanged(GridConstraints oldConstraints) {
659     firePropertyChanged(PROP_CONSTRAINTS, oldConstraints, myConstraints);
660   }
661
662   public IProperty[] getModifiedProperties() {
663     IntrospectedProperty[] props = getPalette().getIntrospectedProperties(this);
664     ArrayList<IProperty> result = new ArrayList<IProperty>();
665     for (IntrospectedProperty prop : props) {
666       if (isMarkedAsModified(prop)) {
667         result.add(prop);
668       }
669     }
670     return result.toArray(new IProperty[result.size()]);
671   }
672
673   public IContainer getParentContainer() {
674     return myParent;
675   }
676
677   public boolean hasIntrospectedProperties() {
678     return true;
679   }
680
681   public boolean accept(ComponentVisitor visitor) {
682     return visitor.visit(this);
683   }
684
685   public boolean areChildrenExclusive() {
686     return false;
687   }
688
689   public void loadLwProperty(final LwComponent lwComponent,
690                              final LwIntrospectedProperty lwProperty,
691                              final IntrospectedProperty property) {
692     myLoadingProperties = true;
693     try {
694       try {
695         final Object value = lwComponent.getPropertyValue(lwProperty);
696         //noinspection unchecked
697         property.setValue(this, value);
698       }
699       catch (Exception e) {
700         LOG.error(e);
701         //TODO[anton,vova]: show error and continue to load form
702       }
703     }
704     finally {
705       myLoadingProperties = false;
706     }
707   }
708
709   public void doneLoadingFromLw() {
710   }
711
712   @Nullable
713   public static RadComponent createSnapshotComponent(final SnapshotContext context, final JComponent component) {
714     String id = context.newId();
715     RadComponent result;
716
717     Class componentClass = component.getClass();
718     if (componentClass.isAnonymousClass()) {
719       componentClass = componentClass.getSuperclass();
720     }
721     if (component instanceof JPanel && !isCompositeComponent(component)) {
722       RadContainer container = new RadContainer(componentClass, id, context.getPalette());
723       final RadLayoutManager manager = LayoutManagerRegistry.createFromLayout(component.getLayout());
724       if (manager == null) {
725         return null;
726       }
727       container.setLayoutManager(manager);
728       result = container;
729     }
730     else if (component instanceof Box.Filler) {
731       Box.Filler filler = (Box.Filler)component;
732       if (filler.getMaximumSize().height == Short.MAX_VALUE) {
733         result = new RadVSpacer(null, id);
734         result.getConstraints().setVSizePolicy(GridConstraints.SIZEPOLICY_CAN_GROW | GridConstraints.SIZEPOLICY_WANT_GROW);
735       }
736       else {
737         result = new RadHSpacer(null, id);
738         result.getConstraints().setHSizePolicy(GridConstraints.SIZEPOLICY_CAN_GROW | GridConstraints.SIZEPOLICY_WANT_GROW);
739       }
740     }
741     else {
742       final RadComponentFactory factory = InsertComponentProcessor.getRadComponentFactory(componentClass);
743       if (factory == null) {
744         result = new RadAtomicComponent(componentClass, id, context.getPalette());
745       }
746       else {
747         result = factory.newInstance(componentClass, id, context.getPalette());
748       }
749     }
750
751     context.registerComponent(component, result);
752     result.importSnapshotComponent(context, component);
753
754     final IntrospectedProperty[] properties = context.getPalette().getIntrospectedProperties(component.getClass(),
755                                                                                              result.getDelegee().getClass());
756     for (IntrospectedProperty prop : properties) {
757       if (component instanceof AbstractButton) {
758         AbstractButton btn = (AbstractButton)component;
759         if (prop.getName().equals(SwingProperties.LABEL) && btn.getLabel().equals(btn.getText())) {
760           continue;
761         }
762         if (prop.getName().equals(SwingProperties.ACTION_COMMAND) && btn.getActionCommand().equals(btn.getText())) {
763           continue;
764         }
765       }
766       prop.importSnapshotValue(context, component, result);
767     }
768
769     if (component instanceof AbstractButton) {
770       AbstractButton btn = (AbstractButton)component;
771       if (btn.getModel() instanceof DefaultButtonModel) {
772         DefaultButtonModel model = (DefaultButtonModel)btn.getModel();
773         if (model.getGroup() != null) {
774           context.registerButtonGroup(model.getGroup());
775         }
776       }
777     }
778
779     return result;
780   }
781
782   private static boolean isCompositeComponent(final JComponent component) {
783     if (component.getComponentCount() == 0) {
784       return false;
785     }
786
787     JComponent instance;
788     try {
789       instance = component.getClass().newInstance();
790     }
791     catch (Exception ex) {
792       return false;
793     }
794     return instance.getComponentCount() == component.getComponentCount();
795   }
796
797   protected void importSnapshotComponent(final SnapshotContext context, final JComponent component) {
798   }
799
800   @Nullable
801   public String getComponentTitle() {
802     Palette palette = Palette.getInstance(getProject());
803     IntrospectedProperty[] props = palette.getIntrospectedProperties(this);
804     for (IntrospectedProperty prop : props) {
805       if (prop.getName().equals(SwingProperties.TEXT) && prop instanceof IntroStringProperty) {
806         StringDescriptor value = (StringDescriptor)prop.getValue(this);
807         if (value != null) {
808           return "\"" + value.getResolvedValue() + "\"";
809         }
810       }
811     }
812
813     if (this instanceof RadContainer) {
814       RadContainer container = (RadContainer)this;
815       StringDescriptor descriptor = container.getBorderTitle();
816       if (descriptor != null) {
817         if (descriptor.getResolvedValue() == null) {
818           descriptor.setResolvedValue(StringDescriptorManager.getInstance(getModule()).resolve(this, descriptor));
819         }
820         return "\"" + descriptor.getResolvedValue() + "\"";
821       }
822     }
823
824     if (getParent() instanceof RadTabbedPane) {
825       RadTabbedPane parentTabbedPane = (RadTabbedPane)getParent();
826       final StringDescriptor descriptor = parentTabbedPane.getChildTitle(this);
827       if (descriptor != null) {
828         if (descriptor.getResolvedValue() == null) {
829           descriptor.setResolvedValue(StringDescriptorManager.getInstance(getModule()).resolve(this, descriptor));
830         }
831         return "\"" + descriptor.getResolvedValue() + "\"";
832       }
833       else {
834         parentTabbedPane.getChildTitle(this);
835       }
836     }
837     return null;
838   }
839
840   public String getDisplayName() {
841     StringBuilder titleBuilder = new StringBuilder();
842     if (getBinding() != null) {
843       titleBuilder.append(getBinding());
844     }
845     else {
846       final String className = getComponentClassName();
847       int pos = className.lastIndexOf('.');
848       if (pos < 0) {
849         titleBuilder.append(className);
850       }
851       else {
852         titleBuilder.append(className.substring(pos + 1).replace('$', '.'));
853       }
854       final String title = getComponentTitle();
855       if (title != null) {
856         titleBuilder.append(" ").append(title);
857       }
858     }
859     return titleBuilder.toString();
860   }
861 }