package com.jetbrains.lang.dart.ide.actions; import com.intellij.ide.BrowserUtil; import com.intellij.notification.Notification; import com.intellij.notification.NotificationGroup; import com.intellij.notification.NotificationListener; import com.intellij.notification.NotificationType; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.colors.EditorColors; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.ui.EditorNotificationPanel; import com.intellij.ui.EditorNotifications; import com.jetbrains.lang.dart.DartBundle; import com.jetbrains.lang.dart.DartFileType; import com.jetbrains.lang.dart.analyzer.DartAnalysisServerService; import com.jetbrains.lang.dart.flutter.FlutterUtil; import com.jetbrains.lang.dart.sdk.*; import com.jetbrains.lang.dart.util.PubspecYamlUtil; import icons.DartIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.HyperlinkEvent; public class DartEditorNotificationsProvider extends EditorNotifications.Provider<EditorNotificationPanel> { private static final Key<EditorNotificationPanel> KEY = Key.create("DartEditorNotificationsProvider"); private static final NotificationGroup NOTIFICATION_GROUP = NotificationGroup.balloonGroup("Dart Support"); @NotNull private final Project myProject; public DartEditorNotificationsProvider(@NotNull final Project project) { myProject = project; } @Override @NotNull public Key<EditorNotificationPanel> getKey() { return KEY; } @Override @Nullable public EditorNotificationPanel createNotificationPanel(@NotNull final VirtualFile vFile, @NotNull final FileEditor fileEditor) { if (!vFile.isInLocalFileSystem()) { return null; } if (PubspecYamlUtil.PUBSPEC_YAML.equalsIgnoreCase(vFile.getName())) { final Module module = ModuleUtilCore.findModuleForFile(vFile, myProject); if (module == null) return null; // Defer to the Flutter plugin for package management and SDK configuration if appropriate. if (FlutterUtil.isFlutterPluginInstalled() && FlutterUtil.isFlutterModule(module)) return null; final DartSdk sdk = DartSdk.getDartSdk(myProject); if (sdk != null && DartSdkLibUtil.isDartSdkEnabled(module)) { return new PubActionsPanel(); } } if (PubspecYamlUtil.PUBSPEC_YAML.equalsIgnoreCase(vFile.getName()) || vFile.getFileType() == DartFileType.INSTANCE) { final DartSdk sdk = DartSdk.getDartSdk(myProject); final PsiFile psiFile = PsiManager.getInstance(myProject).findFile(vFile); if (psiFile == null) return null; final Module module = ModuleUtilCore.findModuleForPsiElement(psiFile); if (module == null) return null; // no SDK if (sdk == null) { final String sdkPath = DartSdkUtil.getFirstKnownDartSdkPath(); if (DartSdkUtil.isDartSdkHome(sdkPath)) { return createNotificationToEnableDartSupport(module); } final String message = DartBundle.message("dart.sdk.is.not.configured"); final String downloadUrl = DartSdkUpdateChecker.SDK_STABLE_DOWNLOAD_URL; final EditorNotificationPanel panel = new EditorNotificationPanel().icon(DartIcons.Dart_16).text(message); panel.createActionLabel(DartBundle.message("download.dart.sdk"), new OpenWebPageRunnable(downloadUrl)); panel.createActionLabel(DartBundle.message("open.dart.settings"), new OpenDartSettingsRunnable(myProject)); return panel; } // SDK not enabled for this module if (!DartSdkLibUtil.isDartSdkEnabled(module)) { return createNotificationToEnableDartSupport(module); } if (!DartAnalysisServerService.isDartSdkVersionSufficient(sdk)) { final String message = DartBundle.message("old.dart.sdk.configured", DartAnalysisServerService.MIN_SDK_VERSION, sdk.getVersion()); final String downloadUrl = DartSdkUpdateChecker.SDK_STABLE_DOWNLOAD_URL; final EditorNotificationPanel panel = new EditorNotificationPanel().icon(DartIcons.Dart_16).text(message); panel.createActionLabel(DartBundle.message("download.dart.sdk"), new OpenWebPageRunnable(downloadUrl)); panel.createActionLabel(DartBundle.message("open.dart.settings"), new OpenDartSettingsRunnable(myProject)); return panel; } } return null; } @NotNull private EditorNotificationPanel createNotificationToEnableDartSupport(@NotNull final Module module) { final String message = DartSdkLibUtil.isIdeWithMultipleModuleSupport() ? DartBundle.message("dart.support.is.not.enabled.for.module.0", module.getName()) : DartBundle.message("dart.support.is.not.enabled.for.project"); final EditorNotificationPanel panel = new EditorNotificationPanel().icon(DartIcons.Dart_16).text(message); panel.createActionLabel(DartBundle.message("enable.dart.support"), new EnableDartSupportForModule(module)); panel.createActionLabel(DartBundle.message("open.dart.settings"), new OpenDartSettingsRunnable(myProject)); return panel; } private static class PubActionsPanel extends EditorNotificationPanel { private PubActionsPanel() { super(EditorColors.GUTTER_BACKGROUND); myLinksPanel.add(new JLabel("Pub actions:")); createActionLabel(DartBundle.message("get.dependencies"), "Dart.pub.get"); createActionLabel(DartBundle.message("upgrade.dependencies"), "Dart.pub.upgrade"); createActionLabel("Build...", "Dart.pub.build"); myLinksPanel.add(new JSeparator(SwingConstants.VERTICAL)); createActionLabel("Repair cache...", "Dart.pub.cache.repair"); } } private static class EnableDartSupportForModule implements Runnable { private final Module myModule; public EnableDartSupportForModule(@NotNull final Module module) { this.myModule = module; } @Override public void run() { final Project project = myModule.getProject(); ApplicationManager.getApplication().runWriteAction(() -> { if (DartSdk.getDartSdk(project) == null) { final String sdkPath = DartSdkUtil.getFirstKnownDartSdkPath(); if (DartSdkUtil.isDartSdkHome(sdkPath)) { DartSdkLibUtil.ensureDartSdkConfigured(project, sdkPath); } else { return; // shouldn't happen, sdk path is already checked } } DartSdkLibUtil.enableDartSdk(myModule); }); final DartSdk sdk = DartSdk.getDartSdk(project); if (sdk != null && DartSdkLibUtil.isDartSdkEnabled(myModule)) { final String title = DartSdkLibUtil.isIdeWithMultipleModuleSupport() ? DartBundle.message("dart.support.enabled.for.module.0", myModule.getName()) : DartBundle.message("dart.support.enabled"); final String message = DartBundle.message("dart.sdk.0.open.dart.settings", sdk.getVersion()); final NotificationListener listener = new NotificationListener.Adapter() { @Override protected void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent e) { DartConfigurable.openDartSettings(project); } }; NOTIFICATION_GROUP.createNotification(title, message, NotificationType.INFORMATION, listener) .notify(project); } } } private static class OpenWebPageRunnable implements Runnable { @NotNull private final String myUrl; private OpenWebPageRunnable(@NotNull final String url) { myUrl = url; } @Override public void run() { BrowserUtil.browse(myUrl); } } private static class OpenDartSettingsRunnable implements Runnable { @NotNull private final Project myProject; private OpenDartSettingsRunnable(@NotNull final Project project) { myProject = project; } @Override public void run() { DartConfigurable.openDartSettings(myProject); } } }