replaced <code></code> with more concise {@code}
[idea/community.git] / plugins / ui-designer / src / com / intellij / uiDesigner / componentTree / ComponentTree.java
1 /*
2  * Copyright 2000-2015 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.componentTree;
17
18 import com.intellij.codeHighlighting.HighlightDisplayLevel;
19 import com.intellij.codeInsight.daemon.impl.SeverityRegistrar;
20 import com.intellij.icons.AllIcons;
21 import com.intellij.ide.DeleteProvider;
22 import com.intellij.ide.highlighter.JavaHighlightingColors;
23 import com.intellij.ide.util.EditSourceUtil;
24 import com.intellij.ide.util.treeView.NodeDescriptor;
25 import com.intellij.lang.annotation.HighlightSeverity;
26 import com.intellij.openapi.actionSystem.*;
27 import com.intellij.openapi.application.ApplicationManager;
28 import com.intellij.openapi.diagnostic.Logger;
29 import com.intellij.openapi.editor.colors.EditorColorsManager;
30 import com.intellij.openapi.editor.colors.EditorColorsScheme;
31 import com.intellij.openapi.editor.colors.TextAttributesKey;
32 import com.intellij.openapi.editor.markup.TextAttributes;
33 import com.intellij.openapi.project.Project;
34 import com.intellij.psi.PsiClass;
35 import com.intellij.psi.PsiField;
36 import com.intellij.ui.ColoredTreeCellRenderer;
37 import com.intellij.ui.JBColor;
38 import com.intellij.ui.PopupHandler;
39 import com.intellij.ui.SimpleTextAttributes;
40 import com.intellij.ui.treeStructure.Tree;
41 import com.intellij.uiDesigner.*;
42 import com.intellij.uiDesigner.actions.StartInplaceEditingAction;
43 import com.intellij.uiDesigner.core.GridConstraints;
44 import com.intellij.uiDesigner.designSurface.*;
45 import com.intellij.uiDesigner.editor.UIFormEditor;
46 import com.intellij.uiDesigner.lw.LwInspectionSuppression;
47 import com.intellij.uiDesigner.palette.ComponentItem;
48 import com.intellij.uiDesigner.palette.Palette;
49 import com.intellij.uiDesigner.quickFixes.QuickFixManager;
50 import com.intellij.uiDesigner.radComponents.*;
51 import com.intellij.util.ArrayUtil;
52 import com.intellij.util.ui.PlatformColors;
53 import com.intellij.util.ui.UIUtil;
54 import com.intellij.util.ui.tree.TreeUtil;
55 import icons.UIDesignerIcons;
56 import org.jetbrains.annotations.NonNls;
57 import org.jetbrains.annotations.NotNull;
58 import org.jetbrains.annotations.Nullable;
59
60 import javax.swing.*;
61 import javax.swing.plaf.TreeUI;
62 import javax.swing.tree.DefaultMutableTreeNode;
63 import javax.swing.tree.DefaultTreeModel;
64 import javax.swing.tree.TreePath;
65 import java.awt.*;
66 import java.awt.datatransfer.Transferable;
67 import java.awt.dnd.*;
68 import java.awt.event.KeyEvent;
69 import java.awt.event.MouseEvent;
70 import java.util.*;
71 import java.util.List;
72
73 /**
74  * @author Anton Katilin
75  * @author Vladimir Kondratyev
76  */
77 public final class ComponentTree extends Tree implements DataProvider {
78   private static final Logger LOG = Logger.getInstance("#com.intellij.uiDesigner.componentTree.ComponentTree");
79
80   public static final DataKey<LwInspectionSuppression[]> LW_INSPECTION_SUPPRESSION_ARRAY_DATA_KEY =
81     DataKey.create(LwInspectionSuppression.class.getName());
82
83   private SimpleTextAttributes myBindingAttributes; // exists only for performance reason
84   private SimpleTextAttributes myClassAttributes; // exists only for performance reason
85   private SimpleTextAttributes myPackageAttributes; // exists only for performance reason
86   private SimpleTextAttributes myUnknownAttributes; // exists only for performance reason
87   private SimpleTextAttributes myTitleAttributes; // exists only for performance reason
88
89   private Map<HighlightSeverity, Map<SimpleTextAttributes, SimpleTextAttributes>> myHighlightAttributes;
90
91   private GuiEditor myEditor;
92   private UIFormEditor myFormEditor;
93   private QuickFixManager myQuickFixManager;
94   private RadComponent myDropTargetComponent = null;
95   private final StartInplaceEditingAction myStartInplaceEditingAction;
96   private final MyDeleteProvider myDeleteProvider = new MyDeleteProvider();
97
98   @NonNls private static final String ourHelpID = "guiDesigner.uiTour.compsTree";
99   private final Project myProject;
100
101   public ComponentTree(@NotNull final Project project) {
102     super(new DefaultTreeModel(new DefaultMutableTreeNode()));
103     myProject = project;
104
105     setCellRenderer(new MyTreeCellRenderer());
106     setRootVisible(false);
107     setShowsRootHandles(true);
108
109     // Enable tooltips
110     ToolTipManager.sharedInstance().registerComponent(this);
111
112     // Install convenient keyboard navigation
113     TreeUtil.installActions(this);
114
115     // Popup menu
116     PopupHandler.installPopupHandler(
117       this,
118       (ActionGroup)ActionManager.getInstance().getAction(IdeActions.GROUP_GUI_DESIGNER_COMPONENT_TREE_POPUP),
119       ActionPlaces.GUI_DESIGNER_COMPONENT_TREE_POPUP, ActionManager.getInstance());
120
121     // F2 should start inplace editing
122     myStartInplaceEditingAction = new StartInplaceEditingAction(null);
123     myStartInplaceEditingAction.registerCustomShortcutSet(
124       new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0)),
125       this
126     );
127
128     if (!ApplicationManager.getApplication().isHeadlessEnvironment()) {
129       setDragEnabled(true);
130       setTransferHandler(new TransferHandler() {
131         public int getSourceActions(JComponent c) {
132           return DnDConstants.ACTION_COPY_OR_MOVE;
133         }
134
135         protected Transferable createTransferable(JComponent c) {
136           return DraggedComponentList.pickupSelection(myEditor, null);
137         }
138       });
139       setDropTarget(new DropTarget(this, new MyDropTargetListener()));
140     }
141   }
142
143   @NotNull
144   public Project getProject() {
145     return myProject;
146   }
147
148   public void initQuickFixManager(JViewport viewPort) {
149     myQuickFixManager = new QuickFixManagerImpl(null, this, viewPort);
150   }
151
152   public void setEditor(final GuiEditor editor) {
153     myEditor = editor;
154     myDeleteProvider.setEditor(editor);
155     myQuickFixManager.setEditor(editor);
156     myStartInplaceEditingAction.setEditor(editor);
157   }
158
159   public void refreshIntentionHint() {
160     myQuickFixManager.refreshIntentionHint();
161   }
162
163   @Nullable
164   public String getToolTipText(final MouseEvent e) {
165     final TreePath path = getPathForLocation(e.getX(), e.getY());
166     final RadComponent component = getComponentFromPath(path);
167     if (component != null) {
168       final ErrorInfo errorInfo = ErrorAnalyzer.getErrorForComponent(component);
169       if (errorInfo != null) {
170         return errorInfo.myDescription;
171       }
172     }
173     return null;
174   }
175
176   @Nullable
177   private static RadComponent getComponentFromPath(TreePath path) {
178     if (path != null) {
179       final DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
180       LOG.assertTrue(node != null);
181       final Object userObject = node.getUserObject();
182       if (userObject instanceof ComponentPtrDescriptor) {
183         final ComponentPtrDescriptor descriptor = (ComponentPtrDescriptor)userObject;
184         final ComponentPtr ptr = descriptor.getElement();
185         if (ptr != null && ptr.isValid()) {
186           final RadComponent component = ptr.getComponent();
187           LOG.assertTrue(component != null);
188           return component;
189         }
190       }
191     }
192     return null;
193   }
194
195   /**
196    * TODO[vova] should return pair <RadComponent, TreePath>
197    *
198    * @return first selected component. The method returns {@code null}
199    *         if there is no selection in the tree.
200    */
201   @Nullable
202   public RadComponent getSelectedComponent() {
203     return ArrayUtil.getFirstElement(getSelectedComponents());
204   }
205
206   /**
207    * TODO[vova] should return pair <RadComponent, TreePath>
208    *
209    * @return currently selected components.
210    */
211   @NotNull public RadComponent[] getSelectedComponents() {
212     final TreePath[] paths = getSelectionPaths();
213     if (paths == null) {
214       return RadComponent.EMPTY_ARRAY;
215     }
216     final ArrayList<RadComponent> result = new ArrayList<>(paths.length);
217     for (TreePath path : paths) {
218       final DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
219       if (node != null && node.getUserObject() instanceof ComponentPtrDescriptor) {
220         final ComponentPtrDescriptor descriptor = (ComponentPtrDescriptor)node.getUserObject();
221         final ComponentPtr ptr = descriptor.getElement();
222         if (ptr != null && ptr.isValid()) {
223           result.add(ptr.getComponent());
224         }
225       }
226     }
227     return result.toArray(new RadComponent[result.size()]);
228   }
229
230   /**
231    * Provides {@link PlatformDataKeys#NAVIGATABLE} to navigate to
232    * binding of currently selected component (if any)
233    */
234   public Object getData(final String dataId) {
235     if (GuiEditor.DATA_KEY.is(dataId)) {
236       return myEditor;
237     }
238
239     if (PlatformDataKeys.DELETE_ELEMENT_PROVIDER.is(dataId)) {
240       return myDeleteProvider;
241     }
242
243     if (PlatformDataKeys.COPY_PROVIDER.is(dataId) ||
244         PlatformDataKeys.CUT_PROVIDER.is(dataId) ||
245         PlatformDataKeys.PASTE_PROVIDER.is(dataId)) {
246       return myEditor == null ? null : myEditor.getData(dataId);
247     }
248
249     if (LW_INSPECTION_SUPPRESSION_ARRAY_DATA_KEY.is(dataId)) {
250       Collection<LwInspectionSuppression> elements = getSelectedElements(LwInspectionSuppression.class);
251       return elements.size() == 0 ? null : elements.toArray(new LwInspectionSuppression[elements.size()]);
252     }
253
254     if (PlatformDataKeys.HELP_ID.is(dataId)) {
255       return ourHelpID;
256     }
257
258     if (PlatformDataKeys.FILE_EDITOR.is(dataId)) {
259       return myFormEditor;
260     }
261
262     if (!CommonDataKeys.NAVIGATABLE.is(dataId)) {
263       return null;
264     }
265
266     final RadComponent selectedComponent = getSelectedComponent();
267     if (selectedComponent == null) {
268       return null;
269     }
270
271     final String classToBind = myEditor.getRootContainer().getClassToBind();
272     if (classToBind == null) {
273       return null;
274     }
275
276     final PsiClass aClass = FormEditingUtil.findClassToBind(myEditor.getModule(), classToBind);
277     if (aClass == null) {
278       return null;
279     }
280
281     if (selectedComponent instanceof RadRootContainer) {
282       return EditSourceUtil.getDescriptor(aClass);
283     }
284
285     final String binding = selectedComponent.getBinding();
286     if (binding == null) {
287       return null;
288     }
289
290     final PsiField[] fields = aClass.getFields();
291
292     for (final PsiField field : fields) {
293       if (binding.equals(field.getName())) {
294         return EditSourceUtil.getDescriptor(field);
295       }
296     }
297
298     return null;
299   }
300
301   public <T> List<T> getSelectedElements(Class<? extends T> elementClass) {
302     final TreePath[] paths = getSelectionPaths();
303     if (paths == null) {
304       return Collections.emptyList();
305     }
306     final ArrayList<T> result = new ArrayList<>(paths.length);
307     for (TreePath path : paths) {
308       final DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
309       Object userObject = node.getUserObject();
310       if (userObject instanceof NodeDescriptor && elementClass.isInstance(((NodeDescriptor) userObject).getElement())) {
311         //noinspection unchecked
312         result.add((T)((NodeDescriptor) node.getUserObject()).getElement());
313       }
314     }
315     return result;
316   }
317
318   private SimpleTextAttributes getAttribute(@NotNull final SimpleTextAttributes attrs,
319                                             @Nullable HighlightDisplayLevel level) {
320     if (level == null) {
321       return attrs;
322     }
323
324     Map<SimpleTextAttributes, SimpleTextAttributes> highlightMap = myHighlightAttributes.get(level.getSeverity());
325     if (highlightMap == null) {
326       highlightMap = new HashMap<>();
327       myHighlightAttributes.put(level.getSeverity(), highlightMap);
328     }
329
330     SimpleTextAttributes result = highlightMap.get(attrs);
331     if (result == null) {
332       final TextAttributesKey attrKey = SeverityRegistrar.getSeverityRegistrar(myProject).getHighlightInfoTypeBySeverity(level.getSeverity()).getAttributesKey();
333       TextAttributes textAttrs = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(attrKey);
334       textAttrs = TextAttributes.merge(attrs.toTextAttributes(), textAttrs);
335       result = SimpleTextAttributes.fromTextAttributes(textAttrs);
336       highlightMap.put(attrs, result);
337     }
338
339     return result;
340   }
341
342   public void setUI(final TreeUI ui) {
343     super.setUI(ui);
344
345     // [vova] we cannot create this hash in constructor and just clear it here. The
346     // problem is that setUI is invoked by constructor of superclass.
347     myHighlightAttributes = new HashMap<>();
348
349     final EditorColorsScheme globalScheme = EditorColorsManager.getInstance().getGlobalScheme();
350     final TextAttributes attributes = globalScheme.getAttributes(JavaHighlightingColors.STRING);
351
352     myBindingAttributes = new SimpleTextAttributes(SimpleTextAttributes.STYLE_BOLD, UIUtil.getTreeForeground());
353     myClassAttributes = new SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, UIUtil.getTreeForeground());
354     myPackageAttributes = new SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, Color.GRAY);
355     myTitleAttributes =new SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, attributes.getForegroundColor());
356     myUnknownAttributes = new SimpleTextAttributes(SimpleTextAttributes.STYLE_WAVED, JBColor.RED);
357   }
358
359   public static Icon getComponentIcon(final RadComponent component) {
360     if (!(component instanceof RadErrorComponent)) {
361       final Palette palette = Palette.getInstance(component.getProject());
362       final ComponentItem item = palette.getItem(component.getComponentClassName());
363       final Icon icon;
364       if (item != null) {
365         icon = item.getSmallIcon();
366       }
367       else {
368         icon = UIDesignerIcons.Unknown_small;
369       }
370       return icon;
371     }
372     else {
373       return AllIcons.General.Error;
374     }
375   }
376
377   public void setDropTargetComponent(final @Nullable RadComponent dropTargetComponent) {
378     if (dropTargetComponent != myDropTargetComponent) {
379       myDropTargetComponent = dropTargetComponent;
380       repaint();
381     }
382   }
383
384   public void setFormEditor(final UIFormEditor formEditor) {
385     myFormEditor = formEditor;
386   }
387
388   private final class MyTreeCellRenderer extends ColoredTreeCellRenderer {
389     @NonNls private static final String SWING_PACKAGE = "javax.swing";
390
391     public void customizeCellRenderer(
392       final JTree tree,
393       final Object value,
394       final boolean selected,
395       final boolean expanded,
396       final boolean leaf,
397       final int row,
398       final boolean hasFocus
399     ) {
400       final DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
401       if (node.getUserObject() instanceof ComponentPtrDescriptor) {
402         final ComponentPtrDescriptor descriptor = (ComponentPtrDescriptor)node.getUserObject();
403         final ComponentPtr ptr = descriptor.getElement();
404         if (ptr == null) return;
405         final RadComponent component = ptr.getComponent();
406         if (component == null) return;
407
408         final HighlightDisplayLevel level = ErrorAnalyzer.getHighlightDisplayLevel(myProject, component);
409
410         // Text
411         boolean hasText = false;
412         final String binding = component.getBinding();
413         if (binding != null) {
414           append(binding, getAttribute(myBindingAttributes, level));
415           append(" : ", getAttribute(myClassAttributes, level));
416           hasText = true;
417         }
418         else {
419           String componentTitle = component.getComponentTitle();
420           if (componentTitle != null) {
421             append(componentTitle, getAttribute(myTitleAttributes, level));
422             append(" : ", getAttribute(myClassAttributes, level));
423             hasText = true;
424           }
425         }
426
427         final String componentClassName = component.getComponentClassName();
428
429         if (component instanceof RadVSpacer) {
430           append(UIDesignerBundle.message("component.vertical.spacer"), getAttribute(myClassAttributes, level));
431         }
432         else if (component instanceof RadHSpacer) {
433           append(UIDesignerBundle.message("component.horizontal.spacer"), getAttribute(myClassAttributes, level));
434         }
435         else if (component instanceof RadErrorComponent) {
436           final RadErrorComponent c = (RadErrorComponent)component;
437           append(c.getErrorDescription(), getAttribute(myUnknownAttributes, level));
438         }
439         else if (component instanceof RadRootContainer) {
440           append(UIDesignerBundle.message("component.form"), getAttribute(myClassAttributes, level));
441           append(" (", getAttribute(myPackageAttributes, level));
442           final String classToBind = ((RadRootContainer)component).getClassToBind();
443           if (classToBind != null) {
444             append(classToBind, getAttribute(myPackageAttributes, level));
445           }
446           else {
447             append(UIDesignerBundle.message("component.no.binding"), getAttribute(myPackageAttributes, level));
448           }
449           append(")", getAttribute(myPackageAttributes, level));
450         }
451         else {
452           String packageName = null;
453           int pos = componentClassName.lastIndexOf('.');
454           if (pos >= 0) {
455             packageName = componentClassName.substring(0, pos);
456           }
457
458           SimpleTextAttributes classAttributes = hasText ? myPackageAttributes : myClassAttributes;
459
460           if (packageName != null) {
461             append(componentClassName.substring(packageName.length() + 1).replace('$', '.'),
462                    getAttribute(classAttributes, level));
463             if (!packageName.equals(SWING_PACKAGE)) {
464               append(" (", getAttribute(myPackageAttributes, level));
465               append(packageName, getAttribute(myPackageAttributes, level));
466               append(")", getAttribute(myPackageAttributes, level));
467             }
468           }
469           else {
470             append(componentClassName.replace('$', '.'), getAttribute(classAttributes, level));
471           }
472         }
473
474         // Icon
475         setIcon(getComponentIcon(component));
476
477         if (component == myDropTargetComponent) {
478           setBorder(BorderFactory.createLineBorder(PlatformColors.BLUE, 1));
479         } else {
480           setBorder(BorderFactory.createEmptyBorder(1,1,1,1));
481         }
482       }
483       else if (node.getUserObject() != null) {
484         final String fragment = node.getUserObject().toString();
485         if (fragment != null) {
486           append(fragment, SimpleTextAttributes.REGULAR_ATTRIBUTES);
487         }
488         if (node.getUserObject() instanceof SuppressionDescriptor) {
489           setIcon(UIDesignerIcons.InspectionSuppression);
490         }
491         else if (node.getUserObject() instanceof ButtonGroupDescriptor) {
492           setIcon(UIDesignerIcons.ButtonGroup);
493         }
494       }
495     }
496   }
497
498   private final class MyDropTargetListener extends DropTargetAdapter {
499     public void dragOver(DropTargetDragEvent dtde) {
500       try {
501         RadComponent dropTargetComponent = null;
502         ComponentDragObject dragObject = null;
503
504         final DraggedComponentList dcl = DraggedComponentList.fromTransferable(dtde.getTransferable());
505         if (dcl != null) {
506           dragObject = dcl;
507         }
508         else {
509           ComponentItem componentItem = SimpleTransferable.getData(dtde.getTransferable(), ComponentItem.class);
510           if (componentItem != null) {
511             dragObject = new ComponentItemDragObject(componentItem);
512           }
513         }
514
515         boolean canDrop = false;
516         if (dragObject != null) {
517           final TreePath path = getPathForLocation((int) dtde.getLocation().getX(),
518                                                    (int) dtde.getLocation().getY());
519           final RadComponent targetComponent = getComponentFromPath(path);
520           if (path != null && targetComponent instanceof RadContainer) {
521             final ComponentDropLocation dropLocation = ((RadContainer)targetComponent).getDropLocation(null);
522             canDrop = dropLocation.canDrop(dragObject);
523             if (dcl != null && FormEditingUtil.isDropOnChild(dcl, dropLocation)) {
524               canDrop = false;
525             }
526             if (canDrop) {
527               dropTargetComponent = targetComponent;
528               dtde.acceptDrag(dtde.getDropAction());
529             }
530           }
531         }
532         if (!canDrop) {
533           dtde.rejectDrag();
534         }
535         setDropTargetComponent(dropTargetComponent);
536       }
537       catch (Exception e) {
538         LOG.error(e);
539       }
540     }
541
542     public void dragExit(DropTargetEvent dte) {
543       setDropTargetComponent(null);
544     }
545
546     public void drop(DropTargetDropEvent dtde) {
547       try {
548         final DraggedComponentList dcl = DraggedComponentList.fromTransferable(dtde.getTransferable());
549         ComponentItem componentItem = SimpleTransferable.getData(dtde.getTransferable(), ComponentItem.class);
550         if (dcl != null || componentItem != null) {
551           final TreePath path = getPathForLocation((int) dtde.getLocation().getX(),
552                                                    (int) dtde.getLocation().getY());
553           final RadComponent targetComponent = getComponentFromPath(path);
554           if (!myEditor.ensureEditable()) return;
555           if (targetComponent instanceof RadContainer) {
556             final ComponentDropLocation dropLocation = ((RadContainer)targetComponent).getDropLocation(null);
557             if (dcl != null) {
558               if (!FormEditingUtil.isDropOnChild(dcl, dropLocation)) {
559                 RadComponent[] components = dcl.getComponents().toArray(new RadComponent [dcl.getComponents().size()]);
560                 RadContainer[] originalParents = dcl.getOriginalParents();
561                 final GridConstraints[] originalConstraints = dcl.getOriginalConstraints();
562                 for(int i=0; i<components.length; i++) {
563                   originalParents [i].removeComponent(components [i]);
564                 }
565                 dropLocation.processDrop(myEditor, components, null, dcl);
566                 for (int i = 0; i < originalConstraints.length; i++) {
567                   if (originalParents[i].getLayoutManager().isGrid()) {
568                     FormEditingUtil.deleteEmptyGridCells(originalParents[i], originalConstraints[i]);
569                   }
570                 }
571               }
572             }
573             else {
574               new InsertComponentProcessor(myEditor).processComponentInsert(componentItem, dropLocation);
575             }
576           }
577           myEditor.refreshAndSave(true);
578         }
579         setDropTargetComponent(null);
580       }
581       catch (Exception e) {
582         LOG.error(e);
583       }
584     }
585   }
586
587   private static class MyDeleteProvider implements DeleteProvider {
588     private GuiEditor myEditor;
589
590     public void setEditor(final GuiEditor editor) {
591       myEditor = editor;
592     }
593
594     public void deleteElement(@NotNull DataContext dataContext) {
595       if (myEditor != null) {
596         LwInspectionSuppression[] suppressions = LW_INSPECTION_SUPPRESSION_ARRAY_DATA_KEY.getData(dataContext);
597         if (suppressions != null) {
598           if (!myEditor.ensureEditable()) return;
599           for(LwInspectionSuppression suppression: suppressions) {
600             myEditor.getRootContainer().removeInspectionSuppression(suppression);
601           }
602           myEditor.refreshAndSave(true);
603         }
604         else {
605           DeleteProvider baseProvider = (DeleteProvider) myEditor.getData(PlatformDataKeys.DELETE_ELEMENT_PROVIDER.getName());
606           if (baseProvider != null) {
607             baseProvider.deleteElement(dataContext);
608           }
609         }
610       }
611     }
612
613     public boolean canDeleteElement(@NotNull DataContext dataContext) {
614       if (myEditor != null) {
615         LwInspectionSuppression[] suppressions = LW_INSPECTION_SUPPRESSION_ARRAY_DATA_KEY.getData(dataContext);
616         if (suppressions != null) {
617           return true;
618         }
619         DeleteProvider baseProvider = (DeleteProvider) myEditor.getData(PlatformDataKeys.DELETE_ELEMENT_PROVIDER.getName());
620         if (baseProvider != null) {
621           return baseProvider.canDeleteElement(dataContext);
622         }
623       }
624       return false;
625     }
626   }
627 }