From ce5b6677bc4ba102c7a33de8dbea7bead6e99da7 Mon Sep 17 00:00:00 2001 From: berthaultval Date: Thu, 23 Jan 2020 15:39:11 +0100 Subject: [PATCH 1/5] New class Utils with zip and unzip method Archive method produce zip Merge with the PR on afs Signed-off-by: berthaultval Signed-off-by: berthaultval --- .../java/com/powsybl/gse/app/ProjectPane.java | 19 ++++++++------- .../com/powsybl/gse/util/NodeChooser.java | 23 ++++++++++--------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/gse-app/src/main/java/com/powsybl/gse/app/ProjectPane.java b/gse-app/src/main/java/com/powsybl/gse/app/ProjectPane.java index 4449171d..d42a41f4 100644 --- a/gse-app/src/main/java/com/powsybl/gse/app/ProjectPane.java +++ b/gse-app/src/main/java/com/powsybl/gse/app/ProjectPane.java @@ -41,6 +41,7 @@ import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.stage.DirectoryChooser; +import javafx.stage.FileChooser; import javafx.stage.Stage; import javafx.util.Callback; import javafx.util.Pair; @@ -85,7 +86,6 @@ public class ProjectPane extends Tab { private final TaskItemList taskItems; private final TaskMonitorPane taskMonitorPane; private final Map lCache = new HashMap<>(); - private final CopyManager localArchiveManager = CopyManager.getInstance(); private final AppStorageListener appStorageListener; public ProjectPane(Scene scene, Project project, GseContext context) { @@ -721,9 +721,11 @@ private void archive(AbstractNodeBase item) { context.getExecutor().execute(() -> { TaskMonitor.Task task = project.getFileSystem().getTaskMonitor().startTask(String.format(RESOURCE_BUNDLE.getString("ArchiveTask"), selectedDirectory.getName()), project); try { - localArchiveManager.copy(Collections.singletonList(item), selectedDirectory); - } catch (CopyPasteException e) { + item.archive(selectedDirectory.toPath(), true); + LOGGER.info("Archiving node {} ({}) is complete", item.getName(), item.getId()); + } catch (AfsException e) { GseAlerts.showDialogError(e.getMessage()); + LOGGER.error("Archiving has failed for node {}", item.getId(), e); } finally { project.getFileSystem().getTaskMonitor().stopTask(task.getId()); } @@ -737,13 +739,14 @@ private void unarchiveItems(TreeItem folderItem) { throw new IllegalStateException("Can't unarchive item if target is not a project folder!"); } - DirectoryChooser directoryChooser = new DirectoryChooser(); - java.io.File selectedDirectory = directoryChooser.showDialog(getContent().getScene().getWindow()); - if (selectedDirectory != null) { + FileChooser fileChooser = new FileChooser(); + fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("ZIP", "*.zip")); + java.io.File selectedFile = fileChooser.showOpenDialog(getContent().getScene().getWindow()); + if (selectedFile != null) { context.getExecutor().execute(() -> { - TaskMonitor.Task task = project.getFileSystem().getTaskMonitor().startTask(String.format(RESOURCE_BUNDLE.getString("UnarchiveTask"), selectedDirectory.getName()), project); + TaskMonitor.Task task = project.getFileSystem().getTaskMonitor().startTask(String.format(RESOURCE_BUNDLE.getString("UnarchiveTask"), selectedFile.getName()), project); try { - ((ProjectFolder) folder).unarchive(selectedDirectory.toPath()); + ((ProjectFolder) folder).unarchive(selectedFile.toPath(),true); Platform.runLater(() -> refresh(folderItem)); } catch (Exception e) { Platform.runLater(() -> GseAlerts.showDialogError(e.getMessage())); diff --git a/gse-util/src/main/java/com/powsybl/gse/util/NodeChooser.java b/gse-util/src/main/java/com/powsybl/gse/util/NodeChooser.java index abb7fc7e..1b8a0827 100644 --- a/gse-util/src/main/java/com/powsybl/gse/util/NodeChooser.java +++ b/gse-util/src/main/java/com/powsybl/gse/util/NodeChooser.java @@ -25,11 +25,9 @@ import javafx.scene.text.Font; import javafx.scene.text.FontPosture; import javafx.scene.text.Text; -import javafx.stage.DirectoryChooser; -import javafx.stage.Modality; -import javafx.stage.Stage; -import javafx.stage.Window; +import javafx.stage.*; import javafx.util.Callback; +import org.apache.commons.compress.archivers.ArchiveException; import org.controlsfx.control.BreadCrumbBar; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -691,11 +689,13 @@ private void archive(AbstractNodeBase item) { context.getExecutor().execute(() -> { InfoDialog infoDialog = new InfoDialog(String.format(RESOURCE_BUNDLE.getString("ArchiveTask"), item.getName()), true); try { - localArchiveManager.copy(Collections.singletonList(item), selectedDirectory); + item.archive(selectedDirectory.toPath(), true); infoDialog.updateStage(RESOURCE_BUNDLE.getString("CompleteTask")); - } catch (CopyPasteException e) { + LOGGER.info("Archiving node {} ({}) is complete", item.getName(), item.getId()); + } catch (AfsException e) { Platform.runLater(() -> GseAlerts.showDialogError(e.getMessage())); infoDialog.updateStage(RESOURCE_BUNDLE.getString("ErrorTask"), Color.RED); + LOGGER.error("Archiving has failed for node {}", item.getId(), e); } }); } @@ -707,13 +707,14 @@ private void unarchiveItems(TreeItem folderItem) { throw new IllegalStateException("Can't unarchive item if target is not a folder!"); } - DirectoryChooser directoryChooser = new DirectoryChooser(); - java.io.File selectedDirectory = directoryChooser.showDialog(window); - if (selectedDirectory != null) { + FileChooser fileChooser = new FileChooser(); + fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("ZIP", "*.zip")); + java.io.File selectedFile = fileChooser.showOpenDialog(window); + if (selectedFile != null) { context.getExecutor().execute(() -> { - InfoDialog infoDialog = new InfoDialog(String.format(RESOURCE_BUNDLE.getString("UnarchiveTask"), selectedDirectory.getName()), true); + InfoDialog infoDialog = new InfoDialog(String.format(RESOURCE_BUNDLE.getString("UnarchiveTask"), selectedFile.getName()), true); try { - ((Folder) folder).unarchive(selectedDirectory.toPath()); + ((Folder) folder).unarchive(selectedFile.toPath(),true); infoDialog.updateStage(RESOURCE_BUNDLE.getString("CompleteTask")); Platform.runLater(() -> refresh(folderItem)); } catch (Exception e) { From 81817c3564240faee20d1bf35764332f64c87dea Mon Sep 17 00:00:00 2001 From: berthaultval Date: Tue, 28 Jan 2020 11:30:14 +0100 Subject: [PATCH 2/5] corrections after review Signed-off-by: berthaultval Signed-off-by: berthaultval --- .../java/com/powsybl/gse/app/ProjectPane.java | 9 +++++--- .../gse/copy_paste/afs/CopyManager.java | 21 +++++++------------ .../gse/copy_paste/afs/CopyService.java | 5 +++-- .../com/powsybl/gse/util/NodeChooser.java | 9 ++++---- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/gse-app/src/main/java/com/powsybl/gse/app/ProjectPane.java b/gse-app/src/main/java/com/powsybl/gse/app/ProjectPane.java index d42a41f4..827d1a5f 100644 --- a/gse-app/src/main/java/com/powsybl/gse/app/ProjectPane.java +++ b/gse-app/src/main/java/com/powsybl/gse/app/ProjectPane.java @@ -12,6 +12,7 @@ import com.powsybl.afs.*; import com.powsybl.afs.storage.AppStorage; import com.powsybl.afs.storage.NodeInfo; +import com.powsybl.afs.storage.Utils; import com.powsybl.afs.storage.events.*; import com.powsybl.commons.util.ServiceLoaderCache; import com.powsybl.gse.copy_paste.afs.CopyManager; @@ -49,6 +50,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; import java.lang.reflect.Field; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; @@ -721,9 +723,10 @@ private void archive(AbstractNodeBase item) { context.getExecutor().execute(() -> { TaskMonitor.Task task = project.getFileSystem().getTaskMonitor().startTask(String.format(RESOURCE_BUNDLE.getString("ArchiveTask"), selectedDirectory.getName()), project); try { + Utils.checkDiskSpace(selectedDirectory.toPath()); item.archive(selectedDirectory.toPath(), true); LOGGER.info("Archiving node {} ({}) is complete", item.getName(), item.getId()); - } catch (AfsException e) { + } catch (AfsException | IOException e) { GseAlerts.showDialogError(e.getMessage()); LOGGER.error("Archiving has failed for node {}", item.getId(), e); } finally { @@ -746,7 +749,7 @@ private void unarchiveItems(TreeItem folderItem) { context.getExecutor().execute(() -> { TaskMonitor.Task task = project.getFileSystem().getTaskMonitor().startTask(String.format(RESOURCE_BUNDLE.getString("UnarchiveTask"), selectedFile.getName()), project); try { - ((ProjectFolder) folder).unarchive(selectedFile.toPath(),true); + ((ProjectFolder) folder).unarchive(selectedFile.toPath(), true); Platform.runLater(() -> refresh(folderItem)); } catch (Exception e) { Platform.runLater(() -> GseAlerts.showDialogError(e.getMessage())); @@ -827,7 +830,7 @@ private void paste(TreeItem selectedTreeItem) { Platform.runLater(() -> { GseAlerts.showPasteCompleteInfo(nodeNames, projectFolder.getName()); }); - } catch (CopyPasteException e) { + } catch (CopyPasteException | IOException e) { LOGGER.error("Failed to copy nodes {}", projectNodes, e); Platform.runLater(() -> GseAlerts.showDialogCopyError(e)); } finally { diff --git a/gse-copy-paste-afs/src/main/java/com/powsybl/gse/copy_paste/afs/CopyManager.java b/gse-copy-paste-afs/src/main/java/com/powsybl/gse/copy_paste/afs/CopyManager.java index 45897005..e6648fc7 100644 --- a/gse-copy-paste-afs/src/main/java/com/powsybl/gse/copy_paste/afs/CopyManager.java +++ b/gse-copy-paste-afs/src/main/java/com/powsybl/gse/copy_paste/afs/CopyManager.java @@ -7,6 +7,7 @@ package com.powsybl.gse.copy_paste.afs; import com.powsybl.afs.*; +import com.powsybl.afs.storage.Utils; import com.powsybl.commons.util.ServiceLoaderCache; import com.powsybl.computation.local.LocalComputationManager; import com.powsybl.gse.copy_paste.afs.exceptions.*; @@ -61,7 +62,7 @@ private CopyManager() { init(); } - public void copyPaste(List nodes, AbstractNodeBase targetFolder) throws CopyPasteException { + public void copyPaste(List nodes, AbstractNodeBase targetFolder) throws CopyPasteException, IOException { String fileSystem = getCommonFileSystem(nodes); Optional targetProjectOpt = (targetFolder instanceof ProjectNode) ? Optional.of(((ProjectNode) targetFolder).getProject()) : Optional.empty(); Optional task = targetProjectOpt.map(targetProject -> targetProject.getFileSystem().getTaskMonitor().startTask("Copying", targetProject)); @@ -105,14 +106,6 @@ public Map copy(List nodes, @Nulla copyInfo.nodeId = node.getId(); copyInfo.node = node; copyInfo.archivePath = resolveArchiveTargetDirectory(targetDirectory); - - File archiveFile = copyInfo.archivePath.toFile(); - long freeSpacePercent = 100 * archiveFile.getFreeSpace() / archiveFile.getTotalSpace(); - LOGGER.info("Copying into drive with {}% free space", freeSpacePercent); - if (freeSpacePercent < MIN_DISK_SPACE_THRESHOLD) { - throw new CopyPasteException("Not enough space"); - } - copyInfo.expirationDate = ZonedDateTime.now().plusHours(COPY_EXPIRATION_TIME); currentCopies.put(copyInfo.nodeId, copyInfo); @@ -120,6 +113,7 @@ public Map copy(List nodes, @Nulla LOGGER.info("Copying (archiving) node {} ({})", node.getName(), node.getId()); logger.accept(String.format("Copying node %s", copyInfo.getNode().getName())); try { + Utils.checkDiskSpace(copyInfo.archivePath); node.archive(copyInfo.archivePath); copyInfo.archiveSuccess = true; LOGGER.info("Copying (archiving) node {} ({}) is complete", node.getName(), node.getId()); @@ -134,7 +128,7 @@ public Map copy(List nodes, @Nulla return currentCopies; } - public void paste(String fileSystemName, List nodesIds, AbstractNodeBase folder) throws CopyPasteException { + public void paste(String fileSystemName, List nodesIds, AbstractNodeBase folder) throws CopyPasteException, IOException { paste(fileSystemName, nodesIds, folder, LOGGER::debug); } @@ -142,7 +136,7 @@ public void paste(String fileSystemName, List nodesIds, AbstractNodeBase * @param nodesIds the copied node's id * @param folder the archive destination's folder */ - public void paste(String fileSystemName, List nodesIds, AbstractNodeBase folder, Consumer logger) throws CopyPasteException { + public void paste(String fileSystemName, List nodesIds, AbstractNodeBase folder, Consumer logger) throws CopyPasteException, IOException { Objects.requireNonNull(nodesIds); throwBadArgumentException(fileSystemName, folder); @@ -263,7 +257,7 @@ public void run() { }, CLEANUP_DELAY, CLEANUP_PERIOD); } - private String renameAndPaste(AbstractNodeBase folder, List children, CopyInfo info) throws CopyPasteException { + private String renameAndPaste(AbstractNodeBase folder, List children, CopyInfo info) throws CopyPasteException, IOException { for (AbstractNodeBase child : children) { String name = child.getName(); if (info.node.getName().equals(name)) { @@ -276,7 +270,7 @@ private String renameAndPaste(AbstractNodeBase folder, List nodes, AbstractNodeBase targetFolder) throws CopyPasteException; + void copyPaste(String fileSystemName, List nodes, AbstractNodeBase targetFolder) throws CopyPasteException, IOException; void copy(String fileSystemName, List nodes) throws CopyPasteException; - void paste(String fileSystemName, List nodesIds, AbstractNodeBase folder) throws CopyPasteException; + void paste(String fileSystemName, List nodesIds, AbstractNodeBase folder) throws CopyPasteException, IOException; } diff --git a/gse-util/src/main/java/com/powsybl/gse/util/NodeChooser.java b/gse-util/src/main/java/com/powsybl/gse/util/NodeChooser.java index 1b8a0827..396e3029 100644 --- a/gse-util/src/main/java/com/powsybl/gse/util/NodeChooser.java +++ b/gse-util/src/main/java/com/powsybl/gse/util/NodeChooser.java @@ -7,9 +7,9 @@ package com.powsybl.gse.util; import com.powsybl.afs.*; +import com.powsybl.afs.storage.Utils; import com.powsybl.gse.copy_paste.afs.CopyManager; import com.powsybl.gse.copy_paste.afs.CopyService; -import com.powsybl.gse.copy_paste.afs.exceptions.CopyPasteException; import com.powsybl.gse.spi.GseContext; import impl.org.controlsfx.skin.BreadCrumbBarSkin; import javafx.application.Platform; @@ -27,11 +27,11 @@ import javafx.scene.text.Text; import javafx.stage.*; import javafx.util.Callback; -import org.apache.commons.compress.archivers.ArchiveException; import org.controlsfx.control.BreadCrumbBar; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; import java.util.*; import java.util.function.BiPredicate; import java.util.prefs.Preferences; @@ -689,10 +689,11 @@ private void archive(AbstractNodeBase item) { context.getExecutor().execute(() -> { InfoDialog infoDialog = new InfoDialog(String.format(RESOURCE_BUNDLE.getString("ArchiveTask"), item.getName()), true); try { + Utils.checkDiskSpace(selectedDirectory.toPath()); item.archive(selectedDirectory.toPath(), true); infoDialog.updateStage(RESOURCE_BUNDLE.getString("CompleteTask")); LOGGER.info("Archiving node {} ({}) is complete", item.getName(), item.getId()); - } catch (AfsException e) { + } catch (AfsException | IOException e) { Platform.runLater(() -> GseAlerts.showDialogError(e.getMessage())); infoDialog.updateStage(RESOURCE_BUNDLE.getString("ErrorTask"), Color.RED); LOGGER.error("Archiving has failed for node {}", item.getId(), e); @@ -714,7 +715,7 @@ private void unarchiveItems(TreeItem folderItem) { context.getExecutor().execute(() -> { InfoDialog infoDialog = new InfoDialog(String.format(RESOURCE_BUNDLE.getString("UnarchiveTask"), selectedFile.getName()), true); try { - ((Folder) folder).unarchive(selectedFile.toPath(),true); + ((Folder) folder).unarchive(selectedFile.toPath(), true); infoDialog.updateStage(RESOURCE_BUNDLE.getString("CompleteTask")); Platform.runLater(() -> refresh(folderItem)); } catch (Exception e) { From f45bdd3c160c6b91f4f9ed62b02bfb792585b17f Mon Sep 17 00:00:00 2001 From: berthaultval Date: Wed, 5 Feb 2020 10:50:37 +0100 Subject: [PATCH 3/5] sonar corrections Signed-off-by: berthaultval --- .../main/java/com/powsybl/gse/copy_paste/afs/CopyManager.java | 3 +-- gse-util/src/main/java/com/powsybl/gse/util/NodeChooser.java | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/gse-copy-paste-afs/src/main/java/com/powsybl/gse/copy_paste/afs/CopyManager.java b/gse-copy-paste-afs/src/main/java/com/powsybl/gse/copy_paste/afs/CopyManager.java index e6648fc7..6d49086e 100644 --- a/gse-copy-paste-afs/src/main/java/com/powsybl/gse/copy_paste/afs/CopyManager.java +++ b/gse-copy-paste-afs/src/main/java/com/powsybl/gse/copy_paste/afs/CopyManager.java @@ -38,7 +38,6 @@ public final class CopyManager { private static final String NODE_COPY_TYPE = "@NODE@"; private static final String COPY_SIGNATURE = "@COPY_SIGNATURE@"; private static final long COPY_EXPIRATION_TIME = 6; - private static final long MIN_DISK_SPACE_THRESHOLD = 10; private static final Logger LOGGER = LoggerFactory.getLogger(CopyManager.class); private static final String TEMP_DIR_PREFIX = "powsybl_node_export"; private static final long CLEANUP_DELAY = 36000; @@ -270,7 +269,7 @@ private String renameAndPaste(AbstractNodeBase folder, List extends GridP private boolean success; private Set openedProjects = new HashSet<>(); private SimpleBooleanProperty deleteMenuItemDisableProperty = new SimpleBooleanProperty(false); - private final CopyManager localArchiveManager = CopyManager.getInstance(); private BooleanProperty copied = new SimpleBooleanProperty(false); From 4809f7442a60f363fcdd7f093b32b5e93ba5001b Mon Sep 17 00:00:00 2001 From: berthaultval Date: Thu, 6 Feb 2020 17:53:35 +0100 Subject: [PATCH 4/5] remarks corrections Signed-off-by: berthaultval --- .../java/com/powsybl/gse/copy_paste/afs/CopyManager.java | 8 ++++---- .../java/com/powsybl/gse/copy_paste/afs/CopyService.java | 5 ++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/gse-copy-paste-afs/src/main/java/com/powsybl/gse/copy_paste/afs/CopyManager.java b/gse-copy-paste-afs/src/main/java/com/powsybl/gse/copy_paste/afs/CopyManager.java index 6d49086e..4673574f 100644 --- a/gse-copy-paste-afs/src/main/java/com/powsybl/gse/copy_paste/afs/CopyManager.java +++ b/gse-copy-paste-afs/src/main/java/com/powsybl/gse/copy_paste/afs/CopyManager.java @@ -61,7 +61,7 @@ private CopyManager() { init(); } - public void copyPaste(List nodes, AbstractNodeBase targetFolder) throws CopyPasteException, IOException { + public void copyPaste(List nodes, AbstractNodeBase targetFolder) throws CopyPasteException { String fileSystem = getCommonFileSystem(nodes); Optional targetProjectOpt = (targetFolder instanceof ProjectNode) ? Optional.of(((ProjectNode) targetFolder).getProject()) : Optional.empty(); Optional task = targetProjectOpt.map(targetProject -> targetProject.getFileSystem().getTaskMonitor().startTask("Copying", targetProject)); @@ -127,7 +127,7 @@ public Map copy(List nodes, @Nulla return currentCopies; } - public void paste(String fileSystemName, List nodesIds, AbstractNodeBase folder) throws CopyPasteException, IOException { + public void paste(String fileSystemName, List nodesIds, AbstractNodeBase folder) throws CopyPasteException { paste(fileSystemName, nodesIds, folder, LOGGER::debug); } @@ -135,7 +135,7 @@ public void paste(String fileSystemName, List nodesIds, AbstractNodeBase * @param nodesIds the copied node's id * @param folder the archive destination's folder */ - public void paste(String fileSystemName, List nodesIds, AbstractNodeBase folder, Consumer logger) throws CopyPasteException, IOException { + public void paste(String fileSystemName, List nodesIds, AbstractNodeBase folder, Consumer logger) throws CopyPasteException { Objects.requireNonNull(nodesIds); throwBadArgumentException(fileSystemName, folder); @@ -256,7 +256,7 @@ public void run() { }, CLEANUP_DELAY, CLEANUP_PERIOD); } - private String renameAndPaste(AbstractNodeBase folder, List children, CopyInfo info) throws CopyPasteException, IOException { + private String renameAndPaste(AbstractNodeBase folder, List children, CopyInfo info) throws CopyPasteException { for (AbstractNodeBase child : children) { String name = child.getName(); if (info.node.getName().equals(name)) { diff --git a/gse-copy-paste-afs/src/main/java/com/powsybl/gse/copy_paste/afs/CopyService.java b/gse-copy-paste-afs/src/main/java/com/powsybl/gse/copy_paste/afs/CopyService.java index 23b74041..4fbd0d69 100644 --- a/gse-copy-paste-afs/src/main/java/com/powsybl/gse/copy_paste/afs/CopyService.java +++ b/gse-copy-paste-afs/src/main/java/com/powsybl/gse/copy_paste/afs/CopyService.java @@ -9,7 +9,6 @@ import com.powsybl.afs.AbstractNodeBase; import com.powsybl.gse.copy_paste.afs.exceptions.CopyPasteException; -import java.io.IOException; import java.util.List; /** @@ -17,9 +16,9 @@ */ public interface CopyService { - void copyPaste(String fileSystemName, List nodes, AbstractNodeBase targetFolder) throws CopyPasteException, IOException; + void copyPaste(String fileSystemName, List nodes, AbstractNodeBase targetFolder) throws CopyPasteException; void copy(String fileSystemName, List nodes) throws CopyPasteException; - void paste(String fileSystemName, List nodesIds, AbstractNodeBase folder) throws CopyPasteException, IOException; + void paste(String fileSystemName, List nodesIds, AbstractNodeBase folder) throws CopyPasteException; } From 1225e6b0c59158067b7cd50e1f7e83117fa92197 Mon Sep 17 00:00:00 2001 From: berthaultval Date: Thu, 6 Feb 2020 18:05:31 +0100 Subject: [PATCH 5/5] remarks corrections Signed-off-by: berthaultval --- gse-app/src/main/java/com/powsybl/gse/app/ProjectPane.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gse-app/src/main/java/com/powsybl/gse/app/ProjectPane.java b/gse-app/src/main/java/com/powsybl/gse/app/ProjectPane.java index 827d1a5f..a7655e68 100644 --- a/gse-app/src/main/java/com/powsybl/gse/app/ProjectPane.java +++ b/gse-app/src/main/java/com/powsybl/gse/app/ProjectPane.java @@ -830,7 +830,7 @@ private void paste(TreeItem selectedTreeItem) { Platform.runLater(() -> { GseAlerts.showPasteCompleteInfo(nodeNames, projectFolder.getName()); }); - } catch (CopyPasteException | IOException e) { + } catch (CopyPasteException e) { LOGGER.error("Failed to copy nodes {}", projectNodes, e); Platform.runLater(() -> GseAlerts.showDialogCopyError(e)); } finally {