blob: 6f0bc72d53053156b9d01a5737d667df7bf5ec0e [file] [log] [blame]
/*
* Copyright 2000-2012 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.internal;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.search.FilenameIndex;
import java.io.InputStream;
import java.security.MessageDigest;
import java.util.*;
/**
* @author Konstantin Bulenkov
*/
public class ShowImageDuplicatesAction extends AnAction {
//FileTypeManager.getInstance().getFileTypeByExtension("png").getAllPossibleExtensions() ?
private static final List<String> IMAGE_EXTENSIONS = Arrays.asList("png", "jpg", "jpeg", "gif", "tiff", "bmp");
@Override
public void actionPerformed(AnActionEvent e) {
final Project project = getEventProject(e);
assert project != null;
ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
@Override
public void run() {
collectAndShowDuplicates(project);
}
}, "Gathering images", true, project);
}
private static void collectAndShowDuplicates(final Project project) {
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
if (indicator != null && !indicator.isCanceled()) {
indicator.setText("Collecting project images...");
indicator.setIndeterminate(false);
final List<VirtualFile> images = new ArrayList<VirtualFile>();
for (String ext : IMAGE_EXTENSIONS) {
images.addAll(FilenameIndex.getAllFilesByExt(project, ext));
}
final Map<Long, Set<VirtualFile>> duplicates = new HashMap<Long, Set<VirtualFile>>();
final Map<Long, VirtualFile> all = new HashMap<Long, VirtualFile>();
for (int i = 0; i < images.size(); i++) {
indicator.setFraction((double)(i + 1) / (double)images.size());
final VirtualFile file = images.get(i);
if (!(file.getFileSystem() instanceof LocalFileSystem)) continue;
final long length = file.getLength();
if (all.containsKey(length)) {
if (!duplicates.containsKey(length)) {
final HashSet<VirtualFile> files = new HashSet<VirtualFile>();
files.add(all.get(length));
duplicates.put(length, files);
}
duplicates.get(length).add(file);
} else {
all.put(length, file);
}
indicator.checkCanceled();
}
showResults(project, images, duplicates, all);
}
}
private static void showResults(final Project project, final List<VirtualFile> images,
Map<Long, Set<VirtualFile>> duplicates,
Map<Long, VirtualFile> all) {
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
if (indicator == null || indicator.isCanceled()) return;
indicator.setText("MD5 check");
int count = 0;
for (Set set : duplicates.values()) count+=set.size();
final Map<String, Set<VirtualFile>> realDuplicates = new HashMap<String, Set<VirtualFile>>();
int seek = 0;
for (Set<VirtualFile> files : duplicates.values()) {
for (VirtualFile file : files) {
seek++;
indicator.setFraction((double)seek / (double)count);
try {
final String md5 = getMD5Checksum(file.getInputStream());
if (realDuplicates.containsKey(md5)) {
realDuplicates.get(md5).add(file);
} else {
final HashSet<VirtualFile> set = new HashSet<VirtualFile>();
set.add(file);
realDuplicates.put(md5, set);
}
}
catch (Exception ignored) {
}
}
}
count = 0;
for (String key : new ArrayList<String>(realDuplicates.keySet())) {
final int size = realDuplicates.get(key).size();
if (size == 1) {
realDuplicates.remove(key);
} else {
count+=size;
}
}
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
new ImageDuplicateResultsDialog(project, images, realDuplicates).show();
}
});
}
@Override
public void update(AnActionEvent e) {
e.getPresentation().setEnabledAndVisible(getEventProject(e) != null);
}
public static byte[] createChecksum(InputStream fis) throws Exception {
byte[] buffer = new byte[1024];
MessageDigest md5 = MessageDigest.getInstance("MD5");
int read;
while ((read = fis.read(buffer)) > 0) md5.update(buffer, 0, read);
fis.close();
return md5.digest();
}
public static String getMD5Checksum(InputStream fis) throws Exception {
byte[] bytes = createChecksum(fis);
String md5 = "";
for (byte b : bytes) md5 += Integer.toString((b & 0xff) + 0x100, 16).substring(1);
return md5;
}
}