1313using Openize . Slides . Common ;
1414using System . Dynamic ;
1515using P15 = DocumentFormat . OpenXml . Office2013 . PowerPoint ;
16+ using DocumentFormat . OpenXml . Drawing . Charts ;
1617
1718namespace 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