Skip to content

Commit 46c5dcd

Browse files
Merge pull request #13 from openize-com/muhammadumar-patch
Clone Within & Copy Across Presentations
2 parents eb19084 + c2ddfc4 commit 46c5dcd

File tree

4 files changed

+349
-254
lines changed

4 files changed

+349
-254
lines changed

PowerPoint/Openize.Slides.Facade/PresentationDocumentFacade.cs

Lines changed: 136 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@
1313
using Openize.Slides.Common;
1414
using System.Dynamic;
1515
using P15 = DocumentFormat.OpenXml.Office2013.PowerPoint;
16+
using DocumentFormat.OpenXml.Drawing.Charts;
1617

1718
namespace Openize.Slides.Facade
1819
{
1920
public class PresentationDocumentFacade : IDisposable
2021
{
21-
private static PresentationDocumentFacade _instance = null;
22+
private static readonly Dictionary<string, PresentationDocumentFacade> _instances = new Dictionary<string, PresentationDocumentFacade>();
23+
private static PresentationDocumentFacade _lastInstance;
24+
private static string _FilePath = null;
2225
private static MemoryStream _MemoryStream = null;
2326
private PKG.PresentationDocument _PresentationDocument = null;
2427
private bool disposedValue;
@@ -31,6 +34,8 @@ public class PresentationDocumentFacade : IDisposable
3134
private bool isNewPresentation = false;
3235
private List<SlideFacade> _SlideFacades = null;
3336
private CommentAuthorsPart _CommentAuthorPart;
37+
private Int32Value _slideWidth;
38+
private Int32Value _slideHeight;
3439

3540

3641

@@ -43,6 +48,9 @@ public class PresentationDocumentFacade : IDisposable
4348
public List<SlideFacade> SlideFacades { get => _SlideFacades; set => _SlideFacades = value; }
4449
public bool IsNewPresentation { get => isNewPresentation; set => isNewPresentation = value; }
4550
public CommentAuthorsPart CommentAuthorPart { get => _CommentAuthorPart; set => _CommentAuthorPart = value; }
51+
public Int32Value SlideWidth { get => _slideWidth; set => _slideWidth = value; }
52+
public Int32Value SlideHeight { get => _slideHeight; set => _slideHeight = value; }
53+
public static string FilePath { get => _FilePath; set => _FilePath = value; }
4654

4755
public PKG.PresentationPart GetPresentationPart ()
4856
{
@@ -55,6 +63,7 @@ private PresentationDocumentFacade (String FilePath, bool isNewFile)
5563
{
5664
if (isNewFile)
5765
{
66+
_FilePath = FilePath;
5867
IsNewPresentation = isNewFile;
5968
SlideMasterIdList slideMasterIdList = new SlideMasterIdList(new SlideMasterId() { Id = (UInt32Value)2147483648U, RelationshipId = "rId1" });
6069

@@ -70,6 +79,7 @@ private PresentationDocumentFacade (String FilePath, bool isNewFile)
7079
}
7180
else
7281
{
82+
_FilePath = FilePath;
7383
_PresentationDocument = PKG.PresentationDocument.Open(FilePath, true);
7484
_PresentationPart = _PresentationDocument.PresentationPart;
7585
_PresentationSlideParts = GetSlideParts(_PresentationPart);
@@ -167,47 +177,51 @@ public void RemoveCommentAuthor(int id)
167177
public static PresentationDocumentFacade Create (String FilePath)
168178
{
169179

170-
if (_instance == null)
180+
if (!_instances.ContainsKey(FilePath))
171181
{
172-
_instance = new PresentationDocumentFacade(FilePath, true);
173-
return _instance;
182+
_instances[FilePath] = new PresentationDocumentFacade(FilePath, true);
174183
}
175-
return _instance;
184+
_lastInstance = _instances[FilePath];
185+
return _instances[FilePath];
186+
}
187+
188+
public static PresentationDocumentFacade Create(String FilePath,int SlideWidth, int SlideHeight)
189+
{
190+
191+
if (!_instances.ContainsKey(FilePath))
192+
{
193+
_instances[FilePath] = new PresentationDocumentFacade(FilePath, true);
194+
}
195+
_lastInstance = _instances[FilePath];
196+
return _instances[FilePath];
176197
}
177198
public static PresentationDocumentFacade Open (string FilePath)
178199
{
179-
if (_instance == null)
200+
if (!_instances.ContainsKey(FilePath))
180201
{
181-
try
182-
{
183-
_MemoryStream = new MemoryStream();
184-
using (FileStream fs = new FileStream(FilePath, FileMode.Open))
185-
{
186-
fs.CopyTo(_MemoryStream);
187-
}
188-
}
189-
catch (Exception ex)
190-
{
191-
string errorMessage = Common.OpenizeException.ConstructMessage(ex, "Loading Document");
192-
throw new Common.OpenizeException(errorMessage, ex);
193-
}
194-
195-
_instance = new PresentationDocumentFacade(FilePath, false);
196-
return _instance;
202+
_instances[FilePath] = new PresentationDocumentFacade(FilePath, false);
197203
}
198-
return _instance;
204+
_lastInstance = _instances[FilePath];
205+
return _instances[FilePath];
199206
}
200207

201-
public static PresentationDocumentFacade getInstance ()
208+
public static PresentationDocumentFacade getInstance(string FilePath = null)
202209
{
203-
return _instance;
210+
return FilePath != null ? _instances.GetValueOrDefault(FilePath) : _lastInstance;
204211
}
205212

206213
private void CreatePresentationParts ()
207214
{
215+
// Default values in EMUs
216+
const int defaultWidth = 9144000; // 10 inches
217+
const int defaultHeight = 6858000; // 7.5 inches
218+
219+
// Use the class-level values if set, otherwise use defaults
220+
Int32Value slideWidth = _slideWidth ?? defaultWidth;
221+
Int32Value slideHeight = _slideHeight ?? defaultHeight;
208222

209223
//SlideIdList slideIdList1 = new SlideIdList(new SlideId() { Id = (UInt32Value)256U, RelationshipId = "rId2" });
210-
SlideSize slideSize1 = new SlideSize() { Cx = 9144000, Cy = 6858000, Type = SlideSizeValues.Custom };
224+
SlideSize slideSize1 = new SlideSize() { Cx = slideWidth, Cy = slideHeight, Type = SlideSizeValues.Custom };
211225
NotesSize notesSize1 = new NotesSize() { Cx = 6858000, Cy = 9144000 };
212226
DefaultTextStyle defaultTextStyle1 = new DefaultTextStyle();
213227

@@ -537,6 +551,15 @@ public void AppendSlide (SlideFacade slideFacade)
537551
slideFacade.PresentationSlide.Save(slideFacade.SlidePart);
538552
_PresentationSlideParts.Add(slideFacade.SlidePart);
539553

554+
555+
}
556+
public void Clone(SlideFacade slideFacade)
557+
{
558+
559+
slideFacade.PresentationSlide.Save(slideFacade.SlidePart);
560+
_PresentationSlideParts.Add(slideFacade.SlidePart);
561+
562+
540563
}
541564
public void InsertSlide (int index, SlideFacade slideFacade)
542565
{
@@ -563,50 +586,111 @@ public void MoveSlideToIndex (int currentIndex, int newIndex)
563586
}
564587
}
565588

566-
/// <summary>
567-
/// This method releases unmanaged resources.
568-
/// </summary>
569-
/// <param name="disposing">A boolean value.</param>
570-
protected virtual void Dispose (bool disposing)
589+
public void CopySlide(SlideFacade slideFacade)
571590
{
572-
if (!disposedValue)
591+
// Open source and target presentations
592+
593+
var targetPresentation = this;
594+
595+
// Get the source slide part
596+
SlidePart sourceSlidePart = slideFacade.SlidePart;
597+
598+
// Get the target presentation part
599+
PresentationPart targetPresentationPart = getInstance(FilePath).GetPresentationPart();
600+
SlideIdList targetSlideIdList = targetPresentationPart.Presentation.SlideIdList;
601+
uint newSlideId = _SlideIdList.Elements<SlideId>().Max(s => s.Id.Value) + 1;
602+
603+
604+
SlidePart newSlidePart = CopySlidePart(sourceSlidePart, targetPresentationPart);
605+
606+
SlideId newSlideIdElement = new SlideId()
573607
{
574-
if (disposing)
608+
Id = newSlideId,
609+
RelationshipId = _PresentationPart.GetIdOfPart(newSlidePart)
610+
};
611+
_SlideIdList.Append(newSlideIdElement);
612+
613+
614+
}
615+
public static SlidePart CopySlidePart(SlidePart sourceSlidePart, PresentationPart destinationPresentationPart)
616+
{
617+
SlidePart newSlidePart = destinationPresentationPart.AddNewPart<SlidePart>();
618+
619+
// Clone slide but prevent locking issues
620+
newSlidePart.Slide = (P.Slide)sourceSlidePart.Slide.CloneNode(true);
621+
622+
// Handle Slide Layout properly
623+
if (sourceSlidePart.SlideLayoutPart != null)
624+
{
625+
SlideLayoutPart destLayoutPart = destinationPresentationPart.SlideMasterParts
626+
.SelectMany(master => master.SlideLayoutParts)
627+
.FirstOrDefault(layout => layout.Uri == sourceSlidePart.SlideLayoutPart.Uri);
628+
629+
if (destLayoutPart != null)
575630
{
576-
// TODO: dispose managed state (managed objects)
577-
_PresentationDocument.Dispose();
578-
_MemoryStream.Dispose();
631+
newSlidePart.AddPart(destLayoutPart);
579632
}
633+
}
580634

635+
newSlidePart.Slide.Save();
636+
return newSlidePart;
637+
}
581638

582-
disposedValue = true;
583-
}
639+
640+
public static void Save(string FilePath = null)
641+
{
642+
var instance = getInstance(FilePath);
643+
instance?.Save();
584644
}
585-
public void Save ()
645+
646+
private void RemoveParts()
586647
{
587-
if (IsNewPresentation)
648+
_PresentationDocument = null;
649+
_PresentationPart = null;
650+
_PresentationSlideParts = null;
651+
_CommentAuthorPart = null;
652+
_PresentationSlideLayoutParts = null;
653+
_SlideIdList = null;
654+
_PresentationSlideMasterPart = null;
655+
656+
}
657+
public void Close(string FilePath = null)
658+
{
659+
if (FilePath == null)
588660
{
589-
CreatePresentationParts();
661+
FilePath = _instances.FirstOrDefault(kvp => kvp.Value == _lastInstance).Key;
590662
}
591-
else
663+
if (FilePath != null && _instances.ContainsKey(FilePath))
592664
{
593-
_PresentationDocument.Save();
665+
_instances[FilePath].Save(); // Ensure saving before closing
666+
_instances[FilePath].Dispose();
667+
_instances.Remove(FilePath);
668+
if (_lastInstance == _instances.GetValueOrDefault(FilePath))
669+
{
670+
_lastInstance = null;
671+
}
594672
}
595-
_PresentationDocument.Dispose();
673+
}
596674

675+
public void Save()
676+
{
677+
_PresentationDocument?.PresentationPart?.Presentation.Save();
678+
_PresentationDocument?.Save();
597679
}
598-
public void Save (String FilePath)
680+
protected virtual void Dispose(bool disposing)
599681
{
600-
_PresentationDocument.Save();
601-
682+
if (!disposedValue)
683+
{
684+
if (disposing)
685+
{
686+
_PresentationDocument?.Dispose();
687+
}
688+
disposedValue = true;
689+
}
602690
}
603691

604-
/// <summary>
605-
/// This method releases unmanaged resources.
606-
/// </summary>
607-
public void Dispose ()
692+
public void Dispose()
608693
{
609-
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
610694
Dispose(disposing: true);
611695
GC.SuppressFinalize(this);
612696
}

0 commit comments

Comments
 (0)