diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..13e4bb7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,133 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.svclog +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.pubxml +*.azurePubxml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +packages/ +## TODO: If the tool you use requires repositories.config, also uncomment the next line +!packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +![Ss]tyle[Cc]op.targets +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml + +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac desktop service store files +.DS_Store + +_NCrunch* \ No newline at end of file diff --git a/FileFormat.Slides-Test/Program.cs b/FileFormat.Slides-Test/Program.cs index 826cd3c..39711fd 100644 --- a/FileFormat.Slides-Test/Program.cs +++ b/FileFormat.Slides-Test/Program.cs @@ -2,7 +2,7 @@ using PKG = DocumentFormat.OpenXml.Packaging; using P = DocumentFormat.OpenXml.Presentation; using System; -using GeneratedCode; +//using GeneratedCode; using FileFormat.Slides; using System.Collections.Generic; using FileFormat.Slides.Common; diff --git a/FileFormat.Slides.Common/FileFormat.Slides.Common.csproj b/FileFormat.Slides.Common/FileFormat.Slides.Common.csproj index 49c4d01..f8485ba 100644 --- a/FileFormat.Slides.Common/FileFormat.Slides.Common.csproj +++ b/FileFormat.Slides.Common/FileFormat.Slides.Common.csproj @@ -4,8 +4,17 @@ netcoreapp3.1 + + + + + + diff --git a/FileFormat.Slides.Facade/PresentationDocumentFacade.cs b/FileFormat.Slides.Facade/PresentationDocumentFacade.cs index 5338004..15e2208 100644 --- a/FileFormat.Slides.Facade/PresentationDocumentFacade.cs +++ b/FileFormat.Slides.Facade/PresentationDocumentFacade.cs @@ -564,8 +564,12 @@ public void InsertSlide (int index, SlideFacade slideFacade) { slideFacade.PresentationSlide.Save(slideFacade.SlidePart); _PresentationSlideParts.Add(slideFacade.SlidePart); - MoveSlideToIndex(slideFacade.SlideIndex, index); + // find the current index of the slide in the list and then move it to the specified index + var relationshipId = slideFacade.RelationshipId; + var currentIndex = _SlideIdList.Elements().ToList().FindIndex(item => item.RelationshipId == relationshipId); + + MoveSlideToIndex(slideFacade.SlideIndex, index); } public void MoveSlideToIndex (int currentIndex, int newIndex) diff --git a/FileFormat.Slides.Tests/FileFormat.Slides.Tests.csproj b/FileFormat.Slides.Tests/FileFormat.Slides.Tests.csproj new file mode 100644 index 0000000..6757b9f --- /dev/null +++ b/FileFormat.Slides.Tests/FileFormat.Slides.Tests.csproj @@ -0,0 +1,22 @@ + + + + netcoreapp3.1 + + false + + + + + + + + + + + + + + + + diff --git a/FileFormat.Slides.Tests/InsertSlideTests.cs b/FileFormat.Slides.Tests/InsertSlideTests.cs new file mode 100644 index 0000000..043f084 --- /dev/null +++ b/FileFormat.Slides.Tests/InsertSlideTests.cs @@ -0,0 +1,222 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Linq; +using System.IO; +using System.Collections.Generic; + +namespace FileFormat.Slides.Tests +{ + [TestClass] + public class InsertSlideTests + { + protected List tempFileList = new List(); + + protected Presentation GetSimplePresentation(int numberOfSlides = 3) + { + var tempFile = Path.GetTempFileName(); + var tempPresentationFilename = $"{tempFile}.pptx"; + + // track our mess + tempFileList.Add(tempFile); + tempFileList.Add(tempPresentationFilename); + + Presentation presentation = Presentation.Create(tempPresentationFilename); + + for (var i = 0; i < numberOfSlides; i++) + { + var slideId = $"{i + 1}".PadLeft(3, '0'); + Slide slide = new Slide(); + slide.AddTextShapes(new TextShape() + { + Text = $"this is is slide: {slideId}", + FontSize = 80 + + }); + presentation.AppendSlide(slide); + } + + return presentation; + } + + protected Slide BuildSimpleSlide() + { + Slide slide = new Slide(); + slide.AddTextShapes(new TextShape() + { + Text = "this is is slide: 009", + FontSize = 80 + + }); + return slide; + } + + protected string[] GetRelationshipIdsInOrder(Presentation presentation) + { + return presentation.Facade.SlideIdList.ChildElements + .Select(s => (s as DocumentFormat.OpenXml.Presentation.SlideId).RelationshipId.Value) + .ToArray(); + } + + [TestCleanup] + public void CleanUp() + { + if (tempFileList.Any()) + { + foreach(var file in tempFileList) + { + try { + File.Delete(file); + } + catch { + Console.WriteLine($"Failed to delete: {file}"); + } + } + } + } + + [TestMethod] + public void InsertSlideAtPositionZero() + { + var presentation = GetSimplePresentation(); + var idList = GetRelationshipIdsInOrder(presentation); + + // insert a new slide at the begining of the presentation + Slide slide = BuildSimpleSlide(); + presentation.InsertSlideAt(0, slide); + + // get the new relationship id from it to build out the expected list + var newSlideRelationshipId = slide.RelationshipId; + var expectedIds = new string[] { newSlideRelationshipId, idList[0], idList[1], idList[2] }; + + // Get the current list post insert + var updatedIdList = GetRelationshipIdsInOrder(presentation); + + // validate the slide is where we expext it to be + CollectionAssert.AreEqual(expectedIds, updatedIdList); + + presentation.Save(); + presentation.close(); + } + + [TestMethod] + public void InsertSlideAtPositionOne() + { + var presentation = GetSimplePresentation(); + var idList = GetRelationshipIdsInOrder(presentation); + + // insert a new slide at the begining of the presentation + Slide slide = BuildSimpleSlide(); + presentation.InsertSlideAt(1, slide); + + // get the new relationship id from it to build out the expected list + var newSlideRelationshipId = slide.RelationshipId; + var expectedIds = new string[] { idList[0], newSlideRelationshipId, idList[1], idList[2] }; + + // Get the current list post insert + var updatedIdList = GetRelationshipIdsInOrder(presentation); + + // validate the slide is where we expext it to be + CollectionAssert.AreEqual(expectedIds, updatedIdList); + + presentation.Save(); + presentation.close(); + } + + [TestMethod] + public void InsertSlideAtPositionTwo() + { + var presentation = GetSimplePresentation(); + var idList = GetRelationshipIdsInOrder(presentation); + + // insert a new slide at the begining of the presentation + Slide slide = BuildSimpleSlide(); + presentation.InsertSlideAt(2, slide); + + // get the new relationship id from it to build out the expected list + var newSlideRelationshipId = slide.RelationshipId; + var expectedIds = new string[] { idList[0], idList[1], newSlideRelationshipId, idList[2] }; + + // Get the current list post insert + var updatedIdList = GetRelationshipIdsInOrder(presentation); + + // validate the slide is where we expext it to be + CollectionAssert.AreEqual(expectedIds, updatedIdList); + + presentation.Save(); + presentation.close(); + } + + [TestMethod] + public void InsertSlideAtPositionThree() + { + var presentation = GetSimplePresentation(); + var idList = GetRelationshipIdsInOrder(presentation); + + // insert a new slide at the begining of the presentation + Slide slide = BuildSimpleSlide(); + presentation.InsertSlideAt(3, slide); + + // get the new relationship id from it to build out the expected list + var newSlideRelationshipId = slide.RelationshipId; + var expectedIds = new string[] { idList[0], idList[1], idList[2], newSlideRelationshipId }; + + // Get the current list post insert + var updatedIdList = GetRelationshipIdsInOrder(presentation); + + // validate the slide is where we expext it to be + CollectionAssert.AreEqual(expectedIds, updatedIdList); + + presentation.Save(); + presentation.close(); + } + + [TestMethod] + public void InsertSlideAtPositionOutOfRangeHigh() + { + var presentation = GetSimplePresentation(); + var idList = GetRelationshipIdsInOrder(presentation); + + // insert a new slide at the begining of the presentation + Slide slide = BuildSimpleSlide(); + presentation.InsertSlideAt(99, slide); + + // get the new relationship id from it to build out the expected list + var newSlideRelationshipId = slide.RelationshipId; + var expectedIds = new string[] { idList[0], idList[1], idList[2], newSlideRelationshipId }; + + // Get the current list post insert + var updatedIdList = GetRelationshipIdsInOrder(presentation); + + // validate the slide is where we expext it to be + CollectionAssert.AreEqual(expectedIds, updatedIdList); + + presentation.Save(); + presentation.close(); + } + + [TestMethod] + public void InsertSlideAtPositionOutOfRangeLow() + { + var presentation = GetSimplePresentation(); + var idList = GetRelationshipIdsInOrder(presentation); + + // insert a new slide at the begining of the presentation + Slide slide = BuildSimpleSlide(); + presentation.InsertSlideAt(-5, slide); + + // get the new relationship id from it to build out the expected list + var newSlideRelationshipId = slide.RelationshipId; + var expectedIds = new string[] { idList[0], idList[1], idList[2], newSlideRelationshipId }; + + // Get the current list post insert + var updatedIdList = GetRelationshipIdsInOrder(presentation); + + // validate the slide is where we expext it to be + CollectionAssert.AreEqual(expectedIds, updatedIdList); + + presentation.Save(); + presentation.close(); + } + + } +} diff --git a/FileFormat.Slides.sln b/FileFormat.Slides.sln index d91020f..2b07a0e 100644 --- a/FileFormat.Slides.sln +++ b/FileFormat.Slides.sln @@ -1,43 +1,49 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.33130.400 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileFormat.Slides", "FileFormat.Slides\FileFormat.Slides.csproj", "{17F3D657-D3AB-406E-AA9C-FF8613FB81E9}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileFormat.Slides.Common", "FileFormat.Slides.Common\FileFormat.Slides.Common.csproj", "{A8EAE068-8E31-4866-A600-5CC17FE1F423}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileFormat.Slides.Facade", "Fileformat.Slides.Facade\FileFormat.Slides.Facade.csproj", "{42D256AA-5DB9-4CC9-B290-BA7C86108BEF}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileFormat.Slides-Test", "FileFormat.Slides-Test\FileFormat.Slides-Test.csproj", "{10A9AE59-4C5D-4D6B-82FB-4F066EA7CA53}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {17F3D657-D3AB-406E-AA9C-FF8613FB81E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {17F3D657-D3AB-406E-AA9C-FF8613FB81E9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {17F3D657-D3AB-406E-AA9C-FF8613FB81E9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {17F3D657-D3AB-406E-AA9C-FF8613FB81E9}.Release|Any CPU.Build.0 = Release|Any CPU - {A8EAE068-8E31-4866-A600-5CC17FE1F423}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A8EAE068-8E31-4866-A600-5CC17FE1F423}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A8EAE068-8E31-4866-A600-5CC17FE1F423}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A8EAE068-8E31-4866-A600-5CC17FE1F423}.Release|Any CPU.Build.0 = Release|Any CPU - {42D256AA-5DB9-4CC9-B290-BA7C86108BEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {42D256AA-5DB9-4CC9-B290-BA7C86108BEF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {42D256AA-5DB9-4CC9-B290-BA7C86108BEF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {42D256AA-5DB9-4CC9-B290-BA7C86108BEF}.Release|Any CPU.Build.0 = Release|Any CPU - {10A9AE59-4C5D-4D6B-82FB-4F066EA7CA53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {10A9AE59-4C5D-4D6B-82FB-4F066EA7CA53}.Debug|Any CPU.Build.0 = Debug|Any CPU - {10A9AE59-4C5D-4D6B-82FB-4F066EA7CA53}.Release|Any CPU.ActiveCfg = Release|Any CPU - {10A9AE59-4C5D-4D6B-82FB-4F066EA7CA53}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {3AB71A27-7437-4743-B8BB-D37886E02DC2} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.33130.400 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileFormat.Slides", "FileFormat.Slides\FileFormat.Slides.csproj", "{17F3D657-D3AB-406E-AA9C-FF8613FB81E9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileFormat.Slides.Common", "FileFormat.Slides.Common\FileFormat.Slides.Common.csproj", "{A8EAE068-8E31-4866-A600-5CC17FE1F423}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileFormat.Slides.Facade", "Fileformat.Slides.Facade\FileFormat.Slides.Facade.csproj", "{42D256AA-5DB9-4CC9-B290-BA7C86108BEF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileFormat.Slides-Test", "FileFormat.Slides-Test\FileFormat.Slides-Test.csproj", "{10A9AE59-4C5D-4D6B-82FB-4F066EA7CA53}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileFormat.Slides.Tests", "FileFormat.Slides.Tests\FileFormat.Slides.Tests.csproj", "{A87C0119-FA6E-465A-AA7B-5D30FFA8A5B9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {17F3D657-D3AB-406E-AA9C-FF8613FB81E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {17F3D657-D3AB-406E-AA9C-FF8613FB81E9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {17F3D657-D3AB-406E-AA9C-FF8613FB81E9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {17F3D657-D3AB-406E-AA9C-FF8613FB81E9}.Release|Any CPU.Build.0 = Release|Any CPU + {A8EAE068-8E31-4866-A600-5CC17FE1F423}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A8EAE068-8E31-4866-A600-5CC17FE1F423}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A8EAE068-8E31-4866-A600-5CC17FE1F423}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A8EAE068-8E31-4866-A600-5CC17FE1F423}.Release|Any CPU.Build.0 = Release|Any CPU + {42D256AA-5DB9-4CC9-B290-BA7C86108BEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {42D256AA-5DB9-4CC9-B290-BA7C86108BEF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {42D256AA-5DB9-4CC9-B290-BA7C86108BEF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {42D256AA-5DB9-4CC9-B290-BA7C86108BEF}.Release|Any CPU.Build.0 = Release|Any CPU + {10A9AE59-4C5D-4D6B-82FB-4F066EA7CA53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {10A9AE59-4C5D-4D6B-82FB-4F066EA7CA53}.Debug|Any CPU.Build.0 = Debug|Any CPU + {10A9AE59-4C5D-4D6B-82FB-4F066EA7CA53}.Release|Any CPU.ActiveCfg = Release|Any CPU + {10A9AE59-4C5D-4D6B-82FB-4F066EA7CA53}.Release|Any CPU.Build.0 = Release|Any CPU + {A87C0119-FA6E-465A-AA7B-5D30FFA8A5B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A87C0119-FA6E-465A-AA7B-5D30FFA8A5B9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A87C0119-FA6E-465A-AA7B-5D30FFA8A5B9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A87C0119-FA6E-465A-AA7B-5D30FFA8A5B9}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3AB71A27-7437-4743-B8BB-D37886E02DC2} + EndGlobalSection +EndGlobal diff --git a/FileFormat.Slides/FileFormat.Slides.csproj b/FileFormat.Slides/FileFormat.Slides.csproj index aedc70f..afcf32f 100644 --- a/FileFormat.Slides/FileFormat.Slides.csproj +++ b/FileFormat.Slides/FileFormat.Slides.csproj @@ -5,9 +5,14 @@ True + +