From 1ede745bcb792eeaeda0644d808e385a227da432 Mon Sep 17 00:00:00 2001 From: Michael Bangas Date: Mon, 6 Nov 2023 16:21:18 +0100 Subject: [PATCH] Proposal: Opening/Closing Mechanism for Zip Files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Proposal: Opening/Closing Mechanism for Zip Files ## Background The Eclipse IDE has no built in functionality to open Zip Files and read or manipulate their content. Because of this, other operations like searching inside of Zip Files or comparing two Zip Files were also not possible. ## Description This PR introduces UI support for accesing the opening/closing mechanism for Zip Files over the UI-menu. It is accessed by right-clicking the Zip File that should be opened and then clicking on "Open Zip File". Closing is accessed the same way but when right-clicking an opened Zip File. Please see #1408 for the PR on the repository **eclipse.platform** for the platform implementation and further information. Co-Authored-By: David Erdös --- bundles/org.eclipse.ui.ide/plugin.properties | 4 +- bundles/org.eclipse.ui.ide/plugin.xml | 70 +++++++++++++++- .../fileSystem/zip/CloseZipFileHandler.java | 59 +++++++++++++ .../fileSystem/zip/OpenZipFileHandler.java | 79 +++++++++++++++++ .../zip/ZipFileSystemContributor.java | 84 +++++++++++++++++++ .../wizards/datatransfer/ImportOperation.java | 9 ++ 6 files changed, 302 insertions(+), 3 deletions(-) create mode 100644 bundles/org.eclipse.ui.ide/src/org/eclipse/ui/ide/fileSystem/zip/CloseZipFileHandler.java create mode 100644 bundles/org.eclipse.ui.ide/src/org/eclipse/ui/ide/fileSystem/zip/OpenZipFileHandler.java create mode 100644 bundles/org.eclipse.ui.ide/src/org/eclipse/ui/ide/fileSystem/zip/ZipFileSystemContributor.java diff --git a/bundles/org.eclipse.ui.ide/plugin.properties b/bundles/org.eclipse.ui.ide/plugin.properties index 8647371cf5a..862703f6a48 100644 --- a/bundles/org.eclipse.ui.ide/plugin.properties +++ b/bundles/org.eclipse.ui.ide/plugin.properties @@ -201,7 +201,9 @@ command.copyMarkerResourceQualifiedName.name=Copy Resource Qualified Name To Cli command.copyMarkerResourceQualifiedName.label=Resource Qualified Name command.copyMarkerResourceQualifiedName.description=Copies markers resource qualified name to the clipboard command.copyMarkerResourceQualifiedName.mnemonic=Q - +command.name.openZipFile=Open Zip File +command.name.closeZipFile=Close Zip File +filesystem.file.zip=Zip file command.showInQuickMenu.name= Show In... command.showInQuickMenu.description = Open the Show In menu diff --git a/bundles/org.eclipse.ui.ide/plugin.xml b/bundles/org.eclipse.ui.ide/plugin.xml index b170640a475..7a3514ae3fd 100644 --- a/bundles/org.eclipse.ui.ide/plugin.xml +++ b/bundles/org.eclipse.ui.ide/plugin.xml @@ -1089,7 +1089,17 @@ id="org.eclipse.ui.ide.markers.copyMarkerResourceQualifiedName" name="%command.copyMarkerResourceQualifiedName.name" defaultHandler="org.eclipse.ui.internal.views.markers.CopyMarkerResourceQualifiedNameHandler"> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2718,5 +2778,11 @@ markerType="org.eclipse.core.resources.noExplicitEncoding"> - + + + diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/ide/fileSystem/zip/CloseZipFileHandler.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/ide/fileSystem/zip/CloseZipFileHandler.java new file mode 100644 index 00000000000..d56596c9afe --- /dev/null +++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/ide/fileSystem/zip/CloseZipFileHandler.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2024 Vector Informatik GmbH and others. + * + * This program and the accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: Vector Informatik GmbH - initial API and implementation + *******************************************************************************/ + +package org.eclipse.ui.ide.fileSystem.zip; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.ZipFileTransformer; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * This class represents a handler for closing an opened zip file. + * + * @since 3.132 + */ +public class CloseZipFileHandler extends AbstractHandler { + + /** + * Executes the handler action, which involves closing an opened zip file. + * + * @param event The event triggering the execution of this handler. + */ + @Override + public Object execute(ExecutionEvent event) { + Shell shell = HandlerUtil.getActiveShell(event); + ISelection selection = HandlerUtil.getCurrentSelection(event); + + if (!(selection instanceof IStructuredSelection)) { + return null; + } + + Object element = ((IStructuredSelection) selection).getFirstElement(); + + if (!(element instanceof IFolder)) { + return null; + } + try { + ZipFileTransformer.closeZipFile((IFolder) element); + } catch (Exception e) { + MessageDialog.openError(shell, "Error", "Error opening zip file"); //$NON-NLS-1$ //$NON-NLS-2$ + e.printStackTrace(); + } + return null; + } +} diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/ide/fileSystem/zip/OpenZipFileHandler.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/ide/fileSystem/zip/OpenZipFileHandler.java new file mode 100644 index 00000000000..d0218b39c6b --- /dev/null +++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/ide/fileSystem/zip/OpenZipFileHandler.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2024 Vector Informatik GmbH and others. + * + * This program and the accompanying materials are made available under the terms of the Eclipse + * Public License 2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: Vector Informatik GmbH - initial API and implementation + *******************************************************************************/ + +package org.eclipse.ui.ide.fileSystem.zip; + +import java.lang.reflect.InvocationTargetException; +import java.net.URISyntaxException; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.ZipFileTransformer; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * This class represents a handler for opening zip files. + * + * @since 3.132 + */ +public class OpenZipFileHandler extends AbstractHandler { + + /** + * Executes the handler action, which involves opening a zip file selected by + * the user. + * + * @param event The event triggering the execution of this handler. + */ + @Override + public Object execute(ExecutionEvent event) { + Shell shell = HandlerUtil.getActiveShell(event); + ProgressMonitorDialog dialog = new ProgressMonitorDialog(shell); + ISelection selection = HandlerUtil.getCurrentSelection(event); + if (!(selection instanceof IStructuredSelection)) { + return null; + } + + Object element = ((IStructuredSelection) selection).getFirstElement(); + + if (!(element instanceof IFile)) { + return null; + } + try { + dialog.run(true, false, new IRunnableWithProgress() { + @Override + public void run(IProgressMonitor monitor) throws InterruptedException { + monitor.beginTask("Opening Zip File", 5); //$NON-NLS-1$ + try { + ZipFileTransformer.openZipFile((IFile) element, monitor, true); + } catch (URISyntaxException | CoreException e) { + throw new InterruptedException(e.getMessage()); + } + monitor.worked(1); + } + }); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + MessageDialog.openError(shell, "Error opening zip file", e.getMessage()); //$NON-NLS-1$ + } + return null; + } +} diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/ide/fileSystem/zip/ZipFileSystemContributor.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/ide/fileSystem/zip/ZipFileSystemContributor.java new file mode 100644 index 00000000000..5d3d0fdd8ec --- /dev/null +++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/ide/fileSystem/zip/ZipFileSystemContributor.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.ui.ide.fileSystem.zip; + +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; + +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.ide.fileSystem.FileSystemContributor; + +/** + * ZipFileSystemContributor is the zip example of a file system contributor. + * + * @since 3.23 + */ +public class ZipFileSystemContributor extends FileSystemContributor { + + public ZipFileSystemContributor() { + super(); + } + + @Override + public URI getURI(String pathString) { + try { + if (pathString.startsWith("zip")) //$NON-NLS-1$ + return new URI(pathString); + } catch (URISyntaxException e1) { + return null; + } + if (File.separatorChar != '/') + pathString = pathString.replace(File.separatorChar, '/'); + final int length = pathString.length(); + StringBuffer pathBuf = new StringBuffer(length + 1); + pathBuf.append("file:"); //$NON-NLS-1$ + // There must be a leading slash in a hierarchical URI + if (length > 0 && (pathString.charAt(0) != '/')) + pathBuf.append('/'); + // additional double-slash for UNC paths to distinguish from host + // separator + if (pathString.startsWith("//")) //$NON-NLS-1$ + pathBuf.append('/').append('/'); + pathBuf.append(pathString); + try { + //scheme, host, path, query, fragment + return new URI("zip", null, "/", pathBuf.toString(), null); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (URISyntaxException e) { + return null; + } + } + + /* (non-Javadoc) + * @see org.eclipse.ui.ide.fileSystem.FileSystemContributor#browseFileSystem(java.lang.String, org.eclipse.swt.widgets.Shell) + */ + @Override + public URI browseFileSystem(String initialPath, Shell shell) { + + FileDialog dialog = new FileDialog(shell); + + if (initialPath.length() > 0) + dialog.setFilterPath(initialPath); + + dialog.setFilterExtensions(new String[] {"*.zip"});//$NON-NLS-1$ + + String selectedFile = dialog.open(); + if (selectedFile == null) + return null; + return getURI(selectedFile); + } + +} diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/wizards/datatransfer/ImportOperation.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/wizards/datatransfer/ImportOperation.java index 7eb4b7bf43a..e90b19d6a82 100644 --- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/wizards/datatransfer/ImportOperation.java +++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/wizards/datatransfer/ImportOperation.java @@ -25,6 +25,7 @@ import java.util.zip.ZipEntry; import org.eclipse.core.filesystem.URIUtil; +import org.eclipse.core.filesystem.ZipFileUtil; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; @@ -544,6 +545,14 @@ void importFile(Object fileObject, int policy, IProgressMonitor mon) { targetResource.createLink( createRelativePath(IPath.fromOSString(provider.getFullPath(fileObject)), targetResource), 0, subMonitor.split(50)); + } else if (ZipFileUtil.isOpenZipFile(targetResource.getLocationURI())) {// $NON-NLS-1$ + // When overwriting an opened Zip File with a new Zip File that has the same + // name, the opened zip file needs to be deleted first. + IFolder openedZipFile = targetResource.getProject().getFolder(targetResource.getName()); + if (openedZipFile.exists()) { + openedZipFile.delete(true, subMonitor.split(50)); + } + targetResource.create(contentStream, false, subMonitor.split(50)); } else if (targetResource.exists()) { if (targetResource.isLinked()) { targetResource.delete(true, subMonitor.split(50));