cache charset from content
[fedora-idea.git] / platform-impl / src / com / intellij / openapi / vfs / encoding / ChooseFileEncodingAction.java
blobf0d1d8b1f41ef0e4bdd4887aee1db2bc8c57a6f9
1 /*
2 * Created by IntelliJ IDEA.
3 * User: cdr
4 * Date: Jul 19, 2007
5 * Time: 5:53:46 PM
6 */
7 package com.intellij.openapi.vfs.encoding;
9 import com.intellij.openapi.actionSystem.AnAction;
10 import com.intellij.openapi.actionSystem.AnActionEvent;
11 import com.intellij.openapi.actionSystem.DefaultActionGroup;
12 import com.intellij.openapi.actionSystem.ex.ComboBoxAction;
13 import com.intellij.openapi.editor.Document;
14 import com.intellij.openapi.fileEditor.FileDocumentManager;
15 import com.intellij.openapi.fileTypes.FileType;
16 import com.intellij.openapi.fileTypes.FileTypeManager;
17 import com.intellij.openapi.fileTypes.LanguageFileType;
18 import com.intellij.openapi.fileTypes.StdFileTypes;
19 import com.intellij.openapi.project.Project;
20 import com.intellij.openapi.util.Key;
21 import com.intellij.openapi.util.Pair;
22 import com.intellij.openapi.vfs.CharsetToolkit;
23 import com.intellij.openapi.vfs.VirtualFile;
24 import org.jetbrains.annotations.NotNull;
25 import org.jetbrains.annotations.Nullable;
27 import javax.swing.*;
28 import java.nio.charset.Charset;
29 import java.nio.charset.CharsetDecoder;
30 import java.nio.charset.CharsetEncoder;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Collections;
34 import java.util.List;
36 public abstract class ChooseFileEncodingAction extends ComboBoxAction {
37 private final VirtualFile myVirtualFile;
38 private final Project myProject;
40 public ChooseFileEncodingAction(VirtualFile virtualFile, Project project) {
41 myVirtualFile = virtualFile;
42 myProject = project;
45 public void update(final AnActionEvent e) {
46 boolean enabled = isEnabled(myProject, myVirtualFile);
47 if (myVirtualFile != null) {
48 String prefix;
49 Charset charset = encodingFromContent(myProject, myVirtualFile);
50 if (charset != null) {
51 prefix = "Encoding:";
53 else {
54 prefix = "";
56 if (charset == null) charset = myVirtualFile.getCharset();
57 e.getPresentation().setText(prefix + " " + charset.toString());
59 e.getPresentation().setEnabled(enabled);
62 public static boolean isEnabled(Project project, VirtualFile virtualFile) {
63 if (project == null) return false;
64 boolean enabled = true;
65 if (virtualFile != null) {
66 Charset charset = encodingFromContent(project, virtualFile);
67 if (charset != null) {
68 enabled = false;
70 else if (!virtualFile.isDirectory()) {
71 FileType fileType = FileTypeManager.getInstance().getFileTypeByFile(virtualFile);
72 if (fileType.isBinary()
73 || fileType == StdFileTypes.GUI_DESIGNER_FORM
74 || fileType == StdFileTypes.IDEA_MODULE
75 || fileType == StdFileTypes.IDEA_PROJECT
76 || fileType == StdFileTypes.IDEA_WORKSPACE
77 || fileType == StdFileTypes.PATCH
78 || fileType == StdFileTypes.PROPERTIES
80 || fileType == StdFileTypes.XML
81 || fileType == StdFileTypes.JSPX
82 || fileType == StdFileTypes.XHTML
83 ) {
84 enabled = false;
88 return enabled;
91 private static final Key<Pair<Charset, Long>> CACHED_CHARSET_FROM_CONTENT = Key.create("CACHED_CHARSET");
92 public static Charset encodingFromContent(Project project, VirtualFile virtualFile) {
93 FileType fileType = virtualFile.getFileType();
94 if (fileType instanceof LanguageFileType) {
95 Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
96 if (document == null) return null;
97 Pair<Charset, Long> cachedCharset = document.getUserData(CACHED_CHARSET_FROM_CONTENT);
98 Charset charset;
99 if (cachedCharset == null || cachedCharset.getSecond() != document.getModificationStamp()) {
100 charset = ((LanguageFileType)fileType).extractCharsetFromFileContent(project, virtualFile, document.getText());
101 document.putUserData(CACHED_CHARSET_FROM_CONTENT, Pair.create(charset, document.getModificationStamp()));
103 else {
104 charset = cachedCharset.getFirst();
106 if (charset != null) {
107 return charset;
110 return null;
113 @NotNull
114 protected DefaultActionGroup createPopupActionGroup(final JComponent button) {
115 return createGroup(true);
118 private void fillCharsetActions(DefaultActionGroup group, final VirtualFile virtualFile, List<Charset> charsets) {
119 for (Charset slave : charsets) {
120 ChangeFileEncodingTo action = new ChangeFileEncodingTo(virtualFile, slave){
121 protected void chosen(final VirtualFile file, final Charset charset) {
122 ChooseFileEncodingAction.this.chosen(file, charset);
125 group.add(action);
129 private class ClearThisFileEncodingAction extends AnAction {
130 private final VirtualFile myFile;
132 private ClearThisFileEncodingAction(@Nullable VirtualFile file) {
133 super("<Clear>", "Clear " +
134 (file == null ? "default" : "file '"+file.getName()+"'") +
135 " encoding.", null);
136 myFile = file;
139 public void actionPerformed(final AnActionEvent e) {
140 chosen(myFile, NO_ENCODING);
144 public static final Charset NO_ENCODING = new Charset("NO_ENCODING", null) {
145 public boolean contains(final Charset cs) {
146 return false;
149 public CharsetDecoder newDecoder() {
150 return null;
153 public CharsetEncoder newEncoder() {
154 return null;
157 protected abstract void chosen(VirtualFile virtualFile, Charset charset);
159 public DefaultActionGroup createGroup(boolean showClear) {
160 DefaultActionGroup group = new DefaultActionGroup();
161 List<Charset> favorites = new ArrayList<Charset>(EncodingManager.getInstance().getFavorites());
162 Collections.sort(favorites);
164 if (showClear) {
165 group.add(new ClearThisFileEncodingAction(myVirtualFile));
167 fillCharsetActions(group, myVirtualFile, favorites);
169 DefaultActionGroup more = new DefaultActionGroup("more", true);
170 group.add(more);
171 fillCharsetActions(more, myVirtualFile, Arrays.asList(CharsetToolkit.getAvailableCharsets()));
172 return group;