Skip to content

Commit 4b18eaf

Browse files
committed
Fix duplicates in infinite canvas when pasting
1 parent a22536b commit 4b18eaf

File tree

3 files changed

+97
-79
lines changed

3 files changed

+97
-79
lines changed

ClipboardCanvas/ViewModels/UserControls/CanvasDisplay/InfiniteCanvasViewModel.cs

Lines changed: 94 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ public class InfiniteCanvasViewModel : BaseCanvasViewModel
4444
{
4545
#region Private Members
4646

47+
private bool _isPasting;
48+
4749
private CanvasItem? _lastPastedItem;
4850

4951
private FilesystemChangeWatcher2 _filesystemChangeWatcher;
@@ -98,120 +100,136 @@ public InfiniteCanvasViewModel(IBaseCanvasPreviewControlView view, BaseContentTy
98100
public override async Task<SafeWrapperResult> TryPasteData(DataPackageView dataPackage, CancellationToken cancellationToken)
99101
{
100102
_lastPastedItem = null;
103+
_isPasting = true;
101104
this.cancellationToken = cancellationToken;
102105
SafeWrapperResult fetchDataToViewResult = SafeWrapperResult.SUCCESS;
103106

104-
RaiseOnPasteInitiatedEvent(this, new PasteInitiatedEventArgs(false, null, ContentType, AssociatedCollection));
105-
106-
// First, set Infinite Canvas folder
107-
SafeWrapperResult initializeInfiniteCanvasFolderResult = await InitializeInfiniteCanvasFolder();
108-
if (!AssertNoError(initializeInfiniteCanvasFolderResult)) // Default AssertNoError
109-
{
110-
return initializeInfiniteCanvasFolderResult;
111-
}
112-
113-
if (cancellationToken.IsCancellationRequested) // Check if it's canceled
107+
try
114108
{
115-
DiscardData();
116-
return SafeWrapperResult.CANCEL;
117-
}
118-
119-
// Get content type from data package
120-
BaseContentTypeModel pastedItemContentType = await BaseContentTypeModel.GetContentTypeFromDataPackage(dataPackage);
109+
RaiseOnPasteInitiatedEvent(this,
110+
new PasteInitiatedEventArgs(false, null, ContentType, AssociatedCollection));
121111

122-
if (pastedItemContentType is InvalidContentTypeDataModel invalidContentType)
123-
{
124-
if (invalidContentType.error == (OperationErrorCode.InvalidOperation | OperationErrorCode.NotAFile))
125-
{
126-
// This error code means user tried pasting a folder with Reference Files setting *disabled*
127-
AssertNoErrorInfiniteCanvas(invalidContentType.error); // Only for notification
128-
}
129-
else
112+
// First, set Infinite Canvas folder
113+
SafeWrapperResult initializeInfiniteCanvasFolderResult = await InitializeInfiniteCanvasFolder();
114+
if (!AssertNoError(initializeInfiniteCanvasFolderResult)) // Default AssertNoError
130115
{
131-
return invalidContentType.error;
116+
return initializeInfiniteCanvasFolderResult;
132117
}
133-
}
134-
else
135-
{
136-
// Get correct IPasteModel from contentType
137-
IPasteModel canvasPasteModel = CanvasHelpers.GetPasteModelFromContentType(pastedItemContentType, _infiniteCanvasFileReceiver, new StatusCenterOperationReceiver());
138118

139119
if (cancellationToken.IsCancellationRequested) // Check if it's canceled
140120
{
141121
DiscardData();
142122
return SafeWrapperResult.CANCEL;
143123
}
144124

145-
if (canvasPasteModel == null)
125+
// Get content type from data package
126+
BaseContentTypeModel pastedItemContentType =
127+
await BaseContentTypeModel.GetContentTypeFromDataPackage(dataPackage);
128+
129+
if (pastedItemContentType is InvalidContentTypeDataModel invalidContentType)
146130
{
147-
return BaseContentTypeModel.CannotDisplayContentForTypeResult;
131+
if (invalidContentType.error == (OperationErrorCode.InvalidOperation | OperationErrorCode.NotAFile))
132+
{
133+
// This error code means user tried pasting a folder with Reference Files setting *disabled*
134+
AssertNoErrorInfiniteCanvas(invalidContentType.error); // Only for notification
135+
}
136+
else
137+
{
138+
return invalidContentType.error;
139+
}
148140
}
141+
else
142+
{
143+
// Get correct IPasteModel from contentType
144+
IPasteModel canvasPasteModel = CanvasHelpers.GetPasteModelFromContentType(pastedItemContentType,
145+
_infiniteCanvasFileReceiver, new StatusCenterOperationReceiver());
146+
147+
if (cancellationToken.IsCancellationRequested) // Check if it's canceled
148+
{
149+
DiscardData();
150+
return SafeWrapperResult.CANCEL;
151+
}
149152

150-
// Paste data
151-
SafeWrapper<CanvasItem> pastedItem = await canvasPasteModel.PasteData(dataPackage, UserSettings.AlwaysPasteFilesAsReference, cancellationToken);
152-
_lastPastedItem = pastedItem.Result;
153+
if (canvasPasteModel == null)
154+
{
155+
return BaseContentTypeModel.CannotDisplayContentForTypeResult;
156+
}
153157

154-
// We don't need IPasteModel anymore, so dispose it
155-
canvasPasteModel.Dispose();
158+
// Paste data
159+
SafeWrapper<CanvasItem> pastedItem = await canvasPasteModel.PasteData(dataPackage,
160+
UserSettings.AlwaysPasteFilesAsReference, cancellationToken);
161+
_lastPastedItem = pastedItem.Result;
156162

157-
if (!pastedItem)
158-
{
159-
return pastedItem;
160-
}
163+
// We don't need IPasteModel anymore, so dispose it
164+
canvasPasteModel.Dispose();
161165

162-
// Add new object to Infinite Canvas
163-
var interactableCanvasControlItem = await InteractableCanvasControlModel.AddItem(AssociatedCollection, pastedItemContentType, pastedItem, _infiniteCanvasFileReceiver, cancellationToken);
166+
if (!pastedItem)
167+
{
168+
return pastedItem;
169+
}
170+
171+
// Add new object to Infinite Canvas
172+
var interactableCanvasControlItem = await InteractableCanvasControlModel.AddItem(
173+
AssociatedCollection, pastedItemContentType, pastedItem, _infiniteCanvasFileReceiver,
174+
cancellationToken);
175+
176+
if (cancellationToken.IsCancellationRequested) // Check if it's canceled
177+
{
178+
DiscardData();
179+
return SafeWrapperResult.CANCEL;
180+
}
181+
182+
// Wait for control to load
183+
await Task.Delay(Constants.UI.CONTROL_LOAD_DELAY);
184+
185+
// Update item position based on datapackage
186+
InteractableCanvasControlModel.UpdateItemPositionFromDataPackage(dataPackage,
187+
interactableCanvasControlItem);
188+
189+
// Save data after pasting
190+
SafeWrapperResult saveDataResult = await SaveConfigurationModel();
191+
192+
// Notify paste succeeded
193+
await OnPasteSucceeded(pastedItem);
194+
195+
if (cancellationToken.IsCancellationRequested) // Check if it's canceled
196+
{
197+
DiscardData();
198+
return SafeWrapperResult.CANCEL;
199+
}
200+
201+
AssertNoErrorInfiniteCanvas(saveDataResult); // Only for notification
202+
203+
// Fetch data to view
204+
fetchDataToViewResult = await interactableCanvasControlItem.LoadContent();
205+
}
164206

165207
if (cancellationToken.IsCancellationRequested) // Check if it's canceled
166208
{
167209
DiscardData();
168210
return SafeWrapperResult.CANCEL;
169211
}
170212

171-
// Wait for control to load
172-
await Task.Delay(Constants.UI.CONTROL_LOAD_DELAY);
173-
174-
// Update item position based on datapackage
175-
InteractableCanvasControlModel.UpdateItemPositionFromDataPackage(dataPackage, interactableCanvasControlItem);
176-
177-
// Save data after pasting
178-
SafeWrapperResult saveDataResult = await SaveConfigurationModel();
179-
180-
// Notify paste succeeded
181-
await OnPasteSucceeded(pastedItem);
213+
// Start filesystem change tracker
214+
await StartFilesystemChangeWatcher((await InfiniteCanvasItem.SourceItem) as StorageFolder);
182215

183216
if (cancellationToken.IsCancellationRequested) // Check if it's canceled
184217
{
185218
DiscardData();
186219
return SafeWrapperResult.CANCEL;
187220
}
188221

189-
AssertNoErrorInfiniteCanvas(saveDataResult); // Only for notification
222+
RefreshContextMenuItems();
190223

191-
// Fetch data to view
192-
fetchDataToViewResult = await interactableCanvasControlItem.LoadContent();
193-
}
224+
RaiseOnContentLoadedEvent(this,
225+
new ContentLoadedEventArgs(pastedItemContentType, false, false, CanPasteReference));
194226

195-
if (cancellationToken.IsCancellationRequested) // Check if it's canceled
196-
{
197-
DiscardData();
198-
return SafeWrapperResult.CANCEL;
227+
return fetchDataToViewResult;
199228
}
200-
201-
// Start filesystem change tracker
202-
await StartFilesystemChangeWatcher((await InfiniteCanvasItem.SourceItem) as StorageFolder);
203-
204-
if (cancellationToken.IsCancellationRequested) // Check if it's canceled
229+
finally
205230
{
206-
DiscardData();
207-
return SafeWrapperResult.CANCEL;
231+
_isPasting = false;
208232
}
209-
210-
RefreshContextMenuItems();
211-
212-
RaiseOnContentLoadedEvent(this, new ContentLoadedEventArgs(pastedItemContentType, false, false, CanPasteReference));
213-
214-
return fetchDataToViewResult;
215233
}
216234

217235
public override async Task<SafeWrapperResult> TryLoadExistingData(CanvasItem canvasItem, BaseContentTypeModel contentType, CancellationToken cancellationToken)
@@ -494,9 +512,7 @@ await MainWindow.Instance.DispatcherQueue.EnqueueAsync(async () =>
494512
{
495513
case WatcherChangeTypes.Created:
496514
{
497-
if (changedItem == null ||
498-
InteractableCanvasControlModel.ContainsItem(
499-
InteractableCanvasControlModel.FindItem(changedItem.Path)))
515+
if (changedItem == null || _isPasting || InteractableCanvasControlModel.FindItem(changedItem.Path) is not null)
500516
{
501517
return;
502518
}

ClipboardCanvas/ViewModels/UserControls/Collections/BaseCollectionViewModel.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,8 @@ public virtual Task SetupFilesystemWatcher()
682682
Justification = "<Pending>")]
683683
private async void FilesystemChangeWatcher_OnChangeRegisteredEvent(object sender, ChangeRegisteredEventArgs2 e)
684684
{
685+
// Issue: items are pasted added to collection twice
686+
return;
685687
try
686688
{
687689
await MainWindow.Instance.DispatcherQueue.EnqueueAsync(async () =>

ClipboardCanvas/ViewModels/UserControls/InteractableCanvasControlViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ public bool ContainsItem(InteractableCanvasControlItemViewModel item)
142142

143143
public InteractableCanvasControlItemViewModel FindItem(string path)
144144
{
145-
return Items.FirstOrDefault((item) => item.CanvasItem.AssociatedItem.Path == path);
145+
return Items.FirstOrDefault((item) => item.CanvasItem.AssociatedItem.Path.Equals(path));
146146
}
147147

148148
public InfiniteCanvasConfigurationModel ConstructConfigurationModel()

0 commit comments

Comments
 (0)