[project-model] findModuleForPsiElement: check original file if PsiFile is supplied
[idea/community.git] / java / idea-ui / src / com / intellij / openapi / roots / ui / configuration / libraryEditor / JavadocQuarantineStatusCleaner.java
1 // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.openapi.roots.ui.configuration.libraryEditor;
3
4 import com.intellij.ide.JavaUiBundle;
5 import com.intellij.notification.Notification;
6 import com.intellij.notification.NotificationGroup;
7 import com.intellij.notification.NotificationType;
8 import com.intellij.openapi.application.ApplicationManager;
9 import com.intellij.openapi.application.ModalityState;
10 import com.intellij.openapi.diagnostic.Logger;
11 import com.intellij.openapi.progress.ProgressIndicator;
12 import com.intellij.openapi.progress.Task;
13 import com.intellij.openapi.ui.MessageDialogBuilder;
14 import com.intellij.openapi.ui.Messages;
15 import com.intellij.openapi.util.NlsSafe;
16 import com.intellij.openapi.util.SystemInfo;
17 import com.intellij.openapi.util.text.StringUtil;
18 import com.intellij.openapi.vfs.VirtualFile;
19 import com.sun.jna.platform.mac.XAttrUtil;
20 import org.jetbrains.annotations.NotNull;
21
22 import java.io.IOException;
23 import java.net.URI;
24 import java.nio.file.Files;
25 import java.nio.file.Path;
26 import java.nio.file.Paths;
27 import java.util.List;
28 import java.util.stream.Collectors;
29 import java.util.stream.Stream;
30
31 /**
32  * Files downloaded from Internet are marked as 'quarantined' by OS X.
33  * For such files, opening URLs of type file://path#fragment via
34  * <a href="https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/LaunchServicesConcepts/LSCIntro/LSCIntro.html">
35  *   Launch Services API
36  * </a>
37  * (used internally by {@link java.awt.Desktop#browse(URI)}) won't work as expected (fragment will be ignored on file opening).
38  * This class allows to clear quarantine status from folder containing Javadoc, if confirmed by user.
39  *
40  * Implementation note: UserDefinedFileAttributeView is not supported on macOS (https://bugs.openjdk.java.net/browse/JDK-8030048),
41  * so the class resorts to JNA.
42  */
43 public final class JavadocQuarantineStatusCleaner {
44   private static final Logger LOG = Logger.getInstance(JavadocQuarantineStatusCleaner.class);
45
46   private static final String QUARANTINE_ATTRIBUTE = "com.apple.quarantine";
47
48   public static void cleanIfNeeded(VirtualFile @NotNull ... docFolders) {
49     if (docFolders.length > 0 && SystemInfo.isMac) {
50       ApplicationManager.getApplication().executeOnPooledThread(() -> {
51         List<@NlsSafe String> quarantined = Stream.of(docFolders)
52           .filter(f -> f.isInLocalFileSystem() && f.isDirectory() && XAttrUtil.getXAttr(f.getPath(), QUARANTINE_ATTRIBUTE) != null)
53           .map(VirtualFile::getPath)
54           .collect(Collectors.toList());
55         if (!quarantined.isEmpty()) {
56           ApplicationManager.getApplication().invokeLater(() -> {
57             String title = JavaUiBundle.message("quarantine.cleaner");
58             String message = JavaUiBundle.message("quarantine.dialog.message", StringUtil.join(quarantined, "\n"));
59             if (MessageDialogBuilder.yesNo(title, message).show() == Messages.YES) {
60               cleanQuarantineStatusInBackground(quarantined);
61             }
62           }, ModalityState.any());
63         }
64       });
65     }
66   }
67
68   private static void cleanQuarantineStatusInBackground(List<@NlsSafe String> paths) {
69     new Task.Backgroundable(null, JavaUiBundle.message("quarantine.clean.progress"), true) {
70       @Override
71       public void run(@NotNull ProgressIndicator indicator) {
72         for (@NlsSafe String path : paths) {
73           indicator.checkCanceled();
74           indicator.setText2(path);
75           try (Stream<Path> s = Files.walk(Paths.get(path))) {
76             s.forEach(p -> {
77               indicator.checkCanceled();
78               XAttrUtil.removeXAttr(p.toFile().getAbsolutePath(), QUARANTINE_ATTRIBUTE);
79             });
80           }
81           catch (IOException e) {
82             throw new RuntimeException(e);
83           }
84         }
85       }
86
87       @Override
88       public void onThrowable(@NotNull Throwable error) {
89         LOG.warn(error);
90         String title = JavaUiBundle.message("quarantine.cleaner");
91         String message = JavaUiBundle.message("quarantine.error.message", error.getMessage());
92         new Notification(NotificationGroup.createIdWithTitle("Quarantine Cleaner", title), title, message, NotificationType.WARNING)
93           .notify(null);
94       }
95     }.queue();
96   }
97 }