From 4b18eaffa83868ecb5c6a7bbb84d81a62d3521d9 Mon Sep 17 00:00:00 2001 From: d2dyno006 <53011783+d2dyno006@users.noreply.github.com> Date: Thu, 1 Dec 2022 00:36:34 +0100 Subject: [PATCH] Fix duplicates in infinite canvas when pasting --- .../CanvasDisplay/InfiniteCanvasViewModel.cs | 172 ++++++++++-------- .../Collections/BaseCollectionViewModel.cs | 2 + .../InteractableCanvasControlViewModel.cs | 2 +- 3 files changed, 97 insertions(+), 79 deletions(-) diff --git a/ClipboardCanvas/ViewModels/UserControls/CanvasDisplay/InfiniteCanvasViewModel.cs b/ClipboardCanvas/ViewModels/UserControls/CanvasDisplay/InfiniteCanvasViewModel.cs index 5cc7fdd3..9df785c1 100644 --- a/ClipboardCanvas/ViewModels/UserControls/CanvasDisplay/InfiniteCanvasViewModel.cs +++ b/ClipboardCanvas/ViewModels/UserControls/CanvasDisplay/InfiniteCanvasViewModel.cs @@ -44,6 +44,8 @@ public class InfiniteCanvasViewModel : BaseCanvasViewModel { #region Private Members + private bool _isPasting; + private CanvasItem? _lastPastedItem; private FilesystemChangeWatcher2 _filesystemChangeWatcher; @@ -98,43 +100,21 @@ public InfiniteCanvasViewModel(IBaseCanvasPreviewControlView view, BaseContentTy public override async Task TryPasteData(DataPackageView dataPackage, CancellationToken cancellationToken) { _lastPastedItem = null; + _isPasting = true; this.cancellationToken = cancellationToken; SafeWrapperResult fetchDataToViewResult = SafeWrapperResult.SUCCESS; - RaiseOnPasteInitiatedEvent(this, new PasteInitiatedEventArgs(false, null, ContentType, AssociatedCollection)); - - // First, set Infinite Canvas folder - SafeWrapperResult initializeInfiniteCanvasFolderResult = await InitializeInfiniteCanvasFolder(); - if (!AssertNoError(initializeInfiniteCanvasFolderResult)) // Default AssertNoError - { - return initializeInfiniteCanvasFolderResult; - } - - if (cancellationToken.IsCancellationRequested) // Check if it's canceled + try { - DiscardData(); - return SafeWrapperResult.CANCEL; - } - - // Get content type from data package - BaseContentTypeModel pastedItemContentType = await BaseContentTypeModel.GetContentTypeFromDataPackage(dataPackage); + RaiseOnPasteInitiatedEvent(this, + new PasteInitiatedEventArgs(false, null, ContentType, AssociatedCollection)); - if (pastedItemContentType is InvalidContentTypeDataModel invalidContentType) - { - if (invalidContentType.error == (OperationErrorCode.InvalidOperation | OperationErrorCode.NotAFile)) - { - // This error code means user tried pasting a folder with Reference Files setting *disabled* - AssertNoErrorInfiniteCanvas(invalidContentType.error); // Only for notification - } - else + // First, set Infinite Canvas folder + SafeWrapperResult initializeInfiniteCanvasFolderResult = await InitializeInfiniteCanvasFolder(); + if (!AssertNoError(initializeInfiniteCanvasFolderResult)) // Default AssertNoError { - return invalidContentType.error; + return initializeInfiniteCanvasFolderResult; } - } - else - { - // Get correct IPasteModel from contentType - IPasteModel canvasPasteModel = CanvasHelpers.GetPasteModelFromContentType(pastedItemContentType, _infiniteCanvasFileReceiver, new StatusCenterOperationReceiver()); if (cancellationToken.IsCancellationRequested) // Check if it's canceled { @@ -142,25 +122,87 @@ public override async Task TryPasteData(DataPackageView dataP return SafeWrapperResult.CANCEL; } - if (canvasPasteModel == null) + // Get content type from data package + BaseContentTypeModel pastedItemContentType = + await BaseContentTypeModel.GetContentTypeFromDataPackage(dataPackage); + + if (pastedItemContentType is InvalidContentTypeDataModel invalidContentType) { - return BaseContentTypeModel.CannotDisplayContentForTypeResult; + if (invalidContentType.error == (OperationErrorCode.InvalidOperation | OperationErrorCode.NotAFile)) + { + // This error code means user tried pasting a folder with Reference Files setting *disabled* + AssertNoErrorInfiniteCanvas(invalidContentType.error); // Only for notification + } + else + { + return invalidContentType.error; + } } + else + { + // Get correct IPasteModel from contentType + IPasteModel canvasPasteModel = CanvasHelpers.GetPasteModelFromContentType(pastedItemContentType, + _infiniteCanvasFileReceiver, new StatusCenterOperationReceiver()); + + if (cancellationToken.IsCancellationRequested) // Check if it's canceled + { + DiscardData(); + return SafeWrapperResult.CANCEL; + } - // Paste data - SafeWrapper pastedItem = await canvasPasteModel.PasteData(dataPackage, UserSettings.AlwaysPasteFilesAsReference, cancellationToken); - _lastPastedItem = pastedItem.Result; + if (canvasPasteModel == null) + { + return BaseContentTypeModel.CannotDisplayContentForTypeResult; + } - // We don't need IPasteModel anymore, so dispose it - canvasPasteModel.Dispose(); + // Paste data + SafeWrapper pastedItem = await canvasPasteModel.PasteData(dataPackage, + UserSettings.AlwaysPasteFilesAsReference, cancellationToken); + _lastPastedItem = pastedItem.Result; - if (!pastedItem) - { - return pastedItem; - } + // We don't need IPasteModel anymore, so dispose it + canvasPasteModel.Dispose(); - // Add new object to Infinite Canvas - var interactableCanvasControlItem = await InteractableCanvasControlModel.AddItem(AssociatedCollection, pastedItemContentType, pastedItem, _infiniteCanvasFileReceiver, cancellationToken); + if (!pastedItem) + { + return pastedItem; + } + + // Add new object to Infinite Canvas + var interactableCanvasControlItem = await InteractableCanvasControlModel.AddItem( + AssociatedCollection, pastedItemContentType, pastedItem, _infiniteCanvasFileReceiver, + cancellationToken); + + if (cancellationToken.IsCancellationRequested) // Check if it's canceled + { + DiscardData(); + return SafeWrapperResult.CANCEL; + } + + // Wait for control to load + await Task.Delay(Constants.UI.CONTROL_LOAD_DELAY); + + // Update item position based on datapackage + InteractableCanvasControlModel.UpdateItemPositionFromDataPackage(dataPackage, + interactableCanvasControlItem); + + // Save data after pasting + SafeWrapperResult saveDataResult = await SaveConfigurationModel(); + + // Notify paste succeeded + await OnPasteSucceeded(pastedItem); + + if (cancellationToken.IsCancellationRequested) // Check if it's canceled + { + DiscardData(); + return SafeWrapperResult.CANCEL; + } + + AssertNoErrorInfiniteCanvas(saveDataResult); // Only for notification + + // Fetch data to view + fetchDataToViewResult = await interactableCanvasControlItem.LoadContent(); + } if (cancellationToken.IsCancellationRequested) // Check if it's canceled { @@ -168,17 +210,8 @@ public override async Task TryPasteData(DataPackageView dataP return SafeWrapperResult.CANCEL; } - // Wait for control to load - await Task.Delay(Constants.UI.CONTROL_LOAD_DELAY); - - // Update item position based on datapackage - InteractableCanvasControlModel.UpdateItemPositionFromDataPackage(dataPackage, interactableCanvasControlItem); - - // Save data after pasting - SafeWrapperResult saveDataResult = await SaveConfigurationModel(); - - // Notify paste succeeded - await OnPasteSucceeded(pastedItem); + // Start filesystem change tracker + await StartFilesystemChangeWatcher((await InfiniteCanvasItem.SourceItem) as StorageFolder); if (cancellationToken.IsCancellationRequested) // Check if it's canceled { @@ -186,32 +219,17 @@ public override async Task TryPasteData(DataPackageView dataP return SafeWrapperResult.CANCEL; } - AssertNoErrorInfiniteCanvas(saveDataResult); // Only for notification + RefreshContextMenuItems(); - // Fetch data to view - fetchDataToViewResult = await interactableCanvasControlItem.LoadContent(); - } + RaiseOnContentLoadedEvent(this, + new ContentLoadedEventArgs(pastedItemContentType, false, false, CanPasteReference)); - if (cancellationToken.IsCancellationRequested) // Check if it's canceled - { - DiscardData(); - return SafeWrapperResult.CANCEL; + return fetchDataToViewResult; } - - // Start filesystem change tracker - await StartFilesystemChangeWatcher((await InfiniteCanvasItem.SourceItem) as StorageFolder); - - if (cancellationToken.IsCancellationRequested) // Check if it's canceled + finally { - DiscardData(); - return SafeWrapperResult.CANCEL; + _isPasting = false; } - - RefreshContextMenuItems(); - - RaiseOnContentLoadedEvent(this, new ContentLoadedEventArgs(pastedItemContentType, false, false, CanPasteReference)); - - return fetchDataToViewResult; } public override async Task TryLoadExistingData(CanvasItem canvasItem, BaseContentTypeModel contentType, CancellationToken cancellationToken) @@ -494,9 +512,7 @@ await MainWindow.Instance.DispatcherQueue.EnqueueAsync(async () => { case WatcherChangeTypes.Created: { - if (changedItem == null || - InteractableCanvasControlModel.ContainsItem( - InteractableCanvasControlModel.FindItem(changedItem.Path))) + if (changedItem == null || _isPasting || InteractableCanvasControlModel.FindItem(changedItem.Path) is not null) { return; } diff --git a/ClipboardCanvas/ViewModels/UserControls/Collections/BaseCollectionViewModel.cs b/ClipboardCanvas/ViewModels/UserControls/Collections/BaseCollectionViewModel.cs index 6665d8da..28a6d5b2 100644 --- a/ClipboardCanvas/ViewModels/UserControls/Collections/BaseCollectionViewModel.cs +++ b/ClipboardCanvas/ViewModels/UserControls/Collections/BaseCollectionViewModel.cs @@ -682,6 +682,8 @@ public virtual Task SetupFilesystemWatcher() Justification = "")] private async void FilesystemChangeWatcher_OnChangeRegisteredEvent(object sender, ChangeRegisteredEventArgs2 e) { + // Issue: items are pasted added to collection twice + return; try { await MainWindow.Instance.DispatcherQueue.EnqueueAsync(async () => diff --git a/ClipboardCanvas/ViewModels/UserControls/InteractableCanvasControlViewModel.cs b/ClipboardCanvas/ViewModels/UserControls/InteractableCanvasControlViewModel.cs index 6a1902f7..65e44d25 100644 --- a/ClipboardCanvas/ViewModels/UserControls/InteractableCanvasControlViewModel.cs +++ b/ClipboardCanvas/ViewModels/UserControls/InteractableCanvasControlViewModel.cs @@ -142,7 +142,7 @@ public bool ContainsItem(InteractableCanvasControlItemViewModel item) public InteractableCanvasControlItemViewModel FindItem(string path) { - return Items.FirstOrDefault((item) => item.CanvasItem.AssociatedItem.Path == path); + return Items.FirstOrDefault((item) => item.CanvasItem.AssociatedItem.Path.Equals(path)); } public InfiniteCanvasConfigurationModel ConstructConfigurationModel()