private EditorHighlighter createHighlighter() {
    if (myTemplate != null && myProject != null && myVelocityFileType != FileTypes.UNKNOWN) {
      return EditorHighlighterFactory.getInstance()
          .createEditorHighlighter(
              myProject, new LightVirtualFile("aaa." + myTemplate.getExtension() + ".ft"));
    }

    FileType fileType = null;
    if (myTemplate != null) {
      fileType = FileTypeManager.getInstance().getFileTypeByExtension(myTemplate.getExtension());
    }
    if (fileType == null) {
      fileType = FileTypes.PLAIN_TEXT;
    }
    SyntaxHighlighter originalHighlighter =
        SyntaxHighlighterFactory.getSyntaxHighlighter(fileType, null, null);
    if (originalHighlighter == null) originalHighlighter = new PlainSyntaxHighlighter();
    return new LexerEditorHighlighter(
        new TemplateHighlighter(originalHighlighter),
        EditorColorsManager.getInstance().getGlobalScheme());
  }
public class FileTemplateConfigurable implements Configurable, Configurable.NoScroll {
  private static final Logger LOG =
      Logger.getInstance("#com.intellij.ide.fileTemplates.impl.FileTemplateConfigurable");
  @NonNls private static final String EMPTY_HTML = "<html></html>";
  @NonNls private static final String CONTENT_TYPE_PLAIN = "text/plain";

  private JPanel myMainPanel;
  private FileTemplate myTemplate;
  private PsiFile myFile;
  private Editor myTemplateEditor;
  private JTextField myNameField;
  private JTextField myExtensionField;
  private JCheckBox myAdjustBox;
  private JPanel myTopPanel;
  private JEditorPane myDescriptionComponent;
  private boolean myModified = false;
  private URL myDefaultDescriptionUrl;
  private final Project myProject;

  private final List<ChangeListener> myChangeListeners =
      ContainerUtil.createLockFreeCopyOnWriteList();;
  private Splitter mySplitter;
  private final FileType myVelocityFileType =
      FileTypeManager.getInstance().getFileTypeByExtension("ft");
  private JPanel myDescriptionPanel;

  public FileTemplateConfigurable() {
    Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext());
    myProject = project != null ? project : ProjectManager.getInstance().getDefaultProject();
  }

  public FileTemplate getTemplate() {
    return myTemplate;
  }

  public void setTemplate(FileTemplate template, URL defaultDescription) {
    myDefaultDescriptionUrl = defaultDescription;
    myTemplate = template;
    if (myMainPanel != null) {
      reset();
      myNameField.selectAll();
      myExtensionField.selectAll();
    }
  }

  public void setShowInternalMessage(String message) {
    if (message == null) {
      myTopPanel.removeAll();
      myTopPanel.add(
          new JLabel(IdeBundle.message("label.name")),
          new GridBagConstraints(
              0,
              0,
              1,
              1,
              0.0,
              0.0,
              GridBagConstraints.CENTER,
              GridBagConstraints.NONE,
              new Insets(0, 0, 0, 2),
              0,
              0));
      myTopPanel.add(
          myNameField,
          new GridBagConstraints(
              1,
              0,
              1,
              1,
              1.0,
              0.0,
              GridBagConstraints.CENTER,
              GridBagConstraints.HORIZONTAL,
              new Insets(0, 2, 0, 2),
              0,
              0));
      myTopPanel.add(
          new JLabel(IdeBundle.message("label.extension")),
          new GridBagConstraints(
              2,
              0,
              1,
              1,
              0.0,
              0.0,
              GridBagConstraints.CENTER,
              GridBagConstraints.NONE,
              new Insets(0, 2, 0, 2),
              0,
              0));
      myTopPanel.add(
          myExtensionField,
          new GridBagConstraints(
              3,
              0,
              1,
              1,
              .3,
              0.0,
              GridBagConstraints.CENTER,
              GridBagConstraints.HORIZONTAL,
              new Insets(0, 2, 0, 0),
              0,
              0));
      myExtensionField.setColumns(7);
    } else {
      myTopPanel.removeAll();
      myTopPanel.add(
          new JLabel(message),
          new GridBagConstraints(
              0,
              0,
              4,
              1,
              1.0,
              0.0,
              GridBagConstraints.WEST,
              GridBagConstraints.HORIZONTAL,
              new Insets(0, 0, 0, 0),
              0,
              0));
      myTopPanel.add(
          Box.createVerticalStrut(myNameField.getPreferredSize().height),
          new GridBagConstraints(
              4,
              0,
              1,
              1,
              0.0,
              0.0,
              GridBagConstraints.WEST,
              GridBagConstraints.HORIZONTAL,
              new Insets(0, 0, 0, 0),
              0,
              0));
    }
    myMainPanel.revalidate();
    myTopPanel.repaint();
  }

  public void setShowAdjustCheckBox(boolean show) {
    myAdjustBox.setEnabled(show);
  }

  @Override
  public String getDisplayName() {
    return IdeBundle.message("title.file.templates");
  }

  @Override
  public String getHelpTopic() {
    return null;
  }

  @Override
  public JComponent createComponent() {
    myMainPanel = new JPanel(new GridBagLayout());
    myNameField = new JTextField();
    myExtensionField = new JTextField();
    mySplitter = new Splitter(true, 0.4f);

    myTemplateEditor = createEditor();

    myDescriptionComponent = new JEditorPane(UIUtil.HTML_MIME, EMPTY_HTML);
    myDescriptionComponent.setEditable(false);

    myAdjustBox = new JCheckBox(IdeBundle.message("checkbox.reformat.according.to.style"));
    myTopPanel = new JPanel(new GridBagLayout());

    myDescriptionPanel = new JPanel(new GridBagLayout());
    myDescriptionPanel.add(
        SeparatorFactory.createSeparator(IdeBundle.message("label.description"), null),
        new GridBagConstraints(
            0,
            0,
            1,
            1,
            0.0,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(0, 0, 2, 0),
            0,
            0));
    myDescriptionPanel.add(
        ScrollPaneFactory.createScrollPane(myDescriptionComponent),
        new GridBagConstraints(
            0,
            1,
            1,
            1,
            1.0,
            1.0,
            GridBagConstraints.CENTER,
            GridBagConstraints.BOTH,
            new Insets(2, 0, 0, 0),
            0,
            0));

    myMainPanel.add(
        myTopPanel,
        new GridBagConstraints(
            0,
            0,
            4,
            1,
            1.0,
            0.0,
            GridBagConstraints.CENTER,
            GridBagConstraints.HORIZONTAL,
            new Insets(0, 0, 2, 0),
            0,
            0));
    myMainPanel.add(
        myAdjustBox,
        new GridBagConstraints(
            0,
            1,
            4,
            1,
            0.0,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(2, 0, 2, 0),
            0,
            0));
    myMainPanel.add(
        mySplitter,
        new GridBagConstraints(
            0,
            2,
            4,
            1,
            1.0,
            1.0,
            GridBagConstraints.CENTER,
            GridBagConstraints.BOTH,
            new Insets(2, 0, 0, 0),
            0,
            0));

    mySplitter.setSecondComponent(myDescriptionPanel);
    setShowInternalMessage(null);

    myNameField.addFocusListener(
        new FocusAdapter() {
          @Override
          public void focusLost(FocusEvent e) {
            onNameChanged();
          }
        });
    myExtensionField.addFocusListener(
        new FocusAdapter() {
          @Override
          public void focusLost(FocusEvent e) {
            onNameChanged();
          }
        });
    myMainPanel.setPreferredSize(new Dimension(400, 300));
    return myMainPanel;
  }

  private Editor createEditor() {
    EditorFactory editorFactory = EditorFactory.getInstance();
    Document doc =
        myFile == null
            ? editorFactory.createDocument(myTemplate == null ? "" : myTemplate.getText())
            : PsiDocumentManager.getInstance(myFile.getProject()).getDocument(myFile);
    Editor editor =
        myProject == null
            ? editorFactory.createEditor(doc)
            : editorFactory.createEditor(doc, myProject);

    EditorSettings editorSettings = editor.getSettings();
    editorSettings.setVirtualSpace(false);
    editorSettings.setLineMarkerAreaShown(false);
    editorSettings.setIndentGuidesShown(false);
    editorSettings.setLineNumbersShown(false);
    editorSettings.setFoldingOutlineShown(false);
    editorSettings.setAdditionalColumnsCount(3);
    editorSettings.setAdditionalLinesCount(3);

    EditorColorsScheme scheme = editor.getColorsScheme();
    scheme.setColor(EditorColors.CARET_ROW_COLOR, null);

    editor
        .getDocument()
        .addDocumentListener(
            new DocumentAdapter() {
              @Override
              public void documentChanged(DocumentEvent e) {
                onTextChanged();
              }
            });

    ((EditorEx) editor).setHighlighter(createHighlighter());
    mySplitter.setFirstComponent(editor.getComponent());
    return editor;
  }

  private void onTextChanged() {
    myModified = true;
  }

  public String getNameValue() {
    return myNameField.getText();
  }

  public String getExtensionValue() {
    return myExtensionField.getText();
  }

  private void onNameChanged() {
    ChangeEvent event = new ChangeEvent(this);
    for (ChangeListener changeListener : myChangeListeners) {
      changeListener.stateChanged(event);
    }
  }

  public void addChangeListener(ChangeListener listener) {
    if (!myChangeListeners.contains(listener)) {
      myChangeListeners.add(listener);
    }
  }

  public void removeChangeListener(ChangeListener listener) {
    myChangeListeners.remove(listener);
  }

  @Override
  public boolean isModified() {
    if (myModified) {
      return true;
    }
    String name = (myTemplate == null) ? "" : myTemplate.getName();
    String extension = (myTemplate == null) ? "" : myTemplate.getExtension();
    if (!Comparing.equal(name, myNameField.getText())) {
      return true;
    }
    if (!Comparing.equal(extension, myExtensionField.getText())) {
      return true;
    }
    if (myTemplate != null) {
      if (myTemplate.isReformatCode() != myAdjustBox.isSelected()) {
        return true;
      }
    }
    return false;
  }

  @Override
  public void apply() throws ConfigurationException {
    if (myTemplate != null) {
      myTemplate.setText(myTemplateEditor.getDocument().getText());
      String name = myNameField.getText();
      String extension = myExtensionField.getText();
      int lastDotIndex = extension.lastIndexOf(".");
      if (lastDotIndex >= 0) {
        name += extension.substring(0, lastDotIndex + 1);
        extension = extension.substring(lastDotIndex + 1);
      }
      if (name.length() == 0 || !isValidFilename(name + "." + extension)) {
        throw new ConfigurationException(
            IdeBundle.message("error.invalid.template.file.name.or.extension"));
      }
      myTemplate.setName(name);
      myTemplate.setExtension(extension);
      myTemplate.setReformatCode(myAdjustBox.isSelected());
    }
    myModified = false;
  }

  // TODO: needs to be generalized someday for other profiles
  private static boolean isValidFilename(final String filename) {
    if (filename.contains("/") || filename.contains("\\") || filename.contains(":")) {
      return false;
    }
    final File tempFile = new File(FileUtil.getTempDirectory() + File.separator + filename);
    return FileUtil.ensureCanCreateFile(tempFile);
  }

  @Override
  public void reset() {
    final String text = (myTemplate == null) ? "" : myTemplate.getText();
    String name = (myTemplate == null) ? "" : myTemplate.getName();
    String extension = (myTemplate == null) ? "" : myTemplate.getExtension();
    String description = (myTemplate == null) ? "" : myTemplate.getDescription();

    if ((description.length() == 0) && (myDefaultDescriptionUrl != null)) {
      try {
        description = UrlUtil.loadText(myDefaultDescriptionUrl);
      } catch (IOException e) {
        LOG.error(e);
      }
    }

    EditorFactory.getInstance().releaseEditor(myTemplateEditor);
    myFile = createFile(text, name);
    myTemplateEditor = createEditor();

    boolean adjust = (myTemplate != null) && myTemplate.isReformatCode();
    myNameField.setText(name);
    myExtensionField.setText(extension);
    myAdjustBox.setSelected(adjust);
    String desc = description.length() > 0 ? description : EMPTY_HTML;

    // [myakovlev] do not delete these stupid lines! Or you get Exception!
    myDescriptionComponent.setContentType(CONTENT_TYPE_PLAIN);
    myDescriptionComponent.setEditable(true);
    myDescriptionComponent.setText(desc);
    myDescriptionComponent.setContentType(UIUtil.HTML_MIME);
    myDescriptionComponent.setText(desc);
    myDescriptionComponent.setCaretPosition(0);
    myDescriptionComponent.setEditable(false);

    myDescriptionPanel.setVisible(StringUtil.isNotEmpty(description));

    myNameField.setEditable((myTemplate != null) && (!myTemplate.isDefault()));
    myExtensionField.setEditable((myTemplate != null) && (!myTemplate.isDefault()));
    myModified = false;
  }

  @Nullable
  private PsiFile createFile(final String text, final String name) {
    if (myTemplate == null || myProject == null) return null;

    final FileType fileType = myVelocityFileType;
    if (fileType == FileTypes.UNKNOWN) return null;

    final PsiFile file =
        PsiFileFactory.getInstance(myProject)
            .createFileFromText(name + ".txt.ft", fileType, text, 0, true);
    file.getViewProvider()
        .putUserData(
            FileTemplateManager.DEFAULT_TEMPLATE_PROPERTIES,
            FileTemplateManager.getInstance().getDefaultProperties(myProject));
    return file;
  }

  @Override
  public void disposeUIResources() {
    myMainPanel = null;
    if (myTemplateEditor != null) {
      EditorFactory.getInstance().releaseEditor(myTemplateEditor);
      myTemplateEditor = null;
    }
    myFile = null;
  }

  private EditorHighlighter createHighlighter() {
    if (myTemplate != null && myProject != null && myVelocityFileType != FileTypes.UNKNOWN) {
      return EditorHighlighterFactory.getInstance()
          .createEditorHighlighter(
              myProject, new LightVirtualFile("aaa." + myTemplate.getExtension() + ".ft"));
    }

    FileType fileType = null;
    if (myTemplate != null) {
      fileType = FileTypeManager.getInstance().getFileTypeByExtension(myTemplate.getExtension());
    }
    if (fileType == null) {
      fileType = FileTypes.PLAIN_TEXT;
    }
    SyntaxHighlighter originalHighlighter =
        SyntaxHighlighterFactory.getSyntaxHighlighter(fileType, null, null);
    if (originalHighlighter == null) originalHighlighter = new PlainSyntaxHighlighter();
    return new LexerEditorHighlighter(
        new TemplateHighlighter(originalHighlighter),
        EditorColorsManager.getInstance().getGlobalScheme());
  }

  private static final TokenSet TOKENS_TO_MERGE = TokenSet.create(FileTemplateTokenType.TEXT);

  private static class TemplateHighlighter extends SyntaxHighlighterBase {
    private final Lexer myLexer;
    private final SyntaxHighlighter myOriginalHighlighter;

    public TemplateHighlighter(SyntaxHighlighter original) {
      myOriginalHighlighter = original;
      Lexer originalLexer = original.getHighlightingLexer();
      Lexer templateLexer = new FlexAdapter(new FileTemplateTextLexer());
      templateLexer = new MergingLexerAdapter(templateLexer, TOKENS_TO_MERGE);

      myLexer =
          new CompositeLexer(originalLexer, templateLexer) {
            @Override
            protected IElementType getCompositeTokenType(IElementType type1, IElementType type2) {
              if (type2 == FileTemplateTokenType.MACRO
                  || type2 == FileTemplateTokenType.DIRECTIVE) {
                return type2;
              } else {
                return type1;
              }
            }
          };
    }

    @Override
    @NotNull
    public Lexer getHighlightingLexer() {
      return myLexer;
    }

    @Override
    @NotNull
    public TextAttributesKey[] getTokenHighlights(IElementType tokenType) {
      if (tokenType == FileTemplateTokenType.MACRO) {
        return pack(
            myOriginalHighlighter.getTokenHighlights(tokenType),
            TemplateColors.TEMPLATE_VARIABLE_ATTRIBUTES);
      } else if (tokenType == FileTemplateTokenType.DIRECTIVE) {
        return pack(
            myOriginalHighlighter.getTokenHighlights(tokenType),
            TemplateColors.TEMPLATE_VARIABLE_ATTRIBUTES);
      }

      return myOriginalHighlighter.getTokenHighlights(tokenType);
    }
  }

  public void focusToNameField() {
    myNameField.selectAll();
    myNameField.requestFocus();
  }

  public void focusToExtensionField() {
    myExtensionField.selectAll();
    myExtensionField.requestFocus();
  }
}