47

I am writing an IntelliJ IDEA plugin for saving sessions of open tabs called Tab Session. This question is a follow-up of IntelliJ IDEA Plugin Development: Save groups of tabs, save them persistently and reload a set of tabs if requested by the user.

Currently, splitted windows are not supported. Therefore i want to do two things:

  1. Retrieve information about all splitted or unsplitted windows that are containers for editor tabs. I need their position and split direction (horizontal or vertical).
  2. When this information is saved and a tab session needs to be loaded, i need to reconstruct the splitted panes and their tabs exactly as they were before.

Due to the lack of documentation i am currently browsing through the source code and found this promising piece of code:

private EditorsSplitters getSplittersFromFocus() {
  return FileEditorManagerEx.getInstanceEx(myProject).getSplitters();
}

It allows me to iterate through the set of splitted windows by using EditorWindow[] windows = getSplittersFromFocus.getOrderedWindows(). They contain the editor tabs and information about their width and height. But i did not find any information about the split direction and how to reconstruct the splitted windows as they were before.

Can anyone help?

Community
  • 1
  • 1
Alp
  • 27,423
  • 26
  • 110
  • 190
  • 6
    Did you try [Open API and Plugin Development](http://devnet.jetbrains.com/community/idea/open_api_and_plugin_development) forum? I've got some of my questions regarding plugin development answered there. After one of my posts Dmitry Jemerov updated core IDEA API to help me to continue with the development. – kukido Dec 31 '13 at 22:19
  • 1
    yes i did: http://devnet.jetbrains.com/thread/451243?tstart=0 - and i totally missed that answer! thanks for reminding me – Alp Jan 01 '14 at 16:01
  • It's a bit unrelated to your question, but in what aspects does your plugin differ from the IntelliJ Context? – gizmo Feb 06 '14 at 08:30
  • 1
    What do you mean by IntelliJ Context? – Alp Feb 06 '14 at 12:54
  • Here's the link to the latest thread on the JetBrains forum: http://devnet.jetbrains.com/thread/451859 – Eric Bronnimann Feb 10 '14 at 21:59
  • Making some progress, will post an answer soon. – Alp Feb 18 '14 at 16:40
  • 2
    Looking forward to the answer... – Paul Hicks Mar 01 '14 at 17:54

1 Answers1

5

This is untested code, but as it closely resmbles the procedures inside EditorsSplitters writeExternal and writePanel functions I am positive this will work.

Presented are two methods:

  • access output of writeExternal -> should be the more stable API and offers easier access to file information
  • access components of splitter -> this way writeExternal creates it's information; sadly there is at least one protected field without getter involved (window.myPanel inside findWindowWith)
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.impl.EditorsSplitters;
import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Splitter;
import org.jdom.Element;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;

public class SplitterAction extends AnAction {

    public SplitterAction() {
        super("Splitter _Action");
    }

    private static class Info {

    }

    private static class SplitInfo extends Info {
        public Info    first;
        public Info    second;
        public boolean vertical;
        public float   proportions;
    }

    private static class FileInfo extends Info {
        public String[] fileNames;
    }

    @Override
    public void actionPerformed(AnActionEvent anActionEvent) {
        final Project project = anActionEvent.getProject();
        final FileEditorManagerImpl fileEditorManager = (FileEditorManagerImpl) FileEditorManager.getInstance(project);
        EditorsSplitters splitters = fileEditorManager.getSplitters();
        // com.intellij.openapi.fileEditor.impl.EditorsSplitters.writeExternal() and
        // com.intellij.openapi.fileEditor.impl.EditorsSplitters#writePanel inspired this
        final Component component = splitters.getComponent(0);
        final SplitInfo infos = splitterVisitor(component);

        // or you could use this
        Element root = new Element("root");
        splitters.writeExternal(root);

        elementVisitor(root);

        // to restore from writeExternal the following should suffice
        splitters.readExternal(root);
        splitters.openFiles();
    }

    /**
     * Reads writeExternal output
     */
    private Info elementVisitor(Element root) {
        final Element splitter = root.getChild("splitter");
        if (splitter != null) {
            // see com.intellij.openapi.fileEditor.impl.EditorsSplitters#writePanel
            final SplitInfo splitInfo = new SplitInfo();
            // "vertical" or "horizontal"
            splitInfo.vertical = "vertical".equals(splitter.getAttributeValue("split-orientation"));
            splitInfo.proportions = Float.parseFloat(splitter.getAttributeValue("split-proportion"));
            Element first = splitter.getChild("split-first");
            if (first != null) {
                splitInfo.first = elementVisitor(first);
            }
            Element second = splitter.getChild("split-second");
            if (second != null) {
                splitInfo.second = elementVisitor(second);
            }
            return splitInfo;
        }
        final Element leaf = root.getChild("leaf");
        if (leaf != null) {
            final ArrayList<String> fileNames = new ArrayList<String>();
            for (Element file : leaf.getChildren("file")) {
                final String fileName = file.getAttributeValue("leaf-file-name");
                fileNames.add(fileName);
                // further attributes see com.intellij.openapi.fileEditor.impl.EditorsSplitters#writeComposite
            }
            final FileInfo fileInfo = new FileInfo();
            fileInfo.fileNames = fileNames.toArray(new String[fileNames.size()]);
            return fileInfo;
        }
        return null;
    }

    /**
     * Acts directly upon Component
     */
    private SplitInfo splitterVisitor(Component component) {
        if (component instanceof JPanel && ((JPanel) component).getComponentCount() > 0) {
            final Component child = ((JPanel) component).getComponent(0);
            if (child instanceof Splitter) {
                final Splitter splitter = (Splitter) child;
                final SplitInfo splitInfos = new SplitInfo();
                splitInfos.vertical = splitter.isVertical();
                splitInfos.proportions = splitter.getProportion();
                splitInfos.first = splitterVisitor(splitter.getFirstComponent());
                splitInfos.second = splitterVisitor(splitter.getSecondComponent());
                return splitInfos;
            }
            // TODO: retrieve file information
        }
        return null;
    }
}
TheConstructor
  • 4,045
  • 1
  • 28
  • 48
  • What a horrible API for plugin development. 2020. Thanks though, firstvisitor still works. Do you happen to know how to change the size of a splitter? I got the size ratio, but no method to set ... it should be on window, but nothing is where it is. – mmm Apr 10 '20 at 16:09