mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-156758 Disable non project files writing protection, when file is opened explicitly
IDEA-156759 Add an option to 'Non-project files' protection dialog to edit files in a folder IDEA-156760 'Non-project files protection' dialog is had to use with a keyboard
This commit is contained in:
@@ -30,6 +30,7 @@ import com.intellij.openapi.command.undo.UndoManager;
|
||||
import com.intellij.openapi.command.undo.UndoableAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.fileEditor.impl.NonProjectFileWritingAccessProvider;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
@@ -537,22 +538,20 @@ public abstract class BaseRefactoringProcessor implements Runnable {
|
||||
public final void run() {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
doRun();
|
||||
NonProjectFileWritingAccessProvider.disableChecksDuring(this::doRun);
|
||||
|
||||
//noinspection TestOnlyProblems
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
//noinspection TestOnlyProblems
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
return;
|
||||
}
|
||||
if (ApplicationManager.getApplication().isWriteAccessAllowed()) {
|
||||
LOG.error("Refactorings should not be started inside write action\n because they start progress inside and any read action from the progress task would cause the deadlock", new Exception());
|
||||
DumbService.getInstance(myProject).smartInvokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
doRun();
|
||||
}
|
||||
});
|
||||
DumbService.getInstance(myProject).smartInvokeLater(() -> NonProjectFileWritingAccessProvider.disableChecksDuring(this::doRun));
|
||||
}
|
||||
else {
|
||||
doRun();
|
||||
NonProjectFileWritingAccessProvider.disableChecksDuring(this::doRun);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ public class PsiElementRenameHandler implements RenameHandler {
|
||||
if (!PsiManager.getInstance(project).isInProject(element)) {
|
||||
if (element.isPhysical()) {
|
||||
VirtualFile virtualFile = PsiUtilCore.getVirtualFile(element);
|
||||
if (!(virtualFile != null && NonProjectFileWritingAccessProvider.isWriteAccessAllowedExplicitly(virtualFile, project))) {
|
||||
if (!(virtualFile != null && NonProjectFileWritingAccessProvider.isWriteAccessAllowed(virtualFile))) {
|
||||
String message = RefactoringBundle.message("error.out.of.project.element", UsageViewUtil.getType(element));
|
||||
return RefactoringBundle.getCannotRefactorMessage(message);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.fileEditor.FileEditorProvider;
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||
import com.intellij.openapi.fileEditor.ex.FileEditorProviderManager;
|
||||
import com.intellij.openapi.fileEditor.impl.NonProjectFileWritingAccessProvider;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.ex.FileTypeChooser;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
@@ -41,7 +42,6 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.wm.impl.welcomeScreen.NewWelcomeScreen;
|
||||
import com.intellij.platform.PlatformProjectOpenProcessor;
|
||||
import com.intellij.projectImport.ProjectAttachProcessor;
|
||||
import com.intellij.util.Consumer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -127,6 +127,8 @@ public class OpenFileAction extends AnAction implements DumbAware {
|
||||
return;
|
||||
}
|
||||
|
||||
NonProjectFileWritingAccessProvider.allowWriting(file);
|
||||
|
||||
OpenFileDescriptor descriptor = new OpenFileDescriptor(project, file);
|
||||
FileEditorManager.getInstance(project).openTextEditor(descriptor, true);
|
||||
}
|
||||
|
||||
+18
-8
@@ -8,39 +8,48 @@
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<grid id="2f133" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<grid id="2f133" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="3" anchor="2" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="etched"/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="e62df" class="javax.swing.JRadioButton" default-binding="true">
|
||||
<component id="e62df" class="javax.swing.JRadioButton" binding="myUnlockOneButton">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<selected value="true"/>
|
||||
<text value="I want to edit these files anyway"/>
|
||||
<selected value="false"/>
|
||||
<text value="unlock one"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="592c9" class="javax.swing.JRadioButton" binding="myUnlockAllButton" default-binding="true">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="unlock all"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="4ff89" class="javax.swing.JRadioButton" binding="myUnlockDirButton">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="I want to edit any non-project file in the current session"/>
|
||||
<selected value="false"/>
|
||||
<text value="unlock dir"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<component id="dbd63" class="javax.swing.JLabel">
|
||||
<component id="dbd63" class="javax.swing.JLabel" binding="myListTitle">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="These files do not belong to the project"/>
|
||||
<text value="title"/>
|
||||
</properties>
|
||||
</component>
|
||||
<scrollpane id="6c540" class="com.intellij.ui.components.JBScrollPane">
|
||||
@@ -64,6 +73,7 @@
|
||||
<member id="e62df"/>
|
||||
<member id="25953"/>
|
||||
<member id="16741"/>
|
||||
<member id="4ff89"/>
|
||||
</group>
|
||||
</buttonGroups>
|
||||
</form>
|
||||
|
||||
+59
-6
@@ -17,33 +17,85 @@ package com.intellij.openapi.fileEditor.impl;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.readOnlyHandler.FileListRenderer;
|
||||
import com.intellij.openapi.vcs.readOnlyHandler.ReadOnlyStatusDialog;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.CollectionListModel;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.List;
|
||||
|
||||
public class NonProjectFileWritingAccessDialog extends DialogWrapper {
|
||||
private JPanel myPanel;
|
||||
private JLabel myListTitle;
|
||||
private JList myFileList;
|
||||
private JRadioButton myUnlockOneButton;
|
||||
private JRadioButton myUnlockDirButton;
|
||||
private JRadioButton myUnlockAllButton;
|
||||
|
||||
protected NonProjectFileWritingAccessDialog(@NotNull Project project, @NotNull List<VirtualFile> nonProjectFiles) {
|
||||
public NonProjectFileWritingAccessDialog(@NotNull Project project, @NotNull List<VirtualFile> nonProjectFiles) {
|
||||
this(project, nonProjectFiles, "Non-Project Files");
|
||||
}
|
||||
|
||||
public NonProjectFileWritingAccessDialog(@NotNull Project project,
|
||||
@NotNull List<VirtualFile> nonProjectFiles,
|
||||
@NotNull String filesType) {
|
||||
super(project);
|
||||
setTitle("Non-Project Files Access");
|
||||
setTitle(filesType + " Protection");
|
||||
|
||||
myFileList.setCellRenderer(new FileListRenderer());
|
||||
myFileList.setModel(new CollectionListModel<VirtualFile>(nonProjectFiles));
|
||||
|
||||
String theseFilesMessage = ReadOnlyStatusDialog.getTheseFilesMessage(nonProjectFiles);
|
||||
myListTitle.setText(StringUtil.capitalize(theseFilesMessage)
|
||||
+ " " + (nonProjectFiles.size() > 1 ? "do" : "does")
|
||||
+ " not belong to the project:");
|
||||
|
||||
|
||||
myUnlockOneButton.setSelected(true);
|
||||
setTextAndMnemonicAndListeners(myUnlockOneButton, "I want to edit " + theseFilesMessage + " anyway", "edit");
|
||||
|
||||
int dirs = ContainerUtil.map2Set(nonProjectFiles, VirtualFile::getParent).size();
|
||||
setTextAndMnemonicAndListeners(myUnlockDirButton, "I want to edit all files in "
|
||||
+ StringUtil.pluralize("this", dirs)
|
||||
+ " " + StringUtil.pluralize("directory", dirs), "dir");
|
||||
|
||||
setTextAndMnemonicAndListeners(myUnlockAllButton, "I want to edit any non-project file in the current session", "any");
|
||||
|
||||
|
||||
// disable default button to avoid accidental pressing, if user typed something, missed the dialog and pressed 'enter'.
|
||||
getOKAction().putValue(DEFAULT_ACTION, null);
|
||||
getCancelAction().putValue(DEFAULT_ACTION, true);
|
||||
|
||||
getCancelAction().putValue(DEFAULT_ACTION, null);
|
||||
|
||||
getRootPane().registerKeyboardAction(e -> doOKAction(), KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_DOWN_MASK),
|
||||
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
|
||||
getRootPane().registerKeyboardAction(e -> doOKAction(), KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.META_DOWN_MASK),
|
||||
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
private void setTextAndMnemonicAndListeners(JRadioButton button, String text, String mnemonic) {
|
||||
button.setText(text);
|
||||
button.setMnemonic(mnemonic.charAt(0));
|
||||
button.setDisplayedMnemonicIndex(button.getText().indexOf(mnemonic));
|
||||
|
||||
// enabled OK button when user selects an option
|
||||
button.addActionListener(e -> button.getRootPane().setDefaultButton(getButton(getOKAction())));
|
||||
button.addItemListener(e -> button.getRootPane().setDefaultButton(getButton(getOKAction())));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return myUnlockOneButton;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@@ -53,8 +105,9 @@ public class NonProjectFileWritingAccessDialog extends DialogWrapper {
|
||||
|
||||
@NotNull
|
||||
public NonProjectFileWritingAccessProvider.UnlockOption getUnlockOption() {
|
||||
return myUnlockAllButton.isSelected() ? NonProjectFileWritingAccessProvider.UnlockOption.UNLOCK_ALL
|
||||
: NonProjectFileWritingAccessProvider.UnlockOption.UNLOCK;
|
||||
if (myUnlockAllButton.isSelected()) return NonProjectFileWritingAccessProvider.UnlockOption.UNLOCK_ALL;
|
||||
if (myUnlockDirButton.isSelected()) return NonProjectFileWritingAccessProvider.UnlockOption.UNLOCK_DIR;
|
||||
return NonProjectFileWritingAccessProvider.UnlockOption.UNLOCK;
|
||||
}
|
||||
|
||||
protected String getHelpId() {
|
||||
|
||||
+116
-99
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package com.intellij.openapi.fileEditor.impl;
|
||||
|
||||
import com.intellij.ProjectTopics;
|
||||
import com.intellij.ide.impl.ProjectUtil;
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.ServiceKt;
|
||||
import com.intellij.openapi.components.impl.stores.IProjectStore;
|
||||
@@ -24,31 +24,35 @@ import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.project.ex.ProjectEx;
|
||||
import com.intellij.openapi.roots.ModuleRootAdapter;
|
||||
import com.intellij.openapi.roots.ModuleRootEvent;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.NotNullLazyKey;
|
||||
import com.intellij.openapi.util.UserDataHolder;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.util.NotNullFunction;
|
||||
import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
|
||||
import com.intellij.util.NullableFunction;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class NonProjectFileWritingAccessProvider extends WritingAccessProvider {
|
||||
public enum AccessStatus {REQUESTED, ALLOWED}
|
||||
|
||||
private static final Key<Boolean> ENABLE_IN_TESTS = Key.create("NON_PROJECT_FILE_ACCESS_ENABLE_IN_TESTS");
|
||||
private static final Key<Boolean> ALL_ACCESS_ALLOWED = Key.create("NON_PROJECT_FILE_ALL_ACCESS_STATUS");
|
||||
private static final NotNullLazyKey<Map<VirtualFile, AccessStatus>, Project> ACCESS_STATUS
|
||||
= NotNullLazyKey.create("NON_PROJECT_FILE_ACCESS_STATUS", project -> new HashMap<VirtualFile, AccessStatus>());
|
||||
private static final NotNullLazyKey<AtomicInteger, UserDataHolder> ACCESS_ALLOWED
|
||||
= NotNullLazyKey.create("NON_PROJECT_FILE_ACCESS", holder -> new AtomicInteger());
|
||||
|
||||
@NotNull private final Project myProject;
|
||||
@Nullable private static NullableFunction<List<VirtualFile>, UnlockOption> ourCustomUnlocker;
|
||||
@@ -58,26 +62,22 @@ public class NonProjectFileWritingAccessProvider extends WritingAccessProvider {
|
||||
ourCustomUnlocker = unlocker;
|
||||
}
|
||||
|
||||
public NonProjectFileWritingAccessProvider(@NotNull final Project project) {
|
||||
public NonProjectFileWritingAccessProvider(@NotNull Project project) {
|
||||
myProject = project;
|
||||
|
||||
VirtualFileManager.getInstance().addVirtualFileListener(new VirtualFileAdapter() {
|
||||
@Override
|
||||
public void fileDeleted(@NotNull VirtualFileEvent event) {
|
||||
getRegisteredFiles(project).remove(event.getFile());
|
||||
public void fileCreated(@NotNull VirtualFileEvent event) {
|
||||
unlock(event);
|
||||
}
|
||||
}, project);
|
||||
|
||||
myProject.getMessageBus().connect().subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() {
|
||||
@Override
|
||||
public void rootsChanged(ModuleRootEvent event) {
|
||||
Map<VirtualFile, AccessStatus> files = getRegisteredFiles(project);
|
||||
|
||||
// reset access status and notifications for files that became project files
|
||||
for (VirtualFile each : new ArrayList<VirtualFile>(files.keySet())) {
|
||||
if (isProjectFile(each, project)) {
|
||||
files.remove(each);
|
||||
}
|
||||
}
|
||||
public void fileCopied(@NotNull VirtualFileCopyEvent event) {
|
||||
unlock(event);
|
||||
}
|
||||
|
||||
private void unlock(@NotNull VirtualFileEvent event) {
|
||||
if (!event.isFromRefresh() && !event.getFile().isDirectory()) allowWriting(event.getFile());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -90,24 +90,9 @@ public class NonProjectFileWritingAccessProvider extends WritingAccessProvider {
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<VirtualFile> requestWriting(VirtualFile... files) {
|
||||
if (allAccessAllowed(myProject)) return Collections.emptyList();
|
||||
|
||||
List<VirtualFile> deniedFiles = new SmartList<VirtualFile>();
|
||||
|
||||
Map<VirtualFile, AccessStatus> statuses = getRegisteredFiles(myProject);
|
||||
for (VirtualFile each : files) {
|
||||
if (statuses.get(each) == AccessStatus.ALLOWED) continue;
|
||||
|
||||
if (!(each.getFileSystem() instanceof LocalFileSystem)) continue; // do not block e.g., HttpFileSystem, LightFileSystem etc.
|
||||
if (isProjectFile(each, myProject)) {
|
||||
statuses.remove(each);
|
||||
continue;
|
||||
}
|
||||
|
||||
statuses.put(each, AccessStatus.REQUESTED);
|
||||
deniedFiles.add(each);
|
||||
}
|
||||
if (isAllAccessAllowed()) return Collections.emptyList();
|
||||
|
||||
List<VirtualFile> deniedFiles = Stream.of(files).filter(o -> !isWriteAccessAllowed(o)).collect(Collectors.toList());
|
||||
if (deniedFiles.isEmpty()) return Collections.emptyList();
|
||||
|
||||
UnlockOption unlockOption = askToUnlock(deniedFiles);
|
||||
@@ -116,12 +101,13 @@ public class NonProjectFileWritingAccessProvider extends WritingAccessProvider {
|
||||
|
||||
switch (unlockOption) {
|
||||
case UNLOCK:
|
||||
for (VirtualFile eachAllowed : deniedFiles) {
|
||||
statuses.put(eachAllowed, AccessStatus.ALLOWED);
|
||||
}
|
||||
allowWriting(deniedFiles);
|
||||
break;
|
||||
case UNLOCK_DIR:
|
||||
allowWriting(ContainerUtil.map(deniedFiles, VirtualFile::getParent));
|
||||
break;
|
||||
case UNLOCK_ALL:
|
||||
myProject.putUserData(ALL_ACCESS_ALLOWED, Boolean.TRUE);
|
||||
ACCESS_ALLOWED.getValue(getApp()).incrementAndGet();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -137,67 +123,98 @@ public class NonProjectFileWritingAccessProvider extends WritingAccessProvider {
|
||||
return dialog.getUnlockOption();
|
||||
}
|
||||
|
||||
public static boolean isWriteAccessAllowedExplicitly(@NotNull VirtualFile file, @NotNull Project project) {
|
||||
if (!(file.getFileSystem() instanceof LocalFileSystem)) return false;
|
||||
Map<VirtualFile, AccessStatus> statuses = getRegisteredFiles(project);
|
||||
return statuses.get(file) == AccessStatus.ALLOWED ||
|
||||
isProjectFile(file, project);
|
||||
}
|
||||
public static boolean isWriteAccessAllowed(@NotNull VirtualFile file) {
|
||||
if (isAllAccessAllowed()) return true;
|
||||
if (file.isDirectory()) return true;
|
||||
|
||||
private static boolean isProjectFile(@NotNull VirtualFile file, @NotNull Project project) {
|
||||
ProjectFileIndex fileIndex = ProjectFileIndex.SERVICE.getInstance(project);
|
||||
if (fileIndex.isInContent(file)) return true;
|
||||
if (!Registry.is("ide.hide.excluded.files") && fileIndex.isExcluded(file) && !fileIndex.isUnderIgnored(file)) return true;
|
||||
|
||||
if (project instanceof ProjectEx && !project.isDefault()) {
|
||||
if (ProjectUtil.isDirectoryBased(project)) {
|
||||
VirtualFile baseDir = project.getBaseDir();
|
||||
VirtualFile dotIdea = baseDir == null ? null : baseDir.findChild(Project.DIRECTORY_STORE_FOLDER);
|
||||
if (dotIdea != null && VfsUtilCore.isAncestor(dotIdea, file, false)) return true;
|
||||
}
|
||||
|
||||
IProjectStore store = (IProjectStore)ServiceKt.getStateStore(project);
|
||||
String filePath = file.getPath();
|
||||
if (FileUtil.namesEqual(filePath, store.getWorkspaceFilePath()) || FileUtil.namesEqual(filePath, store.getProjectFilePath())) {
|
||||
return true;
|
||||
}
|
||||
for (Module module : ModuleManager.getInstance(project).getModules()) {
|
||||
if (FileUtil.namesEqual(filePath, module.getModuleFilePath())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (NonProjectFileWritingAccessExtension each : Extensions.getExtensions(NonProjectFileWritingAccessExtension.EP_NAME, project)) {
|
||||
if(each.isWritable(file)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public static void enableChecksInTests(@NotNull Project project, boolean enable) {
|
||||
project.putUserData(ENABLE_IN_TESTS, enable ? Boolean.TRUE : null);
|
||||
}
|
||||
|
||||
private static boolean allAccessAllowed(@NotNull Project project) {
|
||||
// disable checks in tests, if not asked
|
||||
if (ApplicationManager.getApplication().isUnitTestMode() && project.getUserData(ENABLE_IN_TESTS) != Boolean.TRUE) {
|
||||
if (!(file.getFileSystem() instanceof LocalFileSystem)) return true;
|
||||
if (file.getFileSystem() instanceof TempFileSystem) return true;
|
||||
if (!getApp().isUnitTestMode()
|
||||
&& FileUtil.isAncestor(new File(FileUtil.getTempDirectory()), VfsUtilCore.virtualToIoFile(file), true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return project.getUserData(ALL_ACCESS_ALLOWED) == Boolean.TRUE;
|
||||
VirtualFile each = file;
|
||||
while (each != null) {
|
||||
if (ACCESS_ALLOWED.getValue(each).get() > 0) return true;
|
||||
each = each.getParent();
|
||||
}
|
||||
|
||||
return isProjectFile(file);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static AccessStatus getAccessStatus(@NotNull Project project, @NotNull VirtualFile file) {
|
||||
return allAccessAllowed(project) ? AccessStatus.ALLOWED : getRegisteredFiles(project).get(file);
|
||||
private static boolean isProjectFile(@NotNull VirtualFile file) {
|
||||
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
|
||||
ProjectFileIndex fileIndex = ProjectFileIndex.SERVICE.getInstance(project);
|
||||
if (fileIndex.isInContent(file)) return true;
|
||||
if (!Registry.is("ide.hide.excluded.files") && fileIndex.isExcluded(file) && !fileIndex.isUnderIgnored(file)) return true;
|
||||
|
||||
if (project instanceof ProjectEx && !project.isDefault()) {
|
||||
if (ProjectUtil.isDirectoryBased(project)) {
|
||||
VirtualFile baseDir = project.getBaseDir();
|
||||
VirtualFile dotIdea = baseDir == null ? null : baseDir.findChild(Project.DIRECTORY_STORE_FOLDER);
|
||||
if (dotIdea != null && VfsUtilCore.isAncestor(dotIdea, file, false)) return true;
|
||||
}
|
||||
|
||||
IProjectStore store = (IProjectStore)ServiceKt.getStateStore(project);
|
||||
String filePath = file.getPath();
|
||||
if (FileUtil.namesEqual(filePath, store.getWorkspaceFilePath()) || FileUtil.namesEqual(filePath, store.getProjectFilePath())) {
|
||||
return true;
|
||||
}
|
||||
for (Module module : ModuleManager.getInstance(project).getModules()) {
|
||||
if (FileUtil.namesEqual(filePath, module.getModuleFilePath())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (NonProjectFileWritingAccessExtension each : Extensions.getExtensions(NonProjectFileWritingAccessExtension.EP_NAME, project)) {
|
||||
if(each.isWritable(file)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Map<VirtualFile, AccessStatus> getRegisteredFiles(@NotNull Project project) {
|
||||
return ACCESS_STATUS.getValue(project);
|
||||
public static void allowWriting(Collection<VirtualFile> allowedFiles) {
|
||||
for (VirtualFile eachAllowed : allowedFiles) {
|
||||
ACCESS_ALLOWED.getValue(eachAllowed).incrementAndGet();
|
||||
}
|
||||
}
|
||||
|
||||
public enum UnlockOption {UNLOCK, UNLOCK_ALL}
|
||||
public static void allowWriting(VirtualFile... allowedFiles) {
|
||||
allowWriting(Arrays.asList(allowedFiles));
|
||||
}
|
||||
|
||||
public static void disableChecksDuring(@NotNull Runnable runnable) {
|
||||
Application app = getApp();
|
||||
ACCESS_ALLOWED.getValue(app).incrementAndGet();
|
||||
try {
|
||||
runnable.run();
|
||||
}
|
||||
finally {
|
||||
ACCESS_ALLOWED.getValue(app).decrementAndGet();
|
||||
}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public static void enableChecksInTests(boolean enable) {
|
||||
getApp().putUserData(ENABLE_IN_TESTS, enable ? Boolean.TRUE : null);
|
||||
getApp().putUserData(ACCESS_ALLOWED, null);
|
||||
}
|
||||
|
||||
private static boolean isAllAccessAllowed() {
|
||||
Application app = getApp();
|
||||
|
||||
// disable checks in tests, if not asked
|
||||
if (app.isUnitTestMode() && app.getUserData(ENABLE_IN_TESTS) != Boolean.TRUE) {
|
||||
return true;
|
||||
}
|
||||
return ACCESS_ALLOWED.getValue(app).get() > 0;
|
||||
}
|
||||
|
||||
private static Application getApp() {
|
||||
return ApplicationManager.getApplication();
|
||||
}
|
||||
|
||||
public enum UnlockOption {UNLOCK, UNLOCK_DIR, UNLOCK_ALL}
|
||||
}
|
||||
|
||||
+3
@@ -25,6 +25,7 @@ import com.intellij.openapi.fileEditor.*;
|
||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
|
||||
import com.intellij.openapi.fileEditor.impl.EditorWindow;
|
||||
import com.intellij.openapi.fileEditor.impl.EditorWithProviderComposite;
|
||||
import com.intellij.openapi.fileEditor.impl.NonProjectFileWritingAccessProvider;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -75,6 +76,8 @@ public class FileDropHandler implements EditorDropHandler {
|
||||
final VirtualFile vFile = fileSystem.refreshAndFindFileByIoFile(file);
|
||||
final FileEditorManagerEx fileEditorManager = (FileEditorManagerEx) FileEditorManager.getInstance(project);
|
||||
if (vFile != null) {
|
||||
NonProjectFileWritingAccessProvider.allowWriting(vFile);
|
||||
|
||||
if (editorWindow != null) {
|
||||
fileEditorManager.openFileWithProviders(vFile, true, editorWindow);
|
||||
}
|
||||
|
||||
+19
-2
@@ -21,17 +21,19 @@ import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.CollectionComboBoxModel;
|
||||
import com.intellij.ui.ColoredListCellRendererWrapper;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.ui.OptionsDialog;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -186,4 +188,19 @@ public class ReadOnlyStatusDialog extends OptionsDialog {
|
||||
final JRootPane pane = getRootPane();
|
||||
return pane != null ? pane.getDefaultButton() : null;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getTheseFilesMessage(Collection<VirtualFile> files) {
|
||||
boolean dirsOnly = true;
|
||||
for (VirtualFile each : files) {
|
||||
if (!each.isDirectory()) {
|
||||
dirsOnly = false;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int size = files.size();
|
||||
return StringUtil.pluralize("this", size) + " " + StringUtil.pluralize((dirsOnly ? "directory" : "file"), size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,4 +54,5 @@ com.fedot.idea.requirejs 0.24
|
||||
com.widerwille.quicklook 0.8
|
||||
com.phpuaca 1.3.1 1.2.1
|
||||
coffeescript-idea 0.1-1-gae5a
|
||||
RESTClient 1.2
|
||||
RESTClient 1.2
|
||||
krasa.nonProjectFilesUnlocker 1.0 1.1
|
||||
|
||||
+84
-79
@@ -17,6 +17,7 @@ package com.intellij.openapi.fileEditor;
|
||||
|
||||
import com.intellij.openapi.actionSystem.DataConstants;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.Result;
|
||||
import com.intellij.openapi.application.WriteAction;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
@@ -31,7 +32,6 @@ import com.intellij.openapi.module.ModifiableModuleModel;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.project.ex.ProjectManagerEx;
|
||||
import com.intellij.openapi.roots.ContentEntry;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
@@ -39,7 +39,6 @@ import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.WritingAccessProvider;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import com.intellij.testFramework.PsiTestUtil;
|
||||
import com.intellij.ui.EditorNotifications;
|
||||
import com.intellij.ui.EditorNotificationsImpl;
|
||||
import com.intellij.util.NullableFunction;
|
||||
@@ -47,18 +46,21 @@ import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class NonProjectFileAccessTest extends HeavyFileEditorManagerTestCase {
|
||||
|
||||
private Set<VirtualFile> myOpenedFiles = new THashSet<>();
|
||||
private Set<VirtualFile> myCreatedFiles = new THashSet<>();
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
EditorNotifications notifications = new EditorNotificationsImpl(getProject());
|
||||
((ComponentManagerImpl)getProject()).registerComponentInstance(EditorNotifications.class, notifications);
|
||||
NonProjectFileWritingAccessProvider.enableChecksInTests(getProject(), true);
|
||||
NonProjectFileWritingAccessProvider.enableChecksInTests(true);
|
||||
ProjectManagerEx.getInstanceEx().blockReloadingProjectOnExternalChanges();
|
||||
}
|
||||
|
||||
@@ -66,11 +68,21 @@ public class NonProjectFileAccessTest extends HeavyFileEditorManagerTestCase {
|
||||
protected void tearDown() throws Exception {
|
||||
try {
|
||||
NonProjectFileWritingAccessProvider.setCustomUnlocker(null);
|
||||
NonProjectFileWritingAccessProvider.enableChecksInTests(getProject(), false);
|
||||
NonProjectFileWritingAccessProvider.enableChecksInTests(false);
|
||||
FileEditorManager editorManager = FileEditorManager.getInstance(getProject());
|
||||
for (VirtualFile file : myOpenedFiles) {
|
||||
editorManager.closeFile(file);
|
||||
}
|
||||
ApplicationManager.getApplication().runWriteAction(() -> {
|
||||
for (VirtualFile each : myCreatedFiles) {
|
||||
try {
|
||||
each.delete(this);
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
finally {
|
||||
super.tearDown();
|
||||
@@ -91,14 +103,32 @@ public class NonProjectFileAccessTest extends HeavyFileEditorManagerTestCase {
|
||||
typeAndCheck(nonProjectFile, null, true); // still allowed after previous Unlock
|
||||
}
|
||||
|
||||
public void testDoNotLockCreatedAndCopiedFiles() throws Exception {
|
||||
VirtualFile nonProjectFile = createNonProjectFile();
|
||||
typeAndCheck(nonProjectFile, false);
|
||||
|
||||
final VirtualFile[] createdNonProject = new VirtualFile[1];
|
||||
final VirtualFile[] copiedNonProject = new VirtualFile[1];
|
||||
|
||||
new WriteAction<Object>() {
|
||||
@Override
|
||||
protected void run(@NotNull Result<Object> result) throws Throwable {
|
||||
createdNonProject[0] = nonProjectFile.getParent().createChildData(this, "createdNonProject.txt");
|
||||
copiedNonProject[0] = nonProjectFile.copy(this, nonProjectFile.getParent(), "copiedNonProject.txt");
|
||||
myCreatedFiles.add(createdNonProject[0]);
|
||||
myCreatedFiles.add(copiedNonProject[0]);
|
||||
}
|
||||
}.execute();
|
||||
|
||||
typeAndCheck(createdNonProject[0], true);
|
||||
typeAndCheck(copiedNonProject[0], true);
|
||||
|
||||
typeAndCheck(nonProjectFile, false); // original is still locked
|
||||
}
|
||||
|
||||
public void testAccessToProjectSystemFiles() throws Exception {
|
||||
PlatformTestUtil.saveProject(getProject());
|
||||
VirtualFile fileUnderProjectDir = new WriteAction<VirtualFile>() {
|
||||
@Override
|
||||
protected void run(@NotNull Result<VirtualFile> result) throws Throwable {
|
||||
result.setResult(getProject().getBaseDir().createChildData(this, "fileUnderProjectDir.txt"));
|
||||
}
|
||||
}.execute().getResultObject();
|
||||
VirtualFile fileUnderProjectDir = createFileExternally(new File(getProject().getBaseDir().getPath()));
|
||||
|
||||
assertFalse(ProjectFileIndex.SERVICE.getInstance(getProject()).isInContent(fileUnderProjectDir));
|
||||
|
||||
@@ -128,18 +158,14 @@ public class NonProjectFileAccessTest extends HeavyFileEditorManagerTestCase {
|
||||
}.execute().getResultObject();
|
||||
PlatformTestUtil.saveProject(getProject());
|
||||
|
||||
VirtualFile fileUnderModuleDir = new WriteAction<VirtualFile>() {
|
||||
@Override
|
||||
protected void run(@NotNull Result<VirtualFile> result) throws Throwable {
|
||||
result.setResult(moduleWithoutContentRoot.getModuleFile().getParent().createChildData(this, "fileUnderModuleDir.txt"));
|
||||
}
|
||||
}.execute().getResultObject();
|
||||
VirtualFile fileUnderNonProjectModuleDir
|
||||
= createFileExternally(new File(moduleWithoutContentRoot.getModuleFile().getParent().getPath()));
|
||||
|
||||
assertFalse(ProjectFileIndex.SERVICE.getInstance(getProject()).isInContent(fileUnderModuleDir));
|
||||
assertFalse(ProjectFileIndex.SERVICE.getInstance(getProject()).isInContent(fileUnderNonProjectModuleDir));
|
||||
|
||||
typeAndCheck(moduleWithoutContentRoot.getModuleFile(), true);
|
||||
typeAndCheck(myModule.getModuleFile(), true);
|
||||
typeAndCheck(fileUnderModuleDir, false);
|
||||
typeAndCheck(fileUnderNonProjectModuleDir, false);
|
||||
}
|
||||
|
||||
public void testAllowEditingInOneFileOnly() throws Exception {
|
||||
@@ -157,6 +183,31 @@ public class NonProjectFileAccessTest extends HeavyFileEditorManagerTestCase {
|
||||
typeAndCheck(nonProjectFile2, null, true);
|
||||
}
|
||||
|
||||
public void testAllowEditingFileInDirectory() throws Exception {
|
||||
VirtualFile nonProjectFileDir11 = createNonProjectFile();
|
||||
File dir = new File(nonProjectFileDir11.getParent().getPath());
|
||||
VirtualFile nonProjectFileDir12 = createFileExternally(dir);
|
||||
|
||||
File subDir = new File(dir, "subdir");
|
||||
subDir.mkdirs();
|
||||
VirtualFile nonProjectFileDirSubdir1 = createFileExternally(subDir);
|
||||
|
||||
VirtualFile nonProjectFileDir2 = createNonProjectFile();
|
||||
|
||||
typeAndCheck(nonProjectFileDir11, false);
|
||||
typeAndCheck(nonProjectFileDir12, false);
|
||||
typeAndCheck(nonProjectFileDir2, false);
|
||||
|
||||
typeAndCheck(nonProjectFileDir11, NonProjectFileWritingAccessProvider.UnlockOption.UNLOCK_DIR, true);
|
||||
|
||||
// affects other files in dir
|
||||
typeAndCheck(nonProjectFileDir12, true);
|
||||
typeAndCheck(nonProjectFileDirSubdir1, true);
|
||||
|
||||
// doesn't affect files in other dirs
|
||||
typeAndCheck(nonProjectFileDir2, false);
|
||||
}
|
||||
|
||||
public void testAllowEditingInAllFiles() throws Exception {
|
||||
VirtualFile nonProjectFile1 = createNonProjectFile();
|
||||
VirtualFile nonProjectFile2 = createNonProjectFile();
|
||||
@@ -201,57 +252,7 @@ public class NonProjectFileAccessTest extends HeavyFileEditorManagerTestCase {
|
||||
false); // can't write since denied by another write-access provider
|
||||
typeAndCheck(nonProjectFile2, true);
|
||||
}
|
||||
|
||||
public void testClearingInfoForDeletedFiles() throws Exception {
|
||||
final VirtualFile nonProjectFile1 = createNonProjectFile();
|
||||
final VirtualFile nonProjectFile2 = createNonProjectFile();
|
||||
|
||||
typeAndCheck(nonProjectFile1, false);
|
||||
typeAndCheck(nonProjectFile2, false);
|
||||
|
||||
assertNotNull(NonProjectFileWritingAccessProvider.getAccessStatus(getProject(), nonProjectFile1));
|
||||
assertNotNull(NonProjectFileWritingAccessProvider.getAccessStatus(getProject(), nonProjectFile2));
|
||||
|
||||
new WriteAction<Object>() {
|
||||
@Override
|
||||
protected void run(@NotNull Result<Object> result) throws Throwable {
|
||||
nonProjectFile1.delete(this);
|
||||
}
|
||||
}.execute();
|
||||
|
||||
assertNull(NonProjectFileWritingAccessProvider.getAccessStatus(getProject(), nonProjectFile1));
|
||||
assertNotNull(NonProjectFileWritingAccessProvider.getAccessStatus(getProject(), nonProjectFile2));
|
||||
}
|
||||
|
||||
public void testUpdatingNotificationsOnRootChanges() throws Exception {
|
||||
VirtualFile nonProjectFile1 = createNonProjectFile();
|
||||
VirtualFile nonProjectFile2 = createNonProjectFile();
|
||||
|
||||
typeAndCheck(nonProjectFile1, false);
|
||||
typeAndCheck(nonProjectFile2, false);
|
||||
|
||||
assertNotNull(NonProjectFileWritingAccessProvider.getAccessStatus(getProject(), nonProjectFile1));
|
||||
assertNotNull(NonProjectFileWritingAccessProvider.getAccessStatus(getProject(), nonProjectFile2));
|
||||
|
||||
ContentEntry contextRoot = PsiTestUtil.addContentRoot(myModule, nonProjectFile2.getParent());
|
||||
|
||||
// removing notification panel for newly added files
|
||||
assertNotNull(NonProjectFileWritingAccessProvider.getAccessStatus(getProject(), nonProjectFile1));
|
||||
assertNull(NonProjectFileWritingAccessProvider.getAccessStatus(getProject(), nonProjectFile2));
|
||||
|
||||
PsiTestUtil.removeContentEntry(myModule, contextRoot.getFile());
|
||||
|
||||
// do not add notification panel until access is requested
|
||||
assertNotNull(NonProjectFileWritingAccessProvider.getAccessStatus(getProject(), nonProjectFile1));
|
||||
assertNull(NonProjectFileWritingAccessProvider.getAccessStatus(getProject(), nonProjectFile2));
|
||||
|
||||
// but files are still not writable
|
||||
typeAndCheck(nonProjectFile1, false);
|
||||
typeAndCheck(nonProjectFile2, false);
|
||||
assertNotNull(NonProjectFileWritingAccessProvider.getAccessStatus(getProject(), nonProjectFile1));
|
||||
assertNotNull(NonProjectFileWritingAccessProvider.getAccessStatus(getProject(), nonProjectFile2));
|
||||
}
|
||||
|
||||
|
||||
public void testCheckingExtensions() throws Exception {
|
||||
VirtualFile nonProjectFile1 = createNonProjectFile();
|
||||
VirtualFile nonProjectFile2 = createNonProjectFile();
|
||||
@@ -312,23 +313,27 @@ public class NonProjectFileAccessTest extends HeavyFileEditorManagerTestCase {
|
||||
|
||||
@NotNull
|
||||
private VirtualFile createProjectFile() {
|
||||
return new WriteAction<VirtualFile>() {
|
||||
@Override
|
||||
protected void run(@NotNull Result<VirtualFile> result) throws Throwable {
|
||||
result.setResult(ModuleRootManager.getInstance(myModule).getContentRoots()[0].createChildData(this, "projectFile.txt"));
|
||||
}
|
||||
}.execute().getResultObject();
|
||||
return createFileExternally(new File(ModuleRootManager.getInstance(myModule).getContentRoots()[0].getPath()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private VirtualFile createNonProjectFile() {
|
||||
return new WriteAction<VirtualFile>() {
|
||||
private VirtualFile createNonProjectFile() throws IOException {
|
||||
return createFileExternally(FileUtil.createTempDirectory("tmp", null));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private VirtualFile createFileExternally(File dir) {
|
||||
VirtualFile result = new WriteAction<VirtualFile>() {
|
||||
@Override
|
||||
protected void run(@NotNull Result<VirtualFile> result) throws Throwable {
|
||||
VirtualFile tmp = LocalFileSystem.getInstance().findFileByIoFile(FileUtil.createTempDirectory("tmp", null));
|
||||
result.setResult(tmp.createChildData(this, "nonProjectFile.txt"));
|
||||
// create externally, since files created via VFS are marked for editing automatically
|
||||
File file = new File(dir, FileUtil.createSequentFileName(dir, "file", "txt"));
|
||||
file.createNewFile();
|
||||
result.setResult(LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file));
|
||||
}
|
||||
}.execute().getResultObject();
|
||||
myCreatedFiles.add(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void typeAndCheck(VirtualFile file, boolean fileHasBeenChanged) {
|
||||
|
||||
+4
-4
@@ -14,7 +14,7 @@
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="3" anchor="2" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="etched"/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="e62df" class="javax.swing.JRadioButton" binding="myShelveChangesRadioButton" default-binding="true">
|
||||
<constraints>
|
||||
@@ -51,15 +51,15 @@
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<component id="dbd63" class="javax.swing.JLabel">
|
||||
<component id="dbd63" class="javax.swing.JLabel" binding="myListTitle">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="<html>These files do not belong to active changelist:</html>"/>
|
||||
<text value="list title"/>
|
||||
</properties>
|
||||
</component>
|
||||
<scrollpane class="com.intellij.ui.components.JBScrollPane" id="6c540">
|
||||
<scrollpane id="6c540" class="com.intellij.ui.components.JBScrollPane">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
|
||||
+7
@@ -18,11 +18,13 @@ package com.intellij.openapi.vcs.changes.conflicts;
|
||||
import com.intellij.openapi.options.ShowSettingsUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
import com.intellij.openapi.vcs.changes.ChangeList;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManagerImpl;
|
||||
import com.intellij.openapi.vcs.readOnlyHandler.FileListRenderer;
|
||||
import com.intellij.openapi.vcs.readOnlyHandler.ReadOnlyStatusDialog;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.CollectionListModel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -42,6 +44,7 @@ public class ChangelistConflictDialog extends DialogWrapper {
|
||||
private JRadioButton myMoveChangesToActiveRadioButton;
|
||||
private JRadioButton mySwitchToChangelistRadioButton;
|
||||
private JRadioButton myIgnoreRadioButton;
|
||||
private JLabel myListTitle;
|
||||
private JList myFileList;
|
||||
|
||||
private final Project myProject;
|
||||
@@ -51,6 +54,10 @@ public class ChangelistConflictDialog extends DialogWrapper {
|
||||
myProject = project;
|
||||
|
||||
setTitle("Resolve Changelist Conflict");
|
||||
|
||||
myListTitle.setText(StringUtil.capitalize(ReadOnlyStatusDialog.getTheseFilesMessage(conflicts))
|
||||
+ " " + (conflicts.size() > 1 ? "do" : "does")
|
||||
+ " not belong to the active changelist:");
|
||||
|
||||
myFileList.setCellRenderer(new FileListRenderer());
|
||||
myFileList.setModel(new CollectionListModel(conflicts));
|
||||
|
||||
Reference in New Issue
Block a user