Skip to content

Commit

Permalink
Fix duplicates in infinite canvas when pasting
Browse files Browse the repository at this point in the history
  • Loading branch information
d2dyno1 committed Nov 30, 2022
1 parent a22536b commit 4b18eaf
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public class InfiniteCanvasViewModel : BaseCanvasViewModel
{
#region Private Members

private bool _isPasting;

private CanvasItem? _lastPastedItem;

private FilesystemChangeWatcher2 _filesystemChangeWatcher;
Expand Down Expand Up @@ -98,120 +100,136 @@ public InfiniteCanvasViewModel(IBaseCanvasPreviewControlView view, BaseContentTy
public override async Task<SafeWrapperResult> 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
{
DiscardData();
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<CanvasItem> 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<CanvasItem> 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
{
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);
// Start filesystem change tracker
await StartFilesystemChangeWatcher((await InfiniteCanvasItem.SourceItem) as StorageFolder);

if (cancellationToken.IsCancellationRequested) // Check if it's canceled
{
DiscardData();
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<SafeWrapperResult> TryLoadExistingData(CanvasItem canvasItem, BaseContentTypeModel contentType, CancellationToken cancellationToken)
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,8 @@ public virtual Task SetupFilesystemWatcher()
Justification = "<Pending>")]
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 () =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down

0 comments on commit 4b18eaf

Please sign in to comment.