/* * Copyright 2022 The IdeaVim authors * * Use of this source code is governed by an MIT-style * license that can be found in the LICENSE.txt file or at * https://opensource.org/licenses/MIT. */ package com.maddyhome.idea.vim.group; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; import com.intellij.openapi.fileEditor.impl.EditorComposite; import com.intellij.openapi.fileEditor.impl.EditorWindow; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.concurrency.annotations.RequiresReadLock; import com.maddyhome.idea.vim.VimPlugin; import com.maddyhome.idea.vim.api.ExecutionContext; import com.maddyhome.idea.vim.helper.MessageHelper; import com.maddyhome.idea.vim.helper.RWLockLabel; import com.maddyhome.idea.vim.newapi.IjExecutionContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.util.List; import java.util.*; public class WindowGroup extends WindowGroupBase { @Override public void closeCurrentWindow(@NotNull ExecutionContext context) { final FileEditorManagerEx fileEditorManager = getFileEditorManager((DataContext)context.getContext()); final EditorWindow window = fileEditorManager.getSplitters().getCurrentWindow(); if (window != null) { window.closeAllExcept(null); } } @Override public void closeAllExceptCurrent(@NotNull ExecutionContext context) { final FileEditorManagerEx fileEditorManager = getFileEditorManager(((DataContext)context.getContext())); final EditorWindow current = fileEditorManager.getCurrentWindow(); for (final EditorWindow window : fileEditorManager.getWindows()) { if (window != current) { window.closeAllExcept(null); } } } public void closeAllExceptCurrentTab(@NotNull DataContext context) { final EditorWindow currentWindow = getFileEditorManager(context).getCurrentWindow(); currentWindow.closeAllExcept(currentWindow.getSelectedFile()); } public void closeAll(@NotNull ExecutionContext context) { getFileEditorManager(((IjExecutionContext) context).getContext()).closeAllFiles(); } @Override public void selectNextWindow(@NotNull ExecutionContext context) { final FileEditorManagerEx fileEditorManager = getFileEditorManager(((DataContext)context.getContext())); final EditorWindow current = fileEditorManager.getCurrentWindow(); if (current != null) { fileEditorManager.getNextWindow(current).setAsCurrentWindow(true); } } @Override public void selectPreviousWindow(@NotNull ExecutionContext context) { final FileEditorManagerEx fileEditorManager = getFileEditorManager(((DataContext)context.getContext())); final EditorWindow current = fileEditorManager.getCurrentWindow(); if (current != null) { fileEditorManager.getPrevWindow(current).setAsCurrentWindow(true); } } @Override public void selectWindow(@NotNull ExecutionContext context, int index) { final FileEditorManagerEx fileEditorManager = getFileEditorManager(((DataContext)context.getContext())); final EditorWindow[] windows = fileEditorManager.getWindows(); if (index - 1 < windows.length) { windows[index - 1].setAsCurrentWindow(true); } } @Override public void splitWindowHorizontal(@NotNull ExecutionContext context, @NotNull String filename) { splitWindow(SwingConstants.HORIZONTAL, (DataContext)context.getContext(), filename); } @Override public void splitWindowVertical(@NotNull ExecutionContext context, @NotNull String filename) { splitWindow(SwingConstants.VERTICAL, (DataContext)context.getContext(), filename); } @Override @RWLockLabel.Readonly @RequiresReadLock public void selectWindowInRow(@NotNull ExecutionContext context, int relativePosition, boolean vertical) { final FileEditorManagerEx fileEditorManager = getFileEditorManager(((DataContext)context.getContext())); final EditorWindow currentWindow = fileEditorManager.getCurrentWindow(); if (currentWindow != null) { final EditorWindow[] windows = fileEditorManager.getWindows(); final List<EditorWindow> row = findWindowsInRow(currentWindow, Arrays.asList(windows), vertical); selectWindow(currentWindow, row, relativePosition); } } private void selectWindow(@NotNull EditorWindow currentWindow, @NotNull List<EditorWindow> windows, int relativePosition) { final int pos = windows.indexOf(currentWindow); final int selected = pos + relativePosition; final int normalized = Math.max(0, Math.min(selected, windows.size() - 1)); windows.get(normalized).setAsCurrentWindow(true); } private static @NotNull List<EditorWindow> findWindowsInRow(@NotNull EditorWindow anchor, @NotNull List<EditorWindow> windows, final boolean vertical) { final Rectangle anchorRect = getEditorWindowRectangle(anchor); if (anchorRect != null) { final List<EditorWindow> result = new ArrayList<>(); final double coord = vertical ? anchorRect.getX() : anchorRect.getY(); for (EditorWindow window : windows) { final Rectangle rect = getEditorWindowRectangle(window); if (rect != null) { final double min = vertical ? rect.getX() : rect.getY(); final double max = min + (vertical ? rect.getWidth() : rect.getHeight()); if (coord >= min && coord <= max) { result.add(window); } } } result.sort((window1, window2) -> { final Rectangle rect1 = getEditorWindowRectangle(window1); final Rectangle rect2 = getEditorWindowRectangle(window2); if (rect1 != null && rect2 != null) { final double diff = vertical ? (rect1.getY() - rect2.getY()) : (rect1.getX() - rect2.getX()); return diff < 0 ? -1 : diff > 0 ? 1 : 0; } return 0; }); return result; } return Collections.singletonList(anchor); } private static @NotNull FileEditorManagerEx getFileEditorManager(@NotNull DataContext context) { final Project project = PlatformDataKeys.PROJECT.getData(context); return FileEditorManagerEx.getInstanceEx(Objects.requireNonNull(project)); } private void splitWindow(int orientation, @NotNull DataContext context, @NotNull String filename) { final Project project = PlatformDataKeys.PROJECT.getData(context); if (project == null) return; final FileEditorManagerEx fileEditorManager = FileEditorManagerEx.getInstanceEx(project); VirtualFile virtualFile = null; if (filename.length() > 0) { virtualFile = VimPlugin.getFile().findFile(filename, project); if (virtualFile == null) { VimPlugin.showMessage(MessageHelper.message("could.not.find.file.0", filename)); return; } } final EditorWindow editorWindow = fileEditorManager.getSplitters().getCurrentWindow(); if (editorWindow != null) { editorWindow.split(orientation, true, virtualFile, true); } } private static @Nullable Rectangle getEditorWindowRectangle(@NotNull EditorWindow window) { final EditorComposite editor = window.getSelectedComposite(); if (editor != null) { final Point point = editor.getComponent().getLocationOnScreen(); final Dimension dimension = editor.getComponent().getSize(); return new Rectangle(point, dimension); } return null; } }