package name.admitriev.jhelper.ui; import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiElement; import com.intellij.ui.DocumentAdapter; import com.jetbrains.cidr.lang.psi.OCBlockStatement; import com.jetbrains.cidr.lang.psi.OCFile; import com.jetbrains.cidr.lang.psi.OCFunctionDefinition; import com.jetbrains.cidr.lang.psi.visitors.OCRecursiveVisitor; import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.event.DocumentEvent; import java.util.concurrent.atomic.AtomicBoolean; public class UIUtils { private UIUtils() { } /** * Make two fields change simultaneously until the second one ({@code copy}) changed manually. * Maintains equality of {@code String.format(format, main.getText())} and {@code copy.getText()} * * Does nothing if this equality is wrong when method is called. * * @param format format for {@link String#format}. Should contain exactly one format specifier equal to %s */ public static void mirrorFields(JTextField main, JTextField copy, String format) { if (!String.format(format, main.getText()).equals(copy.getText())) { // The copy is already changed. return; } AtomicBoolean changingFirst = new AtomicBoolean(false); AtomicBoolean secondChanged = new AtomicBoolean(false); main.getDocument().addDocumentListener( new DocumentAdapter() { @Override protected void textChanged(DocumentEvent e) { if (secondChanged.get()) { return; } while (!changingFirst.compareAndSet(false, true)) { // intentionally empty } copy.setText(String.format(format, main.getText())); changingFirst.set(false); } } ); copy.getDocument().addDocumentListener( new DocumentAdapter() { @Override protected void textChanged(DocumentEvent e) { if (!changingFirst.get()) { secondChanged.set(true); } } } ); } /** * Make two fields change simultaneously until the second one ({@code copy}) changed manually. * Maintains equality of {@code main.getText()} and {@code copy.getText()} * * Does nothing if this equality is wrong when method is called. */ public static void mirrorFields(JTextField main, JTextField copy) { mirrorFields(main, copy, "%s"); } /** * Finds method @{code methodName} in @{code file} and opens it in an editor. */ public static void openMethodInEditor(Project project, OCFile file, String methodName) { new OpenFileDescriptor( project, file.getVirtualFile(), findMethodBody(file, methodName).getTextOffset() ).navigate(true); } private static PsiElement findMethodBody(OCFile file, @NotNull String method) { Ref<PsiElement> result = new Ref<>(); file.accept( new OCRecursiveVisitor() { @Override public void visitFunctionDefinition(OCFunctionDefinition ocFunctionDefinition) { if (method.equals(ocFunctionDefinition.getName())) { // continue recursion super.visitFunctionDefinition(ocFunctionDefinition); } } @Override public void visitBlockStatement(OCBlockStatement ocBlockStatement) { result.set(ocBlockStatement.getOpeningBrace().getNextSibling()); } } ); return result.get(); } }