ToolWindowFactory (and DumbAware) Implementation Not Loaded Immediately When Installed

已回答

Hi Team,

I've a ToolWindowFactory implementation registered as an extension in plugin.xml. The ToolWindowFactory is DumbAware.

After successful deployment, the toolwindow, when clicked, is not opened & loaded immediately. Making the Toolwindow dumbaware still minds/requires indexing for successful load. It gets stuck all the time. It's hard to access the toolwindow contents successfully when installed and opened for the first time. I had to make several attempts in new windows to proceed as I had to open another project from the current IDE window, give it some time in the new window, then click on the toolwindow. Sometimes, even the new window does not help populating the toolwindow contents immediately.  

The application contains components such as a ToolWindowFactory, a JBCefBrowser, anAction and some listeners for Editor. Do you have any guesses here? 

 

0

Could you please share a screenshot of the “stuck” state and how it looks at runtime? Is your plugin open source or available somewhere for installation? Please also note your IDE version.

0

 

Sure, 

1.) Here's the screeshot. To the left hand side, under Project icon, an icon highlighted in royal blue color is the plugin icon. 

2.) After installing the plugin and restarting the IDE, it opens up a new IDE instance. I select the project to open up in the IDE. Once the project is loaded, when I click the plugin icon, it gets stuck as show in the screenshot. 

3.) The plugin is not open source. We will distribute it soon through JB Marketplace.  I'll figure out a way soon to share it with you for installation. Thanks for providing this option.

4.) IDE version is 2024.2.2  and the Open API version info is 

id("org.jetbrains.intellij.platform") version "2.0.1"

Can I use any Open API or any means to determine if the indexing is completed programmatically?

0

I'd try removing JBCefBrowser and then possibly other components one-by-one. Do you perform any kind of “heavy” initialization in your toolwindow? Unfortunately, it's quite impossible to diagnose this without seeing the actual code.

 

You can query current indexing mode as described here https://plugins.jetbrains.com/docs/intellij/indexing-and-psi-stubs.html#dumb-mode 

0

I am loading JBCefBrowser component to the tool window. 

I'm creating a JBCefBrowser, adding a CefLoadHandler, overriding handler's onLoadStart method by registering several Javascript functions using executeJavascript() method. Out of the several functions, one function is an load event listener, three functions are registered for executing plugin code from Javascript (to execute Java code when user performs some actions on the browser) and several other are regular JS functions that can be called whenever required. As I'm maintaining only one browser instance for a given IDE, I believe that I need to register all of the functions (I'm going to call later) during the load itself and hence the onLoadStart is stuffed with several function definitions.

I'm loading the browser with a HTML page. This HTML page contains just html and body tags. The on load listener function (that's registered inside the onLoadStart() method) gets called. It manipulates the document object by appending a script element. The script element contains the respective information to display in the HTML page. 

There's a reason behind manipulating the document and not adding script files to the HTML page. SSO is integrated with the plugin. Based on the user's login status (logged in or not), user's privileges (can access certain functionality or not), the browser has to display the respective contents. The login status and user privileges information are available in Java. Such information needs to be available in the HTML page for successful on load. Hence, I didn't go for hardcoding the script tags in the HTML page or any other way. I leveraged Load Handler to register all functions (required for all scenarios) at once. Then, I'm calling them as and when required any time post the load using executeJavascript(). If you think I can provide some more information or you've something to share w.r.t this context, please let me know. 

Let's say we have some heavy initialization. With this, after installation, when I am clicking the toolwindow for the first time, there are chances that I've to wait for some time to see the contents. While I wait for the contents, if I click the tool window multiple times (opening and closing the TW), the contents do not get displayed at all. If I don't act upon the toolwindow during the wait time, then I see more chances of seeing the contents after the wait time.

When there's going to be only one instance of the Tool Window and if it is clicked once and the contents do not get loaded immediately for some reason(may be heavy init) but will get loaded eventually, further clicks on the tool window seem to block the contents that are yet to be rendered. What could be the reason?

Do we have to invoke ToolWindows only via EDT? ApplicationManager.getApplication().invokeLater() vs invokeAndWait() 

It seems to me that invokeLater() is like fire and forget. But, I believe that it should render it's result whenever it completes. Do you think invokeAndWait() helps render the contents for sure even when further clicks on the tool window happen?

Here's the different variations I've tried. 

Variation 1:

public class ToolWindow1 implements ToolWindowFactory, DumbAware {
    @Override
    public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
        DumbService.getInstance(project).runWhenSmart(
                () ->
                        ApplicationManager.getApplication().invokeAndWait(() -> {
                            getProjectService(project).setToolWindow(toolWindow);
                            new BrowserService(project).loadBrowserWithContents();
                            JBCefBrowser browser = getBrowser(project).getJbCefBrowser();
                            toolWindow.getContentManager()
                                    .addContent(new ContentImpl(browser.getComponent(), EMPTY, false));

                            new EditorFocusListener(project);
                            new ProjectLanguageDetector(project);
                        })
        );
    }
}

Variation 2:

public class ToolWindow2 implements ToolWindowFactory, DumbAware {
    @Override
    public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
        DumbService.getInstance(project).showDumbModeActionBalloon(
                "Loading Plugin...",
                () ->
                        ApplicationManager.getApplication().invokeLater(() -> {
                            getProjectService(project).setToolWindow(toolWindow);
                            new BrowserService(project).loadBrowserWithContents();

                            JBCefBrowser browser = getBrowser(project).getJbCefBrowser();
                            toolWindow.getContentManager().addContent(
                                    ContentFactory.getInstance().createContent(browser.getComponent(), EMPTY, false));

                            new EditorFocusListener(project);
                            new ProjectLanguageDetector(project);
                        }),
                java.util.List.of()
        );
    }
}

 

Can you please clarify the below ones regarding the toolwindow and service calls as I'm not finding the description of some parameters and methods.

1.) In the above variations, I'm enabling the TW DumbAware and waiting for the smart mode to load the plugin. I believe that I can either wait for the smart mode or load the plugin in dumb mode. 

 If I don't make the TW dumb aware, it shows me “This view is not ready until all indexes are built”        and sometimes it goes without displaying the contents. 

If I make it dumb aware and load the plugin during smart mode, it shows me “Nothing to show” and I get to see the contents almost everytime.

Please share your opinion and highlight the right approach.       

2.) What does the last parameter (list of action Ids) mean in DumbService.showDumbModeActionBalloon()? What's the purpose of passing them?

3.) DumbService offers showDumbModeActionBalloon() method wherein I can pass the loading text. Is there any option I can display a loading icon? Or, Are there any possibilities to display a Spinner Icon by any means while the Tool Window loads?

 

0

1) So the issue is mainly that initializing the tool window contents takes some time, during which the UI is not active/present.

You can show a placeholder UI with custom “loading…” text via `com.intellij.ui.components.JBLoadingPanel`, for example.

2) These are IDs from AnAction instances.

3) See suggested approach in 1).

0

请先登录再写评论。