diff --git a/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryDownloadSettings.java b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryDownloadSettings.java index e9e86d69b592..b94a58246cba 100644 --- a/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryDownloadSettings.java +++ b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryDownloadSettings.java @@ -138,9 +138,9 @@ public class LibraryDownloadSettings { } List> downloaded = - DownloadableFileService.getInstance().createDownloader(toDownload, null, parent, myLibraryName + " Library") - .toDirectory(myDirectoryForDownloadedLibrariesPath) - .downloadAndReturnWithDescriptions(); + DownloadableFileService.getInstance() + .createDownloader(toDownload, myLibraryName + " Library") + .downloadWithProgress(myDirectoryForDownloadedLibrariesPath, null, parent); if (downloaded == null) { return null; } diff --git a/java/java-impl/src/com/intellij/jarFinder/FindJarFix.java b/java/java-impl/src/com/intellij/jarFinder/FindJarFix.java index 6206d3e4a3df..688788ae3c16 100644 --- a/java/java-impl/src/com/intellij/jarFinder/FindJarFix.java +++ b/java/java-impl/src/com/intellij/jarFinder/FindJarFix.java @@ -286,12 +286,13 @@ public abstract class FindJarFix implements IntentionActio PropertiesComponent.getInstance(project).setValue("findjar.last.used.dir", file.getPath()); final DownloadableFileService downloader = DownloadableFileService.getInstance(); final DownloadableFileDescription description = downloader.createFileDescription(jarUrl, jarName); - final VirtualFile[] jars = downloader.createDownloader(Arrays.asList(description), project, myEditorComponent, jarName) - .toDirectory(file.getPath()).download(); - if (jars != null && jars.length == 1) { + final List jars = + downloader.createDownloader(Arrays.asList(description), jarName) + .downloadFilesWithProgress(file.getPath(), project, myEditorComponent); + if (jars != null && jars.size() == 1) { AccessToken token = WriteAction.start(); try { - OrderEntryFix.addJarToRoots(jars[0].getPresentableUrl(), myModule, myRef); + OrderEntryFix.addJarToRoots(jars.get(0).getPresentableUrl(), myModule, myRef); } finally { token.finish(); diff --git a/platform/lang-api/src/com/intellij/util/download/DownloadableFileService.java b/platform/lang-api/src/com/intellij/util/download/DownloadableFileService.java index ca003ab007fe..a38e31d62b9f 100644 --- a/platform/lang-api/src/com/intellij/util/download/DownloadableFileService.java +++ b/platform/lang-api/src/com/intellij/util/download/DownloadableFileService.java @@ -46,9 +46,21 @@ public abstract class DownloadableFileService { @NotNull URL... localUrls); @NotNull + public abstract FileDownloader createDownloader(@NotNull DownloadableFileSetDescription description); + + @NotNull + public abstract FileDownloader createDownloader(@NotNull List fileDescriptions, @NotNull String presentableDownloadName); + + /** + * @deprecated use {@link #createDownloader(DownloadableFileSetDescription)} instead + */ + @NotNull public abstract FileDownloader createDownloader(@NotNull DownloadableFileSetDescription description, @Nullable Project project, JComponent parent); + /** + * @deprecated use {@link #createDownloader(java.util.List, String)} instead + */ @NotNull public abstract FileDownloader createDownloader(List fileDescriptions, @Nullable Project project, JComponent parent, @NotNull String presentableDownloadName); diff --git a/platform/lang-api/src/com/intellij/util/download/FileDownloader.java b/platform/lang-api/src/com/intellij/util/download/FileDownloader.java index 374dcf8c1a30..6ca69ffce0c6 100644 --- a/platform/lang-api/src/com/intellij/util/download/FileDownloader.java +++ b/platform/lang-api/src/com/intellij/util/download/FileDownloader.java @@ -15,11 +15,15 @@ */ package com.intellij.util.download; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; +import java.io.File; +import java.io.IOException; import java.util.List; /** @@ -29,23 +33,45 @@ import java.util.List; */ public interface FileDownloader { /** - * Specifies target directory for downloaded files. If target directory is not specified a file chooser will be shown from {@link #download()} method - * @param directoryForDownloadedFilesPath target directory path - * @return the same instance + * Download files with modal progress dialog + * @param targetDirectoryPath target directory for downloaded files. If {@code null} a file chooser will be shown to select target directory + * @param project project instance used to show the progress window + * @param parentComponent parent component for the progress window + * @return list of downloaded files of {@code null} if the downloading process was failed or cancelled + */ + @Nullable + List downloadFilesWithProgress(@Nullable String targetDirectoryPath, @Nullable Project project, @Nullable JComponent parentComponent); + + /** + * Same as {@link #downloadFilesWithProgress} but returns downloaded files along with corresponding descriptions + */ + @Nullable + List> downloadWithProgress(@Nullable String targetDirectoryPath, + @Nullable Project project, @Nullable JComponent parentComponent); + + /** + * Download files synchronously. Call this method under progress only (see {@link com.intellij.openapi.progress.Task}) + * @param targetDir target directory for downloaded files + * @return list of downloaded files with their descriptions + * @throws IOException + */ + @NotNull + List> download(@NotNull File targetDir) throws IOException; + + /** + * @deprecated specify target directory in {@link #downloadWithProgress} or {@link #downloadFilesWithProgress} method instead */ @NotNull FileDownloader toDirectory(@NotNull String directoryForDownloadedFilesPath); /** - * Download files with modal progress dialog. - * @return downloaded files + * @deprecated use {@link #downloadFilesWithProgress} instead */ @Nullable VirtualFile[] download(); /** - * Download files with modal progress dialog. - * @return downloaded files with corresponding descriptions + * @deprecated use {@link #downloadWithProgress} instead */ @Nullable List> downloadAndReturnWithDescriptions(); diff --git a/platform/lang-impl/src/com/intellij/util/download/impl/DownloadableFileServiceImpl.java b/platform/lang-impl/src/com/intellij/util/download/impl/DownloadableFileServiceImpl.java index c158419e13d2..a24aa6f84309 100644 --- a/platform/lang-impl/src/com/intellij/util/download/impl/DownloadableFileServiceImpl.java +++ b/platform/lang-impl/src/com/intellij/util/download/impl/DownloadableFileServiceImpl.java @@ -55,6 +55,19 @@ public class DownloadableFileServiceImpl extends DownloadableFileService { }; } + @NotNull + @Override + public FileDownloader createDownloader(@NotNull DownloadableFileSetDescription description) { + return createDownloader(description.getFiles(), description.getName()); + } + + @NotNull + @Override + public FileDownloader createDownloader(@NotNull List fileDescriptions, + @NotNull String presentableDownloadName) { + return new FileDownloaderImpl(fileDescriptions, null, null, presentableDownloadName); + } + @NotNull @Override public FileDownloader createDownloader(@NotNull DownloadableFileSetDescription description, diff --git a/platform/lang-impl/src/com/intellij/util/download/impl/FileDownloaderImpl.java b/platform/lang-impl/src/com/intellij/util/download/impl/FileDownloaderImpl.java index 814248bf6f0c..0ed979cc3019 100644 --- a/platform/lang-impl/src/com/intellij/util/download/impl/FileDownloaderImpl.java +++ b/platform/lang-impl/src/com/intellij/util/download/impl/FileDownloaderImpl.java @@ -23,11 +23,11 @@ import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; +import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; @@ -58,166 +58,191 @@ public class FileDownloaderImpl implements FileDownloader { private static final int READ_TIMEOUT = 60*1000; @NonNls private static final String LIB_SCHEMA = "lib://"; - private List myFileDescriptions; - private JComponent myParent; + private final List myFileDescriptions; + private JComponent myParentComponent; private @Nullable Project myProject; private String myDirectoryForDownloadedFilesPath; - private String myDialogTitle; + private final String myDialogTitle; - public FileDownloaderImpl(final List fileDescriptions, + public FileDownloaderImpl(@NotNull List fileDescriptions, final @Nullable Project project, - JComponent parent, + @Nullable JComponent parentComponent, @NotNull String presentableDownloadName) { myProject = project; myFileDescriptions = fileDescriptions; - myParent = parent; + myParentComponent = parentComponent; myDialogTitle = IdeBundle.message("progress.download.0.title", StringUtil.capitalize(presentableDownloadName)); } - @NotNull + @Nullable @Override - public FileDownloader toDirectory(@NotNull String directoryForDownloadedFilesPath) { - myDirectoryForDownloadedFilesPath = directoryForDownloadedFilesPath; - return this; - } - - @Override - public VirtualFile[] download() { - final List> pairs = downloadAndReturnWithDescriptions(); + public List downloadFilesWithProgress(@Nullable String targetDirectoryPath, + @Nullable Project project, + @Nullable JComponent parentComponent) { + final List> pairs = downloadWithProgress(targetDirectoryPath, project, parentComponent); if (pairs == null) return null; List files = new ArrayList(); for (Pair pair : pairs) { files.add(pair.getFirst()); } - return VfsUtilCore.toVirtualFileArray(files); - } - - @Override - public List> downloadAndReturnWithDescriptions() { - VirtualFile dir = null; - if (myDirectoryForDownloadedFilesPath != null) { - File ioDir = new File(FileUtil.toSystemDependentName(myDirectoryForDownloadedFilesPath)); - ioDir.mkdirs(); - dir = LocalFileSystem.getInstance().refreshAndFindFileByPath(myDirectoryForDownloadedFilesPath); - } - - if (dir == null) { - dir = chooseDirectoryForFiles(); - } - - if (dir != null) { - return doDownload(dir); - } - return null; + return files; } @Nullable - private List> doDownload(final VirtualFile dir) { - final List> downloadedFiles = new ArrayList>(); - final List> existingFiles = new ArrayList>(); - final Ref exceptionRef = Ref.create(null); - final Ref currentFile = new Ref(); - final File ioDir = VfsUtilCore.virtualToIoFile(dir); + @Override + public List> downloadWithProgress(@Nullable String targetDirectoryPath, + @Nullable Project project, + @Nullable JComponent parentComponent) { + File dir; + if (targetDirectoryPath != null) { + dir = new File(targetDirectoryPath); + } + else { + VirtualFile virtualDir = chooseDirectoryForFiles(project, parentComponent); + if (virtualDir != null) { + dir = VfsUtilCore.virtualToIoFile(virtualDir); + } + else { + return null; + } + } - ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { + return downloadWithProcess(dir, project, parentComponent); + } + + @Nullable + private List> downloadWithProcess(final File targetDir, + Project project, + JComponent parentComponent) { + final Ref>> localFiles = Ref.create(null); + final Ref exceptionRef = Ref.create(null); + + boolean completed = ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { @Override public void run() { - final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); try { - for (int i = 0; i < myFileDescriptions.size(); i++) { - DownloadableFileDescription description = myFileDescriptions.get(i); - currentFile.set(description); - if (indicator != null) { - indicator.checkCanceled(); - indicator.setText(IdeBundle.message("progress.downloading.0.of.1.file.text", i+1, myFileDescriptions.size())); - } - - final File existing = new File(ioDir, description.getDefaultFileName()); - long size = existing.exists() ? existing.length() : -1; - - if (!download(description, size, downloadedFiles)) { - existingFiles.add(Pair.create(existing, description)); - } - } - } - catch (ProcessCanceledException e) { - exceptionRef.set(e); + localFiles.set(download(targetDir)); } catch (IOException e) { exceptionRef.set(e); } } - }, myDialogTitle, true, myProject, myParent); + }, myDialogTitle, true, project, parentComponent); + if (!completed) { + return null; + } Exception exception = exceptionRef.get(); if (exception != null) { - deleteFiles(downloadedFiles); - if (exception instanceof IOException) { - String message = IdeBundle.message("error.file.download.failed", exception.getMessage()); - if (currentFile.get() != null) { - message += ": " + currentFile.get().getDownloadUrl(); - } - final boolean tryAgain = IOExceptionDialog.showErrorDialog(myDialogTitle, message); - if (tryAgain) { - return doDownload(dir); - } + final boolean tryAgain = IOExceptionDialog.showErrorDialog(myDialogTitle, exception.getMessage()); + if (tryAgain) { + return downloadWithProcess(targetDir, project, parentComponent); } return null; } + return findVirtualFiles(localFiles.get()); + } + + @NotNull + @Override + public List> download(@NotNull File targetDir) throws IOException { + final List> downloadedFiles = new ArrayList>(); + final List> existingFiles = new ArrayList>(); + ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); + if (indicator == null) { + indicator = new EmptyProgressIndicator(); + } try { - return moveToDir(existingFiles, downloadedFiles, dir); + for (int i = 0; i < myFileDescriptions.size(); i++) { + DownloadableFileDescription description = myFileDescriptions.get(i); + indicator.checkCanceled(); + indicator.setText(IdeBundle.message("progress.downloading.0.of.1.file.text", i + 1, myFileDescriptions.size())); + + final File existing = new File(targetDir, description.getDefaultFileName()); + final String url = description.getDownloadUrl(); + if (url.startsWith(LIB_SCHEMA)) { + indicator.setText2(IdeBundle.message("progress.locate.file.text", description.getPresentableFileName())); + final String path = FileUtil.toSystemDependentName(StringUtil.trimStart(url, LIB_SCHEMA)); + final File file = PathManager.findFileInLibDirectory(path); + existingFiles.add(Pair.create(file, description)); + } + else if (url.startsWith(LocalFileSystem.PROTOCOL_PREFIX)) { + String path = FileUtil.toSystemDependentName(StringUtil.trimStart(url, LocalFileSystem.PROTOCOL_PREFIX)); + File file = new File(path); + if (file.exists()) { + existingFiles.add(Pair.create(file, description)); + } + } + else { + File downloaded; + try { + downloaded = downloadFile(description, existing, indicator); + } + catch (IOException e) { + throw new IOException(IdeBundle.message("error.file.download.failed", description.getDownloadUrl(), e.getMessage()), e); + } + if (FileUtil.filesEqual(downloaded, existing)) { + existingFiles.add(Pair.create(existing, description)); + } + else { + downloadedFiles.add(Pair.create(downloaded, description)); + } + } + } + List> localFiles = new ArrayList>(); + localFiles.addAll(moveToDir(downloadedFiles, targetDir)); + localFiles.addAll(existingFiles); + return localFiles; + } + catch (ProcessCanceledException e) { + deleteFiles(downloadedFiles); + throw e; } catch (IOException e) { - if (myProject != null) { - Messages.showErrorDialog(myProject, myDialogTitle, e.getMessage()); - } - else { - Messages.showErrorDialog(myParent, myDialogTitle, e.getMessage()); - } - return null; + deleteFiles(downloadedFiles); + throw e; } } @Nullable - private VirtualFile chooseDirectoryForFiles() { + private static VirtualFile chooseDirectoryForFiles(Project project, JComponent parentComponent) { final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); descriptor.setTitle(IdeBundle.message("dialog.directory.for.downloaded.files.title")); - final VirtualFile baseDir = myProject != null ? myProject.getBaseDir() : null; - return FileChooser.chooseFile(descriptor, myParent, myProject, baseDir); + final VirtualFile baseDir = project != null ? project.getBaseDir() : null; + return FileChooser.chooseFile(descriptor, parentComponent, project, baseDir); + } + + private static List> moveToDir(List> downloadedFiles, + final File targetDir) throws IOException { + FileUtil.createDirectory(targetDir); + List> result = new ArrayList>(); + for (Pair pair : downloadedFiles) { + final DownloadableFileDescription description = pair.getSecond(); + final String fileName = description.generateFileName(new Condition() { + @Override + public boolean value(String s) { + return !new File(targetDir, s).exists(); + } + }); + final File toFile = new File(targetDir, fileName); + FileUtil.rename(pair.getFirst(), toFile); + result.add(Pair.create(toFile, description)); + } + return result; } @NotNull - private static List> moveToDir(final List> existingFiles, final List> downloadedFiles, final VirtualFile dir) throws IOException { + private static List> findVirtualFiles(List> ioFiles) { List> result = new ArrayList>(); - - final File ioDir = VfsUtilCore.virtualToIoFile(dir); - for (Pair pair : downloadedFiles) { - final DownloadableFileDescription description = pair.getSecond(); - final boolean dontTouch = description.getDownloadUrl().startsWith(LIB_SCHEMA) || description.getDownloadUrl().startsWith(LocalFileSystem.PROTOCOL_PREFIX); - final File toFile = dontTouch? pair.getFirst() : generateName(description, ioDir); - if (!dontTouch) { - FileUtil.rename(pair.getFirst(), toFile); - } - VirtualFile file = new WriteAction() { - @Override - protected void run(final Result result) { - final String url = VfsUtil.getUrlForLibraryRoot(toFile); - LocalFileSystem.getInstance().refreshAndFindFileByIoFile(toFile); - result.setResult(VirtualFileManager.getInstance().refreshAndFindFileByUrl(url)); - } - }.execute().getResultObject(); - if (file != null) { - result.add(Pair.create(file, description)); - } - } - - for (final Pair pair : existingFiles) { + for (final Pair pair : ioFiles) { + final File ioFile = pair.getFirst(); VirtualFile libraryRootFile = new WriteAction() { @Override protected void run(final Result result) { - final String url = VfsUtil.getUrlForLibraryRoot(pair.getFirst()); + final String url = VfsUtil.getUrlForLibraryRoot(ioFile); + LocalFileSystem.getInstance().refreshAndFindFileByIoFile(ioFile); result.setResult(VirtualFileManager.getInstance().refreshAndFindFileByUrl(url)); } @@ -229,89 +254,80 @@ public class FileDownloaderImpl implements FileDownloader { return result; } - private static File generateName(DownloadableFileDescription info, final File dir) { - final String fileName = info.generateFileName(new Condition() { - @Override - public boolean value(String s) { - return !new File(dir, s).exists(); - } - }); - return new File(dir, fileName); - } - private static void deleteFiles(final List> pairs) { for (Pair pair : pairs) { FileUtil.delete(pair.getFirst()); } - pairs.clear(); } - private static boolean download(final DownloadableFileDescription fileDescription, - final long existingFileSize, - final List> downloadedFiles) throws IOException { - final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); + @NotNull + private static File downloadFile(final @NotNull DownloadableFileDescription fileDescription, final @NotNull File existingFile, + final @NotNull ProgressIndicator indicator) throws IOException { final String presentableUrl = fileDescription.getPresentableDownloadUrl(); - final String url = fileDescription.getDownloadUrl(); - if (url.startsWith(LIB_SCHEMA)) { - indicator.setText2(IdeBundle.message("progress.locate.file.text", fileDescription.getPresentableFileName())); - final String path = FileUtil.toSystemDependentName(StringUtil.trimStart(url, LIB_SCHEMA)); - final File file = PathManager.findFileInLibDirectory(path); - downloadedFiles.add(Pair.create(file, fileDescription)); - } - else if (url.startsWith(LocalFileSystem.PROTOCOL_PREFIX)) { - String path = FileUtil.toSystemDependentName(StringUtil.trimStart(url, LocalFileSystem.PROTOCOL_PREFIX)); - File file = new File(path); - if (file.exists()) { - downloadedFiles.add(Pair.create(file, fileDescription)); + indicator.setText2(IdeBundle.message("progress.connecting.to.download.file.text", presentableUrl)); + indicator.setIndeterminate(true); + HttpURLConnection connection = (HttpURLConnection)new URL(fileDescription.getDownloadUrl()).openConnection(); + connection.setConnectTimeout(CONNECTION_TIMEOUT); + connection.setReadTimeout(READ_TIMEOUT); + + InputStream input = null; + BufferedOutputStream output = null; + + boolean deleteFile = true; + File tempFile = null; + try { + final int responseCode = connection.getResponseCode(); + if (responseCode != HttpURLConnection.HTTP_OK) { + throw new IOException(IdeBundle.message("error.connection.failed.with.http.code.N", responseCode)); } - } - else { - indicator.setText2(IdeBundle.message("progress.connecting.to.download.file.text", presentableUrl)); - indicator.setIndeterminate(true); - HttpURLConnection connection = (HttpURLConnection)new URL(url).openConnection(); - connection.setConnectTimeout(CONNECTION_TIMEOUT); - connection.setReadTimeout(READ_TIMEOUT); - InputStream input = null; - BufferedOutputStream output = null; - - boolean deleteFile = true; - File tempFile = null; - try { - final int responseCode = connection.getResponseCode(); - if (responseCode != HttpURLConnection.HTTP_OK) { - throw new IOException(IdeBundle.message("error.connection.failed.with.http.code.N", responseCode)); - } - - final int size = connection.getContentLength(); - if (size != -1 && size == existingFileSize) { - return false; - } - - tempFile = FileUtil.createTempFile("downloaded", "file"); - input = UrlConnectionUtil.getConnectionInputStreamWithException(connection, indicator); - output = new BufferedOutputStream(new FileOutputStream(tempFile)); - indicator.setText2(IdeBundle.message("progress.download.file.text", fileDescription.getPresentableFileName(), presentableUrl)); - indicator.setIndeterminate(size == -1); - - NetUtils.copyStreamContent(indicator, input, output, size); - - deleteFile = false; - downloadedFiles.add(Pair.create(tempFile, fileDescription)); - } - finally { - if (input != null) { - input.close(); - } - if (output != null) { - output.close(); - } - if (deleteFile && tempFile != null) { - FileUtil.delete(tempFile); - } - connection.disconnect(); + final int size = connection.getContentLength(); + if (existingFile.exists() && size == existingFile.length()) { + return existingFile; } + + tempFile = FileUtil.createTempFile("downloaded", "file"); + input = UrlConnectionUtil.getConnectionInputStreamWithException(connection, indicator); + output = new BufferedOutputStream(new FileOutputStream(tempFile)); + indicator.setText2(IdeBundle.message("progress.download.file.text", fileDescription.getPresentableFileName(), presentableUrl)); + indicator.setIndeterminate(size == -1); + + NetUtils.copyStreamContent(indicator, input, output, size); + + deleteFile = false; + return tempFile; } - return true; + finally { + if (input != null) { + input.close(); + } + if (output != null) { + output.close(); + } + if (deleteFile && tempFile != null) { + FileUtil.delete(tempFile); + } + connection.disconnect(); + } + } + + @NotNull + @Override + public FileDownloader toDirectory(@NotNull String directoryForDownloadedFilesPath) { + myDirectoryForDownloadedFilesPath = directoryForDownloadedFilesPath; + return this; + } + + @Nullable + @Override + public VirtualFile[] download() { + List files = downloadFilesWithProgress(myDirectoryForDownloadedFilesPath, myProject, myParentComponent); + return files != null ? VfsUtilCore.toVirtualFileArray(files) : null; + } + + @Nullable + @Override + public List> downloadAndReturnWithDescriptions() { + return downloadWithProgress(myDirectoryForDownloadedFilesPath, myProject, myParentComponent); } } diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index 810cbcff73e3..d8e5c52f73f5 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -988,7 +988,7 @@ progress.connecting.to.download.file.text=Connecting to ''{0}''... progress.locate.file.text=Locating ''{0}''... progress.downloading.0.of.1.file.text=Downloading {0} of {1} {1, choice, 1#file|2#files}... dialog.directory.for.downloaded.files.title=Downloaded files will be copied to selected directory -error.file.download.failed=Downloading failed: {0} +error.file.download.failed=Failed to download ''{0}'': {1} maven.repository.presentable.name=Maven repository label.missed.libraries.prefix=The following libraries are missing: