diff --git a/flutter-idea/src/io/flutter/devtools/AbstractDevToolsViewFactory.java b/flutter-idea/src/io/flutter/devtools/AbstractDevToolsViewFactory.java index d68c10fa9..48c0e6412 100644 --- a/flutter-idea/src/io/flutter/devtools/AbstractDevToolsViewFactory.java +++ b/flutter-idea/src/io/flutter/devtools/AbstractDevToolsViewFactory.java @@ -23,6 +23,7 @@ import io.flutter.view.ViewUtils; import kotlin.coroutines.Continuation; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Optional; @@ -63,6 +64,10 @@ public Object isApplicableAsync(@NotNull Project project, @NotNull Continuation< @Override public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) { + createToolWindowContent(project, toolWindow, null); + } + + public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow, @Nullable String warningMessage) { final FlutterSdk flutterSdk = FlutterSdk.getFlutterSdk(project); final FlutterSdkVersion flutterSdkVersion = flutterSdk == null ? null : flutterSdk.getVersion(); @@ -104,15 +109,16 @@ public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindo } // Final case: - loadDevToolsInEmbeddedBrowser(project, toolWindow, flutterSdkVersion); + loadDevToolsInEmbeddedBrowser(project, toolWindow, flutterSdkVersion, warningMessage); // Finally, listen for the panel to be reopened and potentially reload DevTools. - maybeReloadDevToolsWhenVisible(project, toolWindow, flutterSdkVersion); + maybeReloadDevToolsWhenVisible(project, toolWindow, flutterSdkVersion, warningMessage); } private void loadDevToolsInEmbeddedBrowser(@NotNull Project project, @NotNull ToolWindow toolWindow, - @NotNull FlutterSdkVersion flutterSdkVersion) { + @NotNull FlutterSdkVersion flutterSdkVersion, + @Nullable String warningMessage) { viewUtils.presentLabel(toolWindow, "Loading " + getToolWindowTitle() + "..."); AsyncUtils.whenCompleteUiThread( @@ -144,7 +150,7 @@ private void loadDevToolsInEmbeddedBrowser(@NotNull Project project, FlutterUtils.embeddedBrowser(project)) .ifPresent(embeddedBrowser -> { - embeddedBrowser.openPanel(toolWindow, getToolWindowTitle(), devToolsUrl, System.out::println); + embeddedBrowser.openPanel(toolWindow, getToolWindowTitle(), devToolsUrl, System.out::println, warningMessage); devToolsLoadedInBrowser = true; doAfterBrowserOpened(project, embeddedBrowser); // The "refresh" action refreshes the embedded browser, not the panel. @@ -157,14 +163,15 @@ private void loadDevToolsInEmbeddedBrowser(@NotNull Project project, } private void maybeReloadDevToolsWhenVisible(@NotNull Project project, - @NotNull ToolWindow toolWindow, @NotNull FlutterSdkVersion flutterSdkVersion) { + @NotNull ToolWindow toolWindow, @NotNull FlutterSdkVersion flutterSdkVersion, + @Nullable String warningMessage) { MessageBusConnection connection = project.getMessageBus().connect(); connection.subscribe(ToolWindowManagerListener.TOPIC, new ToolWindowManagerListener() { @Override public void toolWindowShown(@NotNull ToolWindow activatedToolWindow) { if (activatedToolWindow.getId().equals(getToolWindowId())) { if (!devToolsLoadedInBrowser) { - loadDevToolsInEmbeddedBrowser(project, toolWindow, flutterSdkVersion); + loadDevToolsInEmbeddedBrowser(project, toolWindow, flutterSdkVersion, warningMessage); } } } diff --git a/flutter-idea/src/io/flutter/propertyeditor/PropertyEditorViewFactory.java b/flutter-idea/src/io/flutter/propertyeditor/PropertyEditorViewFactory.java index 49f2906cd..28cd2c1ba 100644 --- a/flutter-idea/src/io/flutter/propertyeditor/PropertyEditorViewFactory.java +++ b/flutter-idea/src/io/flutter/propertyeditor/PropertyEditorViewFactory.java @@ -6,7 +6,12 @@ package io.flutter.propertyeditor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.wm.ToolWindow; +import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.openapi.wm.ToolWindowType; +import com.intellij.openapi.wm.ex.ToolWindowManagerListener; +import com.intellij.util.messages.MessageBusConnection; import io.flutter.bazel.WorkspaceCache; import io.flutter.dart.DartPlugin; import io.flutter.dart.DartPluginVersion; @@ -16,13 +21,15 @@ import io.flutter.run.daemon.DevToolsInstance; import io.flutter.sdk.FlutterSdkVersion; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; public class PropertyEditorViewFactory extends AbstractDevToolsViewFactory { - @NotNull public static String TOOL_WINDOW_ID = "Flutter Property Editor"; + @NotNull public final static String TOOL_WINDOW_ID = "Flutter Property Editor"; - @NotNull public static String DEVTOOLS_PAGE_ID = "propertyEditor"; + @NotNull public final static String DEVTOOLS_PAGE_ID = "propertyEditor"; + @Nullable private static Boolean previousDockedUnpinned = null; @Override public boolean versionSupportsThisTool(@NotNull final FlutterSdkVersion flutterSdkVersion) { @@ -65,6 +72,39 @@ public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindo "newer version of the Dart plugin.")); return; } - super.createToolWindowContent(project, toolWindow); + + checkDockedUnpinnedAndCreateContent(project, toolWindow); + + final PropertyEditorViewFactory self = this; + MessageBusConnection connection = project.getMessageBus().connect(); + connection.subscribe(ToolWindowManagerListener.TOPIC, new ToolWindowManagerListener() { + @Override + public void toolWindowShown(@NotNull ToolWindow activatedToolWindow) { + if (activatedToolWindow.getId().equals(getToolWindowId())) { + checkDockedUnpinnedAndCreateContent(project, toolWindow); + } + } + + @Override + public void stateChanged(@NotNull ToolWindowManager toolWindowManager, @NotNull ToolWindowManagerEventType changeType) { + if (changeType.equals(ToolWindowManagerEventType.SetToolWindowAutoHide) || + changeType.equals(ToolWindowManagerEventType.SetToolWindowType)) { + checkDockedUnpinnedAndCreateContent(project, toolWindow); + } + } + }); + Disposer.register(toolWindow.getDisposable(), connection); + } + + private void checkDockedUnpinnedAndCreateContent(@NotNull Project project, ToolWindow toolWindow) { + final Boolean isDockedUnpinned = toolWindow.getType().equals(ToolWindowType.DOCKED) && toolWindow.isAutoHide(); + if (!isDockedUnpinned.equals(previousDockedUnpinned)) { + previousDockedUnpinned = isDockedUnpinned; + super.createToolWindowContent(project, toolWindow, isDockedUnpinned + ? "This tool window is in \"Docked Unpinned\" mode, which means it will disappear " + + "during normal use of the property editor. Select Options (three dots) > View " + + "Mode > Docked Pinned instead." + : null); + } } } diff --git a/flutter-idea/src/io/flutter/run/daemon/DevToolsServerTask.java b/flutter-idea/src/io/flutter/run/daemon/DevToolsServerTask.java index 07ad93771..202bfeb12 100644 --- a/flutter-idea/src/io/flutter/run/daemon/DevToolsServerTask.java +++ b/flutter-idea/src/io/flutter/run/daemon/DevToolsServerTask.java @@ -80,7 +80,7 @@ public void run(@NotNull ProgressIndicator progressIndicator) { progressIndicator.setFraction(30); progressIndicator.setText2("Init"); - // If DevTools is not supported, start the daemon instead. + // If the `dart devtools` command is not supported, start the daemon instead. final boolean dartDevToolsSupported = dartSdkSupportsDartDevTools(); if (!dartDevToolsSupported) { LOG.info("Starting the DevTools daemon."); diff --git a/flutter-idea/src/io/flutter/view/EmbeddedBrowser.java b/flutter-idea/src/io/flutter/view/EmbeddedBrowser.java index bd38568c9..7ecf741c0 100644 --- a/flutter-idea/src/io/flutter/view/EmbeddedBrowser.java +++ b/flutter-idea/src/io/flutter/view/EmbeddedBrowser.java @@ -22,6 +22,7 @@ import io.flutter.utils.LabelInput; import io.flutter.utils.OpenApiUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; @@ -35,7 +36,7 @@ /** * There is one instance of embedded browser across the project, but it manages tabs across multiple tool - * windows. Each tab can display contents of an independent URL. + * windows. Each tab can display the contents of an independent URL. */ public abstract class EmbeddedBrowser { static public class BrowserTab { @@ -77,7 +78,18 @@ public void projectClosing(@NotNull Project project) { }); } - public void openPanel(ToolWindow toolWindow, String tabName, DevToolsUrl devToolsUrl, Consumer onBrowserUnavailable) { + public void openPanel(@NotNull ToolWindow toolWindow, + @NotNull String tabName, + @NotNull DevToolsUrl devToolsUrl, + @NotNull Consumer onBrowserUnavailable) { + openPanel(toolWindow, tabName, devToolsUrl, onBrowserUnavailable, null); + } + + public void openPanel(@NotNull ToolWindow toolWindow, + @NotNull String tabName, + @NotNull DevToolsUrl devToolsUrl, + @NotNull Consumer onBrowserUnavailable, + @Nullable String warningMessage) { this.url = devToolsUrl; Map tabs = windows.computeIfAbsent(toolWindow.getId(), k -> new HashMap<>()); @@ -137,7 +149,17 @@ public void openPanel(ToolWindow toolWindow, String tabName, DevToolsUrl devTool tab.content.putUserData(ToolWindow.SHOW_CONTENT_ICON, Boolean.TRUE); // TODO(helin24): Use differentiated icons for each tab and copy from devtools toolbar. tab.content.setIcon(FlutterIcons.Phone); - tab.contentManager.addContent(tab.content); + + final JPanel panel = new JPanel(new BorderLayout()); + + if (warningMessage != null) { + panel.add(new ViewUtils().warningLabel(warningMessage), BorderLayout.NORTH); + } + + panel.add(tab.content.getComponent(), BorderLayout.CENTER); + final Content panelContent = tab.contentManager.getFactory().createContent(panel, null, false); + + tab.contentManager.addContent(panelContent); tab.contentManager.setSelectedContent(tab.content, true); tab.embeddedTab.matchIdeZoom(); }); diff --git a/flutter-idea/src/io/flutter/view/ViewUtils.java b/flutter-idea/src/io/flutter/view/ViewUtils.java index 5ea5beb03..180c03632 100644 --- a/flutter-idea/src/io/flutter/view/ViewUtils.java +++ b/flutter-idea/src/io/flutter/view/ViewUtils.java @@ -22,6 +22,14 @@ import java.util.List; public class ViewUtils { + public @NotNull JBLabel warningLabel(@NotNull String warning) { + final JBLabel descriptionLabel = new JBLabel(wrapWithHtml(warning)); + descriptionLabel.setBorder(JBUI.Borders.empty(5)); + descriptionLabel.setHorizontalAlignment(SwingConstants.CENTER); + descriptionLabel.setForeground(Color.RED); + return descriptionLabel; + } + public void presentLabel(ToolWindow toolWindow, String text) { final JBLabel label = new JBLabel(wrapWithHtml(text), SwingConstants.CENTER); label.setForeground(UIUtil.getLabelDisabledForeground());