public void resetFrom(TemplateImpl another) {
    removeAllParsed();
    toParseSegments = another.toParseSegments;

    myKey = another.getKey();
    myString = another.myString;
    myTemplateText = another.myTemplateText;
    myGroupName = another.myGroupName;
    myId = another.myId;
    myDescription = another.myDescription;
    myShortcutChar = another.myShortcutChar;
    isToReformat = another.isToReformat;
    isToShortenLongNames = another.isToShortenLongNames;
    myIsInline = another.myIsInline;
    myTemplateContext = another.myTemplateContext.createCopy();
    isDeactivated = another.isDeactivated;
    for (Property property : Property.values()) {
      boolean value = another.getValue(property);
      if (value != Template.getDefaultValue(property)) {
        setValue(property, value);
      }
    }
    for (Variable variable : another.myVariables) {
      addVariable(
          variable.getName(),
          variable.getExpressionString(),
          variable.getDefaultValueString(),
          variable.isAlwaysStopAt());
    }
  }
 private static int getTemplateStart(
     TemplateImpl template, String argument, int caretOffset, CharSequence text) {
   int templateStart;
   if (argument == null) {
     templateStart = caretOffset - template.getKey().length();
   } else {
     int argOffset = getArgumentOffset(caretOffset, argument, text);
     templateStart = argOffset - template.getKey().length();
   }
   return templateStart;
 }
  private static List<TemplateImpl> listApplicableTemplates(PsiFile file, int offset) {
    Set<TemplateContextType> contextTypes =
        TemplateManagerImpl.getApplicableContextTypes(file, offset);

    final ArrayList<TemplateImpl> result = ContainerUtil.newArrayList();
    for (final TemplateImpl template : TemplateSettings.getInstance().getTemplates()) {
      if (!template.isDeactivated() && TemplateManagerImpl.isApplicable(template, contextTypes)) {
        result.add(template);
      }
    }
    return result;
  }
  public static List<TemplateImpl> listApplicableTemplates(
      PsiFile file, int offset, boolean selectionOnly) {
    Set<TemplateContextType> contextTypes = getApplicableContextTypes(file, offset);

    final ArrayList<TemplateImpl> result = ContainerUtil.newArrayList();
    for (final TemplateImpl template : TemplateSettings.getInstance().getTemplates()) {
      if (!template.isDeactivated()
          && (!selectionOnly || template.isSelectionTemplate())
          && isApplicable(template, contextTypes)) {
        result.add(template);
      }
    }
    return result;
  }
  @Override
  public void performPaste(@NotNull DataContext dataContext) {
    TemplateGroup group = myConfigurable.getSingleSelectedGroup();
    assert group != null;

    String buffer = CopyPasteManager.getInstance().getContents(DataFlavor.stringFlavor);
    assert buffer != null;

    try {
      for (Element templateElement :
          JDOMUtil.load(new StringReader("<root>" + buffer + "</root>"))
              .getChildren(TemplateSettings.TEMPLATE)) {
        TemplateImpl template =
            TemplateSettings.readTemplateFromElement(
                group.getName(), templateElement, getClass().getClassLoader());
        while (group.containsTemplate(template.getKey(), template.getId())) {
          template.setKey(template.getKey() + "1");
          if (template.getId() != null) {
            template.setId(template.getId() + "1");
          }
        }
        myConfigurable.addTemplate(template);
      }
    } catch (JDOMException ignore) {
    } catch (IOException ignore) {
    }
  }
 @Override
 protected void onNodeStateChanged(final CheckedTreeNode node) {
   Object obj = node.getUserObject();
   if (obj instanceof TemplateImpl) {
     ((TemplateImpl) obj).setDeactivated(!node.isChecked());
   }
 }
 public static boolean isApplicable(TemplateImpl template, Set<TemplateContextType> contextTypes) {
   for (TemplateContextType type : contextTypes) {
     if (template.getTemplateContext().isEnabled(type)) {
       return true;
     }
   }
   return false;
 }
  private static List<TemplateImpl> filterApplicableCandidates(
      PsiFile file, int caretOffset, List<TemplateImpl> candidates) {
    if (candidates.isEmpty()) {
      return candidates;
    }

    PsiFile copy =
        insertDummyIdentifierIfNeeded(
            file, caretOffset, caretOffset, CompletionUtil.DUMMY_IDENTIFIER_TRIMMED);

    List<TemplateImpl> result = new ArrayList<TemplateImpl>();
    for (TemplateImpl candidate : candidates) {
      if (isApplicable(copy, caretOffset - candidate.getKey().length(), candidate)) {
        result.add(candidate);
      }
    }
    return result;
  }
 public void startTemplateWithPrefix(
     final Editor editor,
     final TemplateImpl template,
     @Nullable final PairProcessor<String, String> processor,
     @Nullable String argument) {
   final int caretOffset = editor.getCaretModel().getOffset();
   String key = template.getKey();
   int startOffset = caretOffset - key.length();
   if (argument != null) {
     if (!isDelimiter(key.charAt(key.length() - 1))) {
       // pass space
       startOffset--;
     }
     startOffset -= argument.length();
   }
   startTemplateWithPrefix(editor, template, startOffset, processor, argument);
 }
 public boolean contextsEqual(TemplateImpl defaultTemplate) {
   return getTemplateContext().getDifference(defaultTemplate.getTemplateContext()).isEmpty();
 }
 @Override
 public TemplateImpl copy() {
   TemplateImpl template = new TemplateImpl(myKey, myString, myGroupName);
   template.resetFrom(this);
   return template;
 }
  @Override
  public void actionPerformed(AnActionEvent e) {
    DataContext dataContext = e.getDataContext();
    final Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
    PsiFile file = CommonDataKeys.PSI_FILE.getData(dataContext);

    final Project project = file.getProject();
    PsiDocumentManager.getInstance(project).commitAllDocuments();

    final TextRange selection =
        new TextRange(
            editor.getSelectionModel().getSelectionStart(),
            editor.getSelectionModel().getSelectionEnd());
    PsiElement current = file.findElementAt(selection.getStartOffset());
    int startOffset = selection.getStartOffset();
    while (current instanceof PsiWhiteSpace) {
      current = current.getNextSibling();
      if (current == null) break;
      startOffset = current.getTextRange().getStartOffset();
    }

    if (startOffset >= selection.getEndOffset()) startOffset = selection.getStartOffset();

    final PsiElement[] psiElements =
        PsiTreeUtil.collectElements(
            file,
            new PsiElementFilter() {
              @Override
              public boolean isAccepted(PsiElement element) {
                return selection.contains(element.getTextRange())
                    && element.getReferences().length > 0;
              }
            });

    final Document document =
        EditorFactory.getInstance()
            .createDocument(
                editor.getDocument().getText().substring(startOffset, selection.getEndOffset()));
    final boolean isXml = file.getLanguage().is(StdLanguages.XML);
    final int offsetDelta = startOffset;
    new WriteCommandAction.Simple(project, (String) null) {
      @Override
      protected void run() throws Throwable {
        Map<RangeMarker, String> rangeToText = new HashMap<RangeMarker, String>();

        for (PsiElement element : psiElements) {
          for (PsiReference reference : element.getReferences()) {
            if (!(reference instanceof PsiQualifiedReference)
                || ((PsiQualifiedReference) reference).getQualifier() == null) {
              String canonicalText = reference.getCanonicalText();
              LOG.assertTrue(canonicalText != null, reference.getClass());
              TextRange referenceRange = reference.getRangeInElement();
              final TextRange elementTextRange = element.getTextRange();
              LOG.assertTrue(elementTextRange != null, elementTextRange);
              final TextRange range =
                  elementTextRange.cutOut(referenceRange).shiftRight(-offsetDelta);
              final String oldText = document.getText(range);
              // workaround for Java references: canonicalText contains generics, and we need to cut
              // them off because otherwise
              // they will be duplicated
              int pos = canonicalText.indexOf('<');
              if (pos > 0 && !oldText.contains("<")) {
                canonicalText = canonicalText.substring(0, pos);
              }
              if (isXml) { // strip namespace prefixes
                pos = canonicalText.lastIndexOf(':');
                if (pos >= 0 && pos < canonicalText.length() - 1 && !oldText.contains(":")) {
                  canonicalText = canonicalText.substring(pos + 1);
                }
              }
              if (!canonicalText.equals(oldText)) {
                rangeToText.put(document.createRangeMarker(range), canonicalText);
              }
            }
          }
        }

        for (Map.Entry<RangeMarker, String> entry : rangeToText.entrySet()) {
          document.replaceString(
              entry.getKey().getStartOffset(), entry.getKey().getEndOffset(), entry.getValue());
        }
      }
    }.execute();

    final TemplateImpl template =
        new TemplateImpl(
            TemplateListPanel.ABBREVIATION, document.getText(), TemplateSettings.USER_GROUP_NAME);
    template.setToReformat(true);

    PsiFile copy;
    AccessToken token = WriteAction.start();
    try {
      copy = TemplateManagerImpl.insertDummyIdentifier(editor, file);
    } finally {
      token.finish();
    }
    Set<TemplateContextType> applicable =
        TemplateManagerImpl.getApplicableContextTypes(copy, startOffset);

    for (TemplateContextType contextType : TemplateManagerImpl.getAllContextTypes()) {
      template.getTemplateContext().setEnabled(contextType, applicable.contains(contextType));
    }

    final LiveTemplatesConfigurable configurable = new LiveTemplatesConfigurable();
    ShowSettingsUtil.getInstance()
        .editConfigurable(
            project, configurable, () -> configurable.getTemplateListPanel().addTemplate(template));
  }