JPanel () { myTreeRoot = new CheckedTreeNode(null); myTree = new LiveTemplateTree(new CheckboxTree.CheckboxTreeCellRenderer() { @Override public void customizeRenderer(final JTree tree, Object value, final boolean selected, final boolean expanded, final boolean leaf, final int row, final boolean hasFocus) { if (!(value instanceof DefaultMutableTreeNode)) return; value = ((DefaultMutableTreeNode)value).getUserObject(); if (value instanceof TemplateImpl template) { TemplateImpl defaultTemplate = TemplateSettings.getInstance().getDefaultTemplate(template); LiveTemplateContextsSnapshot allContexts = LiveTemplateContextService.getInstance().getSnapshot(); Color fgColor = defaultTemplate == null || templatesDiffer(allContexts, template, defaultTemplate) ? JBColor.BLUE : null; getTextRenderer().append(template.getKey(), new SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, fgColor)); String description = template.getDescription(); if (StringUtil.isNotEmpty(description)) { getTextRenderer().append(" (" + description + ")", SimpleTextAttributes.GRAY_ATTRIBUTES); } } else if (value instanceof TemplateGroup) { getTextRenderer().append(((TemplateGroup)value).getName(), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); } } }, myTreeRoot, this); myTree.setRootVisible(false); myTree.setShowsRootHandles(true); myTree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); myTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener(){ @Override public void valueChanged(@NotNull final TreeSelectionEvent e) { TemplateSettings templateSettings = TemplateSettings.getInstance(); TemplateImpl template = getTemplate(getSingleSelectedIndex()); if (template != null) { templateSettings.setLastSelectedTemplate(template.getGroupName(), template.getKey()); } else { templateSettings.setLastSelectedTemplate(null, null); showEmptyCard(); } if (myUpdateNeeded) { myAlarm.cancelAllRequests(); myAlarm.addRequest(() -> updateTemplateDetails(false, false), 100); } } }); myTree.registerKeyboardAction(new ActionListener() { @Override public void actionPerformed(@Nullable ActionEvent event) { myCurrentTemplateEditor.focusKey(); } }, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), JComponent.WHEN_FOCUSED); installPopup(); DnDSupport.createBuilder(myTree) .setBeanProvider(dnDActionInfo -> { Point point = dnDActionInfo.getPoint(); if (myTree.getPathForLocation(point.x, point.y) == null) return null; Map<TemplateImpl, DefaultMutableTreeNode> templates = getSelectedTemplates(); return !templates.isEmpty() ? new DnDDragStartBean(templates) : null; }). setDisposableParent(this) .setTargetChecker(new DnDTargetChecker() { @Override public boolean update(DnDEvent event) { @SuppressWarnings("unchecked") Set<String> oldGroupNames = getAllGroups((Map<TemplateImpl, DefaultMutableTreeNode>)event.getAttachedObject()); TemplateGroup group = getDropGroup(event); boolean differentGroup = group != null && !oldGroupNames.contains(group.getName()); event.setDropPossible(differentGroup, ""); return true; } }) .setDropHandler(new DnDDropHandler() { @Override public void drop(DnDEvent event) { //noinspection unchecked moveTemplates((Map<TemplateImpl, DefaultMutableTreeNode>)event.getAttachedObject(), Objects.requireNonNull(getDropGroup(event)).getName()); } }) .setImageProvider(dnDActionInfo -> { Point point = dnDActionInfo.getPoint(); TreePath path = myTree.getPathForLocation(point.x, point.y); return path == null ? null : new DnDImage(DnDAwareTree.getDragImage(myTree, path, point).first); }) .install(); if (myTemplateGroups.size() > 0) { myTree.setSelectionInterval(0, 0); } return initToolbar().createPanel(); }