mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 20:39:40 +07:00
encoding fixes: IDEA-99729, IDEA-99926, IDEA-99809, IDEA-99945
This commit is contained in:
@@ -52,7 +52,9 @@ public class LossyEncodingTest extends LightDaemonAnalyzerTestCase {
|
||||
|
||||
public void testText() throws Exception {
|
||||
doTest("Text.txt");
|
||||
EncodingManager.getInstance().setEncoding(myVFile, Charset.forName("US-ASCII"));
|
||||
Charset ascii = CharsetToolkit.forName("US-ASCII");
|
||||
EncodingManager.getInstance().setEncoding(myVFile, ascii);
|
||||
assertEquals(ascii, myVFile.getCharset());
|
||||
int start = myEditor.getCaretModel().getOffset();
|
||||
type((char)0x445);
|
||||
type((char)0x438);
|
||||
|
||||
@@ -22,11 +22,14 @@
|
||||
*/
|
||||
package com.intellij.codeInspection;
|
||||
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.lang.properties.charset.Native2AsciiCharset;
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.actionSystem.impl.SimpleDataContext;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
|
||||
@@ -38,7 +41,6 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.encoding.ChooseFileEncodingAction;
|
||||
import com.intellij.openapi.vfs.encoding.ReloadFileInOtherEncodingAction;
|
||||
import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
|
||||
import com.intellij.openapi.wm.impl.status.EncodingActionsPair;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiUtilBase;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
@@ -48,6 +50,7 @@ import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
@@ -215,10 +218,22 @@ public class LossyEncodingInspection extends LocalInspectionTool {
|
||||
VirtualFile virtualFile = psiFile.getVirtualFile();
|
||||
|
||||
Editor editor = PsiUtilBase.findEditor(psiFile);
|
||||
DataContext dataContext =
|
||||
EncodingActionsPair.createDataContext(editor, editor == null ? null : editor.getComponent(), virtualFile, project);
|
||||
DataContext dataContext = createDataContext(editor, editor == null ? null : editor.getComponent(), virtualFile, project);
|
||||
ReloadFileInOtherEncodingAction reloadAction = new ReloadFileInOtherEncodingAction();
|
||||
reloadAction.actionPerformed(new AnActionEvent(null, dataContext, "", reloadAction.getTemplatePresentation(), ActionManager.getInstance(), 0));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static DataContext createDataContext(Editor editor, Component component, VirtualFile selectedFile, Project project) {
|
||||
DataContext parent = DataManager.getInstance().getDataContext(component);
|
||||
return SimpleDataContext.getSimpleContext(PlatformDataKeys.VIRTUAL_FILE.getName(), selectedFile,
|
||||
SimpleDataContext.getSimpleContext(PlatformDataKeys.PROJECT.getName(), project,
|
||||
SimpleDataContext.getSimpleContext(
|
||||
PlatformDataKeys.CONTEXT_COMPONENT.getName(),
|
||||
editor == null ? null : editor.getComponent(),
|
||||
parent)));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileFilter;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.ui.tree.AbstractFileTreeTable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -94,7 +95,12 @@ class EncodingFileTreeTable extends AbstractFileTreeTable<Charset> {
|
||||
@NotNull
|
||||
@Override
|
||||
protected DefaultActionGroup createPopupActionGroup(JComponent button) {
|
||||
return createGroup("<Clear>", "Encoding ''{1}''", null, null);
|
||||
return createGroup("<Clear>", null, new Function<Charset, String>() {
|
||||
@Override
|
||||
public String fun(Charset charset) {
|
||||
return "Choose encoding '"+charset+"'";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.ScrollPaneFactory;
|
||||
import com.intellij.ui.table.JBTable;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.PlatformUtils;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -109,7 +110,12 @@ public class FileEncodingConfigurable implements SearchableConfigurable, Optiona
|
||||
@NotNull
|
||||
@Override
|
||||
protected DefaultActionGroup createPopupActionGroup(JComponent button) {
|
||||
return createGroup("<System Default>", "Choose encoding ''{1}''", selected.get(), null);
|
||||
return createGroup("<System Default>", selected.get(), new Function<Charset, String>() {
|
||||
@Override
|
||||
public String fun(Charset charset) {
|
||||
return "Choose encoding '"+charset+"'";
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
parentPanel.removeAll();
|
||||
@@ -161,7 +167,10 @@ public class FileEncodingConfigurable implements SearchableConfigurable, Optiona
|
||||
|
||||
@Override
|
||||
public void apply() throws ConfigurationException {
|
||||
Charset projectCharset = mySelectedProjectCharset.get();
|
||||
|
||||
Map<VirtualFile,Charset> result = myTreeView.getValues();
|
||||
result.put(null, projectCharset);
|
||||
EncodingProjectManager encodingManager = EncodingProjectManager.getInstance(myProject);
|
||||
encodingManager.setMapping(result);
|
||||
encodingManager.setDefaultCharsetForPropertiesFiles(null, mySelectedCharsetForPropertiesFiles.get());
|
||||
@@ -170,8 +179,6 @@ public class FileEncodingConfigurable implements SearchableConfigurable, Optiona
|
||||
|
||||
Charset ideCharset = mySelectedIdeCharset.get();
|
||||
EncodingManager.getInstance().setDefaultCharsetName(ideCharset == null ? "" : ideCharset.name());
|
||||
Charset projectCharset = mySelectedProjectCharset.get();
|
||||
EncodingProjectManager.getInstance(myProject).setEncoding(null, projectCharset);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
/**
|
||||
* @author cdr
|
||||
@@ -32,8 +31,8 @@ abstract class ChangeFileEncodingTo extends AnAction implements DumbAware {
|
||||
private final VirtualFile myFile;
|
||||
private final Charset myCharset;
|
||||
|
||||
ChangeFileEncodingTo(@Nullable VirtualFile file, @NotNull Charset charset, @NotNull String pattern) {
|
||||
super(charset.displayName(), MessageFormat.format(pattern, file == null ? null : file.getName(), charset.displayName()), null);
|
||||
ChangeFileEncodingTo(@Nullable VirtualFile file, @NotNull Charset charset) {
|
||||
super(charset.displayName());
|
||||
myFile = file;
|
||||
myCharset = charset;
|
||||
}
|
||||
|
||||
@@ -33,10 +33,10 @@ import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.FileTypes;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Function;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -81,14 +81,17 @@ public abstract class ChooseFileEncodingAction extends ComboBoxAction {
|
||||
private void fillCharsetActions(@NotNull DefaultActionGroup group,
|
||||
@Nullable VirtualFile virtualFile,
|
||||
@NotNull List<Charset> charsets,
|
||||
@Nullable final Condition<Charset> charsetFilter,
|
||||
@NotNull String pattern) {
|
||||
@NotNull final Function<Charset, String> charsetFilter) {
|
||||
for (final Charset slave : charsets) {
|
||||
ChangeFileEncodingTo action = new ChangeFileEncodingTo(virtualFile, slave, pattern) {
|
||||
ChangeFileEncodingTo action = new ChangeFileEncodingTo(virtualFile, slave) {
|
||||
{
|
||||
if (charsetFilter != null && !charsetFilter.value(slave)) {
|
||||
String description = charsetFilter.fun(slave);
|
||||
if (description == null) {
|
||||
getTemplatePresentation().setIcon(AllIcons.General.Warning);
|
||||
}
|
||||
else {
|
||||
getTemplatePresentation().setDescription(description);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -170,9 +173,8 @@ public abstract class ChooseFileEncodingAction extends ComboBoxAction {
|
||||
|
||||
@NotNull
|
||||
public DefaultActionGroup createGroup(@Nullable("null means do not show 'clear' text") String clearItemText,
|
||||
@NotNull String pattern,
|
||||
Charset alreadySelected,
|
||||
@Nullable Condition<Charset> charsetFilter) {
|
||||
@NotNull Function<Charset, String> charsetFilter) {
|
||||
DefaultActionGroup group = new DefaultActionGroup();
|
||||
List<Charset> favorites = new ArrayList<Charset>(EncodingManager.getInstance().getFavorites());
|
||||
Collections.sort(favorites);
|
||||
@@ -184,14 +186,14 @@ public abstract class ChooseFileEncodingAction extends ComboBoxAction {
|
||||
group.add(new ClearThisFileEncodingAction(myVirtualFile, clearItemText));
|
||||
}
|
||||
if (favorites.isEmpty() && clearItemText == null) {
|
||||
fillCharsetActions(group, myVirtualFile, Arrays.asList(CharsetToolkit.getAvailableCharsets()), charsetFilter, pattern);
|
||||
fillCharsetActions(group, myVirtualFile, Arrays.asList(CharsetToolkit.getAvailableCharsets()), charsetFilter);
|
||||
}
|
||||
else {
|
||||
fillCharsetActions(group, myVirtualFile, favorites, charsetFilter, pattern);
|
||||
fillCharsetActions(group, myVirtualFile, favorites, charsetFilter);
|
||||
|
||||
DefaultActionGroup more = new DefaultActionGroup("more", true);
|
||||
group.add(more);
|
||||
fillCharsetActions(more, myVirtualFile, Arrays.asList(CharsetToolkit.getAvailableCharsets()), charsetFilter, pattern);
|
||||
fillCharsetActions(more, myVirtualFile, Arrays.asList(CharsetToolkit.getAvailableCharsets()), charsetFilter);
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
@@ -215,26 +216,21 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager {
|
||||
myMapping.put(virtualFileOrDir, charset);
|
||||
}
|
||||
myModificationCount++;
|
||||
reloadDir(virtualFileOrDir, charset);
|
||||
if (virtualFileOrDir != null && !virtualFileOrDir.isDirectory()) {
|
||||
virtualFileOrDir.setCharset(null);
|
||||
}
|
||||
reloadAllFilesUnder(virtualFileOrDir);
|
||||
}
|
||||
|
||||
private static void setAndSaveOrReload(@NotNull VirtualFile virtualFileOrDir, Charset charset) {
|
||||
virtualFileOrDir.setCharset(charset);
|
||||
saveOrReload(virtualFileOrDir);
|
||||
private static void clearAndReload(@NotNull VirtualFile virtualFileOrDir) {
|
||||
virtualFileOrDir.setCharset(null);
|
||||
reload(virtualFileOrDir);
|
||||
}
|
||||
|
||||
private static void saveOrReload(@NotNull VirtualFile virtualFile) {
|
||||
private static void reload(@NotNull VirtualFile virtualFile) {
|
||||
FileDocumentManager documentManager = FileDocumentManager.getInstance();
|
||||
Document document = documentManager.getDocument(virtualFile);
|
||||
if (documentManager.isFileModified(virtualFile)) {
|
||||
if (document != null) {
|
||||
documentManager.saveDocument(document);
|
||||
}
|
||||
}
|
||||
else {
|
||||
((VirtualFileListener)documentManager)
|
||||
.contentsChanged(new VirtualFileEvent(null, virtualFile, virtualFile.getName(), virtualFile.getParent()));
|
||||
}
|
||||
((VirtualFileListener)documentManager)
|
||||
.contentsChanged(new VirtualFileEvent(null, virtualFile, virtualFile.getName(), virtualFile.getParent()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -263,6 +259,7 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager {
|
||||
@Override
|
||||
public void setMapping(@NotNull final Map<VirtualFile, Charset> result) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
FileDocumentManager.getInstance().saveAllDocuments(); // consider all files as unmodified
|
||||
final Map<VirtualFile, Charset> map = new HashMap<VirtualFile, Charset>(result.size());
|
||||
ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex();
|
||||
for (Map.Entry<VirtualFile, Charset> entry : result.entrySet()) {
|
||||
@@ -284,16 +281,17 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager {
|
||||
myMapping.clear();
|
||||
myMapping.putAll(map);
|
||||
|
||||
final Processor<VirtualFile> reloadProcessor = createChangeCharsetProcessor();
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Set<VirtualFile> changed = new HashSet<VirtualFile>(map.keySet());
|
||||
changed.addAll(oldMapping.keySet());
|
||||
for (VirtualFile changedFile : changed) {
|
||||
Charset newCharset = map.get(changedFile);
|
||||
final Charset newCharset = map.get(changedFile);
|
||||
Charset oldCharset = oldMapping.get(changedFile);
|
||||
if (!Comparing.equal(newCharset, oldCharset)) {
|
||||
reloadDir(changedFile, newCharset);
|
||||
reloadDir(changedFile, reloadProcessor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -302,10 +300,29 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager {
|
||||
myModificationCount++;
|
||||
}
|
||||
|
||||
private void reloadDir(VirtualFile file, final Charset newCharset) {
|
||||
private static Processor<VirtualFile> createChangeCharsetProcessor() {
|
||||
return new Processor<VirtualFile>() {
|
||||
@Override
|
||||
public boolean process(final VirtualFile file) {
|
||||
if (!(file instanceof VirtualFileSystemEntry)) return false;
|
||||
Document cachedDocument = FileDocumentManager.getInstance().getCachedDocument(file);
|
||||
if (cachedDocument == null) return true;
|
||||
ProgressManager.progress("Reloading files...", file.getPresentableUrl());
|
||||
UIUtil.invokeLaterIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
clearAndReload(file);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void reloadDir(VirtualFile file, @NotNull final Processor<VirtualFile> processor) {
|
||||
if (file == null) {
|
||||
for (VirtualFile virtualFile : ProjectRootManager.getInstance(myProject).getContentRoots()) {
|
||||
reloadDir(virtualFile, newCharset);
|
||||
reloadDir(virtualFile, processor);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -313,20 +330,7 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager {
|
||||
VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() {
|
||||
@Override
|
||||
public boolean visitFile(@NotNull final VirtualFile file) {
|
||||
if (!(file instanceof VirtualFileSystemEntry)) return false;
|
||||
if (!file.isCharsetSet()) return true;
|
||||
Charset oldCharset = file.getCharset();
|
||||
|
||||
if (!Comparing.equal(newCharset, oldCharset)) {
|
||||
ProgressManager.progress("Reloading files...", file.getPresentableUrl());
|
||||
UIUtil.invokeLaterIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setAndSaveOrReload(file, newCharset);
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
return processor.process(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -346,7 +350,39 @@ public class EncodingProjectManagerImpl extends EncodingProjectManager {
|
||||
|
||||
@Override
|
||||
public void setUseUTFGuessing(final VirtualFile virtualFile, final boolean useUTFGuessing) {
|
||||
myUseUTFGuessing = useUTFGuessing;
|
||||
if (myUseUTFGuessing != useUTFGuessing) {
|
||||
myUseUTFGuessing = useUTFGuessing;
|
||||
reloadAllFilesUnder(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void reloadAllFilesUnder(final VirtualFile root) {
|
||||
FileDocumentManager.getInstance().saveAllDocuments(); // consider all files as unmodified
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
reloadDir(root, new Processor<VirtualFile>() {
|
||||
@Override
|
||||
public boolean process(final VirtualFile file) {
|
||||
if (!(file instanceof VirtualFileSystemEntry)) return true;
|
||||
Document cachedDocument = FileDocumentManager.getInstance().getCachedDocument(file);
|
||||
if (cachedDocument != null) {
|
||||
ProgressManager.progress("Reloading file...", file.getPresentableUrl());
|
||||
UIUtil.invokeLaterIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
reload(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (file.isCharsetSet()) {
|
||||
file.setCharset(null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}, "Reload Files", false, myProject);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,10 +18,8 @@ package com.intellij.openapi.vfs.encoding;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.wm.impl.status.EncodingActionsPair;
|
||||
import com.intellij.pom.Navigatable;
|
||||
@@ -55,9 +53,7 @@ public class FileChangeEncodingGroup extends DefaultActionGroup implements DumbA
|
||||
virtualFile = null;
|
||||
}
|
||||
|
||||
Editor editor = e.getData(PlatformDataKeys.EDITOR);
|
||||
boolean enabled =
|
||||
encodingActionsPair.areActionsEnabled(null, editor, editor == null ? null : editor.getComponent(), virtualFile, getEventProject(e));
|
||||
boolean enabled = virtualFile != null && EncodingActionsPair.checkSomeActionEnabled(virtualFile) == null;
|
||||
removeAll();
|
||||
if (enabled) {
|
||||
addAll(encodingActionsPair.createActionGroup());
|
||||
|
||||
@@ -32,7 +32,6 @@ import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.ui.popup.ListPopup;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -40,6 +39,7 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileEvent;
|
||||
import com.intellij.openapi.vfs.VirtualFileListener;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -54,14 +54,15 @@ import java.util.Arrays;
|
||||
* @author cdr
|
||||
*/
|
||||
public class ReloadFileInOtherEncodingAction extends AnAction implements DumbAware {
|
||||
protected String text;
|
||||
|
||||
public ReloadFileInOtherEncodingAction() {
|
||||
text = "Reload in...";
|
||||
this("Reload in...");
|
||||
}
|
||||
protected ReloadFileInOtherEncodingAction(String text) {
|
||||
super(text);
|
||||
}
|
||||
|
||||
@Nullable("null means disabled, otherwise it's the document and the action description")
|
||||
protected Pair<Document, String> checkEnabled(@NotNull VirtualFile virtualFile) {
|
||||
public Pair<Document, String> checkEnabled(@NotNull VirtualFile virtualFile) {
|
||||
String failReason = ChooseFileEncodingAction.checkCanReload(virtualFile).second;
|
||||
if (failReason != null) return null;
|
||||
FileDocumentManager documentManager = FileDocumentManager.getInstance();
|
||||
@@ -82,7 +83,6 @@ public class ReloadFileInOtherEncodingAction extends AnAction implements DumbAwa
|
||||
e.getPresentation().setEnabled(pair != null);
|
||||
if (pair != null) {
|
||||
e.getPresentation().setDescription(pair.second);
|
||||
e.getPresentation().setText(text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,9 +112,9 @@ public class ReloadFileInOtherEncodingAction extends AnAction implements DumbAwa
|
||||
@NotNull
|
||||
@Override
|
||||
protected DefaultActionGroup createPopupActionGroup(JComponent button) {
|
||||
return createGroup(null, "Reload file ''{0}'' in''{1}''", myFile.getCharset(), new Condition<Charset>() {
|
||||
return createGroup(null, myFile.getCharset(), new Function<Charset, String>() {
|
||||
@Override
|
||||
public boolean value(Charset charset) {
|
||||
public String fun(Charset charset) {
|
||||
return isCompatibleCharset(myFile, bytes, document.getText(), charset);
|
||||
}
|
||||
}); // no 'clear'
|
||||
@@ -129,8 +129,8 @@ public class ReloadFileInOtherEncodingAction extends AnAction implements DumbAwa
|
||||
}
|
||||
.createPopupActionGroup(null);
|
||||
|
||||
final ListPopup popup = JBPopupFactory.getInstance().createActionGroupPopup(
|
||||
text, group, e.getDataContext(), JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, false);
|
||||
final ListPopup popup = JBPopupFactory.getInstance().createActionGroupPopup(getTemplatePresentation().getText(),
|
||||
group, e.getDataContext(), JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, false);
|
||||
popup.showInBestPositionFor(e.getDataContext());
|
||||
}
|
||||
|
||||
@@ -176,8 +176,8 @@ public class ReloadFileInOtherEncodingAction extends AnAction implements DumbAwa
|
||||
@NotNull String text,
|
||||
@NotNull Charset charset,
|
||||
@NotNull String action) {
|
||||
if (!isCompatibleCharset(virtualFile, bytes, text, charset)) {
|
||||
int res = Messages.showDialog("Encoding '" + charset.displayName() + "' does not support some characters from the text.",
|
||||
if (isCompatibleCharset(virtualFile, bytes, text, charset) == null) {
|
||||
int res = Messages.showDialog("File '"+virtualFile.getName()+"' most likely wasn't stored in the '" + charset.displayName() + "' encoding.",
|
||||
"Incompatible Encoding: " + charset.displayName(), new String[]{action + " anyway", "Cancel"}, 1,
|
||||
AllIcons.General.WarningDialog);
|
||||
if (res != 0) return false;
|
||||
@@ -209,7 +209,8 @@ public class ReloadFileInOtherEncodingAction extends AnAction implements DumbAwa
|
||||
}
|
||||
|
||||
// charset filter
|
||||
public boolean isCompatibleCharset(@NotNull VirtualFile virtualFile, @NotNull byte[] bytesOnDisk, @NotNull String text, @NotNull Charset charset) {
|
||||
return canBeLoadedIn(virtualFile, bytesOnDisk, charset);
|
||||
@Nullable("null means incompatible")
|
||||
public String isCompatibleCharset(@NotNull VirtualFile virtualFile, @NotNull byte[] bytesOnDisk, @NotNull String text, @NotNull Charset charset) {
|
||||
return canBeLoadedIn(virtualFile, bytesOnDisk, charset) ? "Reload file '" + virtualFile.getName() + "' in '" + charset + "'" : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.openapi.vfs.encoding;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
@@ -25,8 +26,6 @@ import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileEvent;
|
||||
import com.intellij.openapi.vfs.VirtualFileListener;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -38,9 +37,9 @@ import java.text.MessageFormat;
|
||||
/**
|
||||
* @author cdr
|
||||
*/
|
||||
public class ConvertFileEncodingAction extends ReloadFileInOtherEncodingAction {
|
||||
public ConvertFileEncodingAction() {
|
||||
text = "Convert to...";
|
||||
public class SaveFileInEncodingAction extends ReloadFileInOtherEncodingAction {
|
||||
public SaveFileInEncodingAction() {
|
||||
super("Save in...");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -61,18 +60,24 @@ public class ConvertFileEncodingAction extends ReloadFileInOtherEncodingAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompatibleCharset(@NotNull VirtualFile virtualFile, @NotNull byte[] bytesOnDisk, @NotNull String text, @NotNull Charset charset) {
|
||||
return canConvertTo(virtualFile, text, charset);
|
||||
@Nullable("null means incompatible")
|
||||
public String isCompatibleCharset(@NotNull VirtualFile virtualFile, @NotNull byte[] bytesOnDisk, @NotNull String text, @NotNull Charset charset) {
|
||||
return isSafeToConvertTo(virtualFile, text, charset) ? "Convert and save file '" + virtualFile.getName() + "' in '" + charset + "'" : null;
|
||||
}
|
||||
|
||||
private static boolean canConvertTo(@NotNull VirtualFile virtualFile, @NotNull String text, @NotNull Charset charset) {
|
||||
Pair<Charset, byte[]> chosen = LoadTextUtil.chooseMostlyHarmlessCharset(virtualFile.getCharset(), charset, text);
|
||||
private static boolean isSafeToConvertTo(@NotNull VirtualFile virtualFile, @NotNull String text, @NotNull Charset charset) {
|
||||
try {
|
||||
Pair<Charset, byte[]> chosen = LoadTextUtil.chooseMostlyHarmlessCharset(virtualFile.getCharset(), charset, text);
|
||||
|
||||
byte[] buffer = chosen.second;
|
||||
byte[] buffer = chosen.second;
|
||||
|
||||
CharSequence textLoadedBack = LoadTextUtil.getTextByBinaryPresentation(buffer, charset);
|
||||
CharSequence textLoadedBack = LoadTextUtil.getTextByBinaryPresentation(buffer, charset);
|
||||
|
||||
return text.equals(textLoadedBack.toString());
|
||||
return text.equals(textLoadedBack.toString());
|
||||
}
|
||||
catch (UnsupportedOperationException e) { // unsupported encoding
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -82,43 +87,48 @@ public class ConvertFileEncodingAction extends ReloadFileInOtherEncodingAction {
|
||||
@NotNull byte[] bytes,
|
||||
@NotNull final Charset charset) {
|
||||
if (!checkCompatibleEncodingAndWarn(virtualFile, bytes, document.getText(), charset, "Convert")) return;
|
||||
convert(document, editor, virtualFile, charset);
|
||||
saveIn(document, editor, virtualFile, charset);
|
||||
}
|
||||
|
||||
public static void convert(@NotNull Document document, Editor editor, @NotNull VirtualFile virtualFile, @NotNull Charset charset) {
|
||||
@Override
|
||||
protected boolean checkCompatibleEncodingAndWarn(@NotNull VirtualFile virtualFile,
|
||||
@NotNull byte[] bytes,
|
||||
@NotNull String text,
|
||||
@NotNull Charset charset,
|
||||
@NotNull String action) {
|
||||
if (isCompatibleCharset(virtualFile, bytes, text, charset) == null) {
|
||||
int res = Messages.showDialog("Encoding '" + charset.displayName() + "' does not support some characters from the text.",
|
||||
"Incompatible Encoding: " + charset.displayName(), new String[]{action + " anyway", "Cancel"}, 1,
|
||||
AllIcons.General.WarningDialog);
|
||||
if (res != 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void saveIn(@NotNull Document document, Editor editor, @NotNull VirtualFile virtualFile, @NotNull Charset charset) {
|
||||
FileDocumentManager documentManager = FileDocumentManager.getInstance();
|
||||
if (documentManager.isFileModified(virtualFile)) {
|
||||
EncodingManager.getInstance().setEncoding(virtualFile, charset);
|
||||
|
||||
LoadTextUtil.setCharsetWasDetectedFromBytes(virtualFile, null);
|
||||
|
||||
documentManager.saveDocument(document);
|
||||
documentManager.saveDocument(document);
|
||||
Project project = ProjectLocator.getInstance().guessProjectForFile(virtualFile);
|
||||
boolean writable = project == null ? virtualFile.isWritable() : ReadonlyStatusHandler.ensureFilesWritable(project, virtualFile);
|
||||
if (!writable) {
|
||||
CommonRefactoringUtil
|
||||
.showErrorHint(project, editor, "Cannot save the file " + virtualFile.getPresentableUrl(), "Unable to Save", null);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
Project project = ProjectLocator.getInstance().guessProjectForFile(virtualFile);
|
||||
boolean writable = project == null ? virtualFile.isWritable() : ReadonlyStatusHandler.ensureFilesWritable(project, virtualFile);
|
||||
if (!writable) {
|
||||
CommonRefactoringUtil
|
||||
.showErrorHint(project, editor, "Cannot save the file " + virtualFile.getPresentableUrl(), "Unable to Save", null);
|
||||
return;
|
||||
}
|
||||
|
||||
virtualFile.setCharset(charset);
|
||||
try {
|
||||
LoadTextUtil.write(project, virtualFile, virtualFile, document.getText(), document.getModificationStamp());
|
||||
}
|
||||
catch (IOException io) {
|
||||
Messages.showErrorDialog(project, io.getMessage(), "Error Writing File");
|
||||
}
|
||||
|
||||
EncodingManager.getInstance().setEncoding(virtualFile, charset);
|
||||
|
||||
((VirtualFileListener)documentManager).contentsChanged(new VirtualFileEvent(null, virtualFile, virtualFile.getName(), virtualFile.getParent()));
|
||||
virtualFile.setCharset(charset);
|
||||
try {
|
||||
LoadTextUtil.write(project, virtualFile, virtualFile, document.getText(), document.getModificationStamp());
|
||||
}
|
||||
catch (IOException io) {
|
||||
Messages.showErrorDialog(project, io.getMessage(), "Error Writing File");
|
||||
}
|
||||
|
||||
EncodingManager.getInstance().setEncoding(virtualFile, charset);
|
||||
}
|
||||
|
||||
@Nullable("null means enabled, notnull means disabled and contains error message")
|
||||
private static String checkCanConvert(@NotNull VirtualFile virtualFile) {
|
||||
public static String checkCanConvert(@NotNull VirtualFile virtualFile) {
|
||||
if (virtualFile.isDirectory()) {
|
||||
return "file is a directory";
|
||||
}
|
||||
@@ -15,42 +15,27 @@
|
||||
*/
|
||||
package com.intellij.openapi.wm.impl.status;
|
||||
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.actionSystem.impl.SimpleDataContext;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.encoding.ConvertFileEncodingAction;
|
||||
import com.intellij.openapi.vfs.encoding.ChooseFileEncodingAction;
|
||||
import com.intellij.openapi.vfs.encoding.ReloadFileInOtherEncodingAction;
|
||||
import com.intellij.openapi.vfs.encoding.SaveFileInEncodingAction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.InputEvent;
|
||||
|
||||
public class EncodingActionsPair {
|
||||
private final ConvertFileEncodingAction convert = new ConvertFileEncodingAction();
|
||||
private final SaveFileInEncodingAction save = new SaveFileInEncodingAction();
|
||||
private final ReloadFileInOtherEncodingAction reload = new ReloadFileInOtherEncodingAction();
|
||||
|
||||
public boolean areActionsEnabled(InputEvent e,Editor editor, Component component, VirtualFile selectedFile, Project project) {
|
||||
DataContext dataContext = createDataContext(editor, component, selectedFile, project);
|
||||
convert.update(new AnActionEvent(e, dataContext, "", convert.getTemplatePresentation(), ActionManager.getInstance(), 0));
|
||||
reload.update(new AnActionEvent(e, dataContext, "", reload.getTemplatePresentation(), ActionManager.getInstance(), 0));
|
||||
return convert.getTemplatePresentation().isEnabled() || reload.getTemplatePresentation().isEnabled();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static DataContext createDataContext(Editor editor, Component component, VirtualFile selectedFile, Project project) {
|
||||
DataContext parent = DataManager.getInstance().getDataContext(component);
|
||||
return SimpleDataContext.getSimpleContext(PlatformDataKeys.VIRTUAL_FILE.getName(), selectedFile,
|
||||
SimpleDataContext.getSimpleContext(PlatformDataKeys.PROJECT.getName(), project,
|
||||
SimpleDataContext.getSimpleContext(PlatformDataKeys.CONTEXT_COMPONENT.getName(), editor == null ? null : editor.getComponent(),
|
||||
parent)));
|
||||
// null means enabled, error description otherwise
|
||||
public static String checkSomeActionEnabled(@NotNull VirtualFile selectedFile) {
|
||||
String saveError = SaveFileInEncodingAction.checkCanConvert(selectedFile);
|
||||
String reloadError = ChooseFileEncodingAction.checkCanReload(selectedFile).second;
|
||||
return saveError == null ? reloadError : saveError;
|
||||
}
|
||||
|
||||
public DefaultActionGroup createActionGroup() {
|
||||
DefaultActionGroup group = new DefaultActionGroup();
|
||||
group.add(convert);
|
||||
group.add(save);
|
||||
group.add(reload);
|
||||
|
||||
return group;
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
|
||||
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.ui.popup.ListPopup;
|
||||
@@ -207,14 +208,15 @@ public class EncodingPanel extends EditorBasedWidget implements StatusBarWidget.
|
||||
@Override
|
||||
public void run() {
|
||||
VirtualFile file = getSelectedFile();
|
||||
Charset charset = cachedCharsetFromContent(file);
|
||||
String fromBytes = file == null ? null : LoadTextUtil.wasCharsetDetectedFromBytes(file);
|
||||
Charset charset = fromBytes == null ? cachedCharsetFromContent(file) : null;
|
||||
if (charset == null && file != null) charset = file.getCharset();
|
||||
|
||||
String text = charset == null ? "" : charset.displayName();
|
||||
actionEnabled = encodingActionsPair.areActionsEnabled(null,getEditor(), (Component)myStatusBar, file, getProject());
|
||||
String failReason = file == null ? null : EncodingActionsPair.checkSomeActionEnabled(file);
|
||||
actionEnabled = file != null && failReason == null;
|
||||
|
||||
Pair<Charset,String> check = file == null ? null : ChooseFileEncodingAction.checkCanReload(file);
|
||||
String failReason = check == null ? null : check.second;
|
||||
String toolTip = "File Encoding" +
|
||||
(check == null || check.first == null ? "" : ": "+check.first.displayName()) +
|
||||
(failReason == null ? "" : actionEnabled ? " ("+failReason+")" : " (change disabled: " + failReason + ")");
|
||||
|
||||
Reference in New Issue
Block a user