diff --git a/.gitignore b/.gitignore index 863e53de9..acd112022 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,5 @@ cov-report.xml .hubturboconfig/ # StyleCop -PowerPointLabs/PowerPointLabs/StyleCop.Cache \ No newline at end of file +PowerPointLabs/PowerPointLabs/StyleCop.Cache +PowerPointLabs/.vs/PowerPointLabs/v15/sqlite3/storage.ide \ No newline at end of file diff --git a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteAtCursorPosition/PasteAtCursorPositionActionHandler.cs b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteAtCursorPosition/PasteAtCursorPositionActionHandler.cs index 7c988efbd..d642a0e5f 100644 --- a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteAtCursorPosition/PasteAtCursorPositionActionHandler.cs +++ b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteAtCursorPosition/PasteAtCursorPositionActionHandler.cs @@ -5,6 +5,7 @@ using PowerPointLabs.Models; using PowerPointLabs.PasteLab; using PowerPointLabs.TextCollection; +using PowerPointLabs.Utils; using PPExtraEventHelper; @@ -30,7 +31,7 @@ class PasteAtCursorPositionActionHandler : PasteLabActionHandler positionY = ((coordinates.Y - activeWindow.PointsToScreenPixelsY(0)) / yref) * 100; } - ShapeRange pastingShapes = PasteShapesFromClipboard(slide); + ShapeRange pastingShapes = ClipboardUtil.PasteShapesFromClipboard(slide); if (pastingShapes == null) { return null; diff --git a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteAtCursorPosition/PasteAtCursorPositionEnabledHandler.cs b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteAtCursorPosition/PasteAtCursorPositionEnabledHandler.cs index a65a7c761..35d3d6006 100644 --- a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteAtCursorPosition/PasteAtCursorPositionEnabledHandler.cs +++ b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteAtCursorPosition/PasteAtCursorPositionEnabledHandler.cs @@ -10,7 +10,7 @@ class PasteAtCursorPositionEnabledHandler : EnabledHandler { protected override bool GetEnabled(string ribbonId) { - return !GraphicsUtil.IsClipboardEmpty(); + return !ClipboardUtil.IsClipboardEmpty(); } } } \ No newline at end of file diff --git a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteAtOriginalPosition/PasteAtOriginalPositionActionHandler.cs b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteAtOriginalPosition/PasteAtOriginalPositionActionHandler.cs index 386bef888..45ac3f070 100644 --- a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteAtOriginalPosition/PasteAtOriginalPositionActionHandler.cs +++ b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteAtOriginalPosition/PasteAtOriginalPositionActionHandler.cs @@ -3,6 +3,7 @@ using PowerPointLabs.ActionFramework.Common.Attribute; using PowerPointLabs.Models; using PowerPointLabs.TextCollection; +using PowerPointLabs.Utils; namespace PowerPointLabs.ActionFramework.PasteLab { @@ -13,11 +14,11 @@ class PasteAtOriginalPositionActionHandler : PasteLabActionHandler ShapeRange selectedShapes, ShapeRange selectedChildShapes) { PowerPointSlide tempSlide = presentation.AddSlide(index: slide.Index); - ShapeRange tempPastingShapes = PasteShapesFromClipboard(tempSlide); + ShapeRange tempPastingShapes = ClipboardUtil.PasteShapesFromClipboard(tempSlide); if (tempPastingShapes == null) { tempSlide.Delete(); - return PasteShapesFromClipboard(slide); + return ClipboardUtil.PasteShapesFromClipboard(slide); } ShapeRange pastingShapes = slide.CopyShapesToSlide(tempPastingShapes); diff --git a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteAtOriginalPosition/PasteAtOriginalPositionEnabledHandler.cs b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteAtOriginalPosition/PasteAtOriginalPositionEnabledHandler.cs index d947385d0..5be6353de 100644 --- a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteAtOriginalPosition/PasteAtOriginalPositionEnabledHandler.cs +++ b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteAtOriginalPosition/PasteAtOriginalPositionEnabledHandler.cs @@ -10,7 +10,7 @@ class PasteAtOriginalPositionEnabledHandler : EnabledHandler { protected override bool GetEnabled(string ribbonId) { - return !GraphicsUtil.IsClipboardEmpty(); + return !ClipboardUtil.IsClipboardEmpty(); } } } \ No newline at end of file diff --git a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteIntoGroup/PasteIntoGroupActionHandler.cs b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteIntoGroup/PasteIntoGroupActionHandler.cs index 4138160a2..7772a5516 100644 --- a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteIntoGroup/PasteIntoGroupActionHandler.cs +++ b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteIntoGroup/PasteIntoGroupActionHandler.cs @@ -27,7 +27,7 @@ class PasteIntoGroupActionHandler : PasteLabActionHandler return null; } - ShapeRange pastingShapes = PasteShapesFromClipboard(slide); + ShapeRange pastingShapes = ClipboardUtil.PasteShapesFromClipboard(slide); if (pastingShapes == null) { return null; diff --git a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteIntoGroup/PasteIntoGroupEnabledHandler.cs b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteIntoGroup/PasteIntoGroupEnabledHandler.cs index e33cdea21..2d5fec733 100644 --- a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteIntoGroup/PasteIntoGroupEnabledHandler.cs +++ b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteIntoGroup/PasteIntoGroupEnabledHandler.cs @@ -14,7 +14,7 @@ class PasteIntoGroupEnabledHandler : EnabledHandler protected override bool GetEnabled(string ribbonId) { Selection currentSelection = this.GetCurrentSelection(); - return !GraphicsUtil.IsClipboardEmpty() && + return !ClipboardUtil.IsClipboardEmpty() && ShapeUtil.IsSelectionMultipleOrGroup(currentSelection) && !ShapeUtil.HasPlaceholderInSelection(currentSelection); } diff --git a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteLabActionHandler.cs b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteLabActionHandler.cs index 52bf81b76..ed067c7b6 100644 --- a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteLabActionHandler.cs +++ b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteLabActionHandler.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Runtime.InteropServices; using Microsoft.Office.Interop.PowerPoint; @@ -25,7 +24,7 @@ protected sealed override void ExecuteAction(string ribbonId) PowerPointSlide slide = this.GetCurrentSlide(); Selection selection = this.GetCurrentSelection(); - if (GraphicsUtil.IsClipboardEmpty()) + if (ClipboardUtil.IsClipboardEmpty()) { Logger.Log(ribbonId + " failed. Clipboard is empty."); return; @@ -36,9 +35,13 @@ protected sealed override void ExecuteAction(string ribbonId) if (ShapeUtil.IsSelectionShape(selection) && !IsSelectionIgnored(ribbonId)) { + // When pasting some objects, the selection may change to the pasted object (e.g. jpg from desktop). + // Therefore we must capture the selection first. + ShapeRange selectedShapes = selection.ShapeRange; + // Save clipboard onto a temp slide, because CorruptionCorrrection uses Copy-Paste PowerPointSlide tempClipboardSlide = presentation.AddSlide(index: slide.Index); - ShapeRange tempClipboardShapes = PasteShapesFromClipboard(tempClipboardSlide); + ShapeRange tempClipboardShapes = ClipboardUtil.PasteShapesFromClipboard(tempClipboardSlide); // Nothing is pasted, stop now if (tempClipboardShapes == null) @@ -47,8 +50,7 @@ protected sealed override void ExecuteAction(string ribbonId) return; } - // Preserve selection using tags - ShapeRange selectedShapes = selection.ShapeRange; + // Preserve selection by tagging them for (int i = 1; i <= selectedShapes.Count; i++) { selectedShapes[i].Tags.Add(SelectOrderTagName, i.ToString()); @@ -80,7 +82,7 @@ protected sealed override void ExecuteAction(string ribbonId) passedSelectedShapes = slide.ToShapeRange(correctedShapeList); passedSelectedChildShapes = slide.ToShapeRange(correctedChildShapeList); - // Remove the tags after they have been used + // Remove shape tags after they have been used ShapeUtil.DeleteTagFromShapes(passedSelectedShapes, SelectOrderTagName); ShapeUtil.DeleteTagFromShapes(passedSelectedChildShapes, SelectChildOrderTagName); @@ -99,20 +101,6 @@ protected sealed override void ExecuteAction(string ribbonId) protected abstract ShapeRange ExecutePasteAction(string ribbonId, PowerPointPresentation presentation, PowerPointSlide slide, ShapeRange selectedShapes, ShapeRange selectedChildShapes); - protected ShapeRange PasteShapesFromClipboard(PowerPointSlide slide) - { - try - { - return slide.Shapes.Paste(); - } - catch (COMException e) - { - // May be thrown if there is placeholder shape in clipboard - Logger.LogException(e, "PasteShapeFromClipboard"); - return null; - } - } - private bool IsSelectionIgnored(string ribbonId) { return ribbonId.StartsWith("PasteAtCursorPosition") || diff --git a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteToFillSlide/PasteToFillSlideActionHandler.cs b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteToFillSlide/PasteToFillSlideActionHandler.cs index 38a593ad9..7a5f713e7 100644 --- a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteToFillSlide/PasteToFillSlideActionHandler.cs +++ b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteToFillSlide/PasteToFillSlideActionHandler.cs @@ -4,6 +4,7 @@ using PowerPointLabs.Models; using PowerPointLabs.PasteLab; using PowerPointLabs.TextCollection; +using PowerPointLabs.Utils; namespace PowerPointLabs.ActionFramework.PasteLab { @@ -13,7 +14,7 @@ class PasteToFillSlideActionHandler : PasteLabActionHandler protected override ShapeRange ExecutePasteAction(string ribbonId, PowerPointPresentation presentation, PowerPointSlide slide, ShapeRange selectedShapes, ShapeRange selectedChildShapes) { - ShapeRange pastingShapes = PasteShapesFromClipboard(slide); + ShapeRange pastingShapes = ClipboardUtil.PasteShapesFromClipboard(slide); if (pastingShapes == null) { return null; diff --git a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteToFillSlide/PasteToFillSlideEnabledHandler.cs b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteToFillSlide/PasteToFillSlideEnabledHandler.cs index 7b3c8b0ba..da2391eff 100644 --- a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteToFillSlide/PasteToFillSlideEnabledHandler.cs +++ b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/PasteToFillSlide/PasteToFillSlideEnabledHandler.cs @@ -10,7 +10,7 @@ class PasteToFillSlideEnabledHandler : EnabledHandler { protected override bool GetEnabled(string ribbonId) { - return !GraphicsUtil.IsClipboardEmpty(); + return !ClipboardUtil.IsClipboardEmpty(); } } } diff --git a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/ReplaceWithClipboard/ReplaceWithClipboardActionHandler.cs b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/ReplaceWithClipboard/ReplaceWithClipboardActionHandler.cs index 504ded8cb..cf00d2cb5 100644 --- a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/ReplaceWithClipboard/ReplaceWithClipboardActionHandler.cs +++ b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/ReplaceWithClipboard/ReplaceWithClipboardActionHandler.cs @@ -6,6 +6,7 @@ using PowerPointLabs.Models; using PowerPointLabs.PasteLab; using PowerPointLabs.TextCollection; +using PowerPointLabs.Utils; namespace PowerPointLabs.ActionFramework.PasteLab { @@ -21,7 +22,7 @@ class ReplaceWithClipboardActionHandler : PasteLabActionHandler return null; } - ShapeRange pastingShapes = PasteShapesFromClipboard(slide); + ShapeRange pastingShapes = ClipboardUtil.PasteShapesFromClipboard(slide); if (pastingShapes == null) { return null; diff --git a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/ReplaceWithClipboard/ReplaceWithClipboardEnabledHandler.cs b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/ReplaceWithClipboard/ReplaceWithClipboardEnabledHandler.cs index 17d6b0f0e..71692d4ad 100644 --- a/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/ReplaceWithClipboard/ReplaceWithClipboardEnabledHandler.cs +++ b/PowerPointLabs/PowerPointLabs/ActionFramework/PasteLab/ReplaceWithClipboard/ReplaceWithClipboardEnabledHandler.cs @@ -14,7 +14,7 @@ class ReplaceWithClipboardEnabledHandler : EnabledHandler protected override bool GetEnabled(string ribbonId) { Selection currentSelection = this.GetCurrentSelection(); - return !GraphicsUtil.IsClipboardEmpty() && + return !ClipboardUtil.IsClipboardEmpty() && ShapeUtil.IsSelectionSingleShape(currentSelection) && !ShapeUtil.HasPlaceholderInSelection(currentSelection); } diff --git a/PowerPointLabs/PowerPointLabs/PowerPointLabs.csproj b/PowerPointLabs/PowerPointLabs/PowerPointLabs.csproj index c8cc14216..148f09a71 100644 --- a/PowerPointLabs/PowerPointLabs/PowerPointLabs.csproj +++ b/PowerPointLabs/PowerPointLabs/PowerPointLabs.csproj @@ -641,6 +641,7 @@ + diff --git a/PowerPointLabs/PowerPointLabs/SyncLab/Views/SyncPaneWPF.xaml.cs b/PowerPointLabs/PowerPointLabs/SyncLab/Views/SyncPaneWPF.xaml.cs index 766055d1d..3551cb77f 100644 --- a/PowerPointLabs/PowerPointLabs/SyncLab/Views/SyncPaneWPF.xaml.cs +++ b/PowerPointLabs/PowerPointLabs/SyncLab/Views/SyncPaneWPF.xaml.cs @@ -5,7 +5,7 @@ using Microsoft.Office.Interop.PowerPoint; -using static PowerPointLabs.ActionFramework.Common.Extension.ContentControlExtensions; +using PowerPointLabs.ActionFramework.Common.Extension; using PowerPointLabs.TextCollection; using PowerPointLabs.Utils; diff --git a/PowerPointLabs/PowerPointLabs/Utils/ClipboardUtil.cs b/PowerPointLabs/PowerPointLabs/Utils/ClipboardUtil.cs new file mode 100644 index 000000000..deedfc152 --- /dev/null +++ b/PowerPointLabs/PowerPointLabs/Utils/ClipboardUtil.cs @@ -0,0 +1,50 @@ +using System.Runtime.InteropServices; +using System.Windows.Forms; + +using Microsoft.Office.Interop.PowerPoint; + +using PowerPointLabs.ActionFramework.Common.Log; +using PowerPointLabs.Models; + +namespace PowerPointLabs.Utils +{ + internal static class ClipboardUtil + { + #region API + + public static bool IsClipboardEmpty() + { + IDataObject clipboardData = Clipboard.GetDataObject(); + return clipboardData == null || clipboardData.GetFormats().Length == 0; + } + + public static ShapeRange PasteShapesFromClipboard(PowerPointSlide slide) + { + try + { + // Note: Some copied objects are pasted on currentSlide rather than the desired slide (e.g. jpg from desktop), + // so we must check whether it is pasted correctly, else we cut-and-paste it into the correct slide. + + int initialSlideShapesCount = slide.Shapes.Count; + ShapeRange pastedShapes = slide.Shapes.Paste(); + + int finalSlideShapesCount = slide.Shapes.Count; + if (pastedShapes.Count >= 1 && finalSlideShapesCount == initialSlideShapesCount) + { + pastedShapes.Cut(); + pastedShapes = slide.Shapes.Paste(); + } + + return pastedShapes; + } + catch (COMException e) + { + // May be thrown if there is placeholder shape in clipboard + Logger.LogException(e, "PasteShapeFromClipboard"); + return null; + } + } + + #endregion + } +} diff --git a/PowerPointLabs/PowerPointLabs/Utils/GraphicsUtil.cs b/PowerPointLabs/PowerPointLabs/Utils/GraphicsUtil.cs index c30ee6772..ddf4c2eae 100644 --- a/PowerPointLabs/PowerPointLabs/Utils/GraphicsUtil.cs +++ b/PowerPointLabs/PowerPointLabs/Utils/GraphicsUtil.cs @@ -40,20 +40,10 @@ static GraphicsUtil() dpiScale = g.DpiX / TargetDpi; } } - # endregion - - # region API - - # region Clipboard - - public static bool IsClipboardEmpty() - { - IDataObject clipboardData = Clipboard.GetDataObject(); - return clipboardData == null || clipboardData.GetFormats().Length == 0; - } - #endregion + #region API + #region Shape public static void ExportShape(Shape shape, string exportPath) @@ -109,7 +99,7 @@ public static Bitmap ShapeToBitmap(Shape shape) #endregion - # region Slide + #region Slide public static void ExportSlide(Slide slide, string exportPath, float magnifyRatio = 1.0f) { slide.Export(exportPath, @@ -123,9 +113,9 @@ public static void ExportSlide(PowerPointSlide slide, string exportPath, float m ExportSlide(slide.GetNativeSlide(), exportPath, magnifyRatio); } - # endregion + #endregion - # region Bitmap + #region Bitmap public static Bitmap CreateThumbnailImage(Image oriImage, int width, int height) { var scalingRatio = CalculateScalingRatio(oriImage.Size, new Size(width, height)); @@ -153,9 +143,9 @@ public static Bitmap CreateThumbnailImage(Image oriImage, int width, int height) return thumbnail; } - # endregion + #endregion - # region GDI+ + #region GDI+ public static void SuspendDrawing(Control control) { Native.SendMessage(control.Handle, (uint) Native.Message.WM_SETREDRAW, IntPtr.Zero, IntPtr.Zero); @@ -166,9 +156,9 @@ public static void ResumeDrawing(Control control) Native.SendMessage(control.Handle, (uint) Native.Message.WM_SETREDRAW, new IntPtr(1), IntPtr.Zero); control.Refresh(); } - # endregion + #endregion - # region Color + #region Color public static int ConvertColorToRgb(Drawing.Color argb) { return (argb.B << 16) | (argb.G << 8) | argb.R; @@ -282,6 +272,6 @@ public static float GetDpiScale() { return dpiScale; } - # endregion + #endregion } }