diff --git a/src/EPPlus/Constants/ContentTypes.cs b/src/EPPlus/Constants/ContentTypes.cs
index eb98ae61af..ab6abd6c55 100644
--- a/src/EPPlus/Constants/ContentTypes.cs
+++ b/src/EPPlus/Constants/ContentTypes.cs
@@ -19,7 +19,11 @@ internal class ContentTypes
internal const string contentTypeWorkbookMacroEnabled = "application/vnd.ms-excel.sheet.macroEnabled.main+xml";
internal const string contentTypeSharedString = @"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml";
internal const string contentTypeMetaData = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml";
-
+
+ //Template
+ internal const string contentTypeTemplateDefault = @"application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml";
+ internal const string contentTypeTemplateMacroEnabled = "application/vnd.ms-excel.template.macroEnabled.main+xml";
+
//Theme
internal const string contentTypeThemeOverride = "application/vnd.openxmlformats-officedocument.themeOverride+xml";
internal const string contentTypeTheme = @"application/vnd.openxmlformats-officedocument.theme+xml";
diff --git a/src/EPPlus/Enums.cs b/src/EPPlus/Enums.cs
index c596fa3de1..d905205b01 100644
--- a/src/EPPlus/Enums.cs
+++ b/src/EPPlus/Enums.cs
@@ -252,4 +252,21 @@ public enum eWorkbookVisibility
///
Visible
}
+ ///
+ /// Specifies the document format to use when saving a package.
+ ///
+ public enum eDocumentFormat
+ {
+ ///
+ /// A standard Excel workbook (.xlsx, or .xlsm if the workbook contains a VBA project).
+ /// This is the default format.
+ ///
+ Workbook,
+ ///
+ /// An Excel template (.xltx, or .xltm if the workbook contains a VBA project).
+ /// When opened in Excel, a template creates a new workbook based on its contents
+ /// rather than opening the template file itself for editing.
+ ///
+ Template
+ }
}
diff --git a/src/EPPlus/ExcelPackage.cs b/src/EPPlus/ExcelPackage.cs
index 6aec485c67..34610482b7 100644
--- a/src/EPPlus/ExcelPackage.cs
+++ b/src/EPPlus/ExcelPackage.cs
@@ -28,6 +28,8 @@ Date Author Change
#if (!NET35)
using OfficeOpenXml.SensitivityLabels;
+using System.Linq;
+
#endif
#if (Core)
@@ -881,39 +883,6 @@ internal void SavePart(Uri uri, XmlDocument xmlDoc)
var xmlWriter = XmlWriter.Create(stream, xmlSettings);
xmlDoc.Save(xmlWriter);
}
- ///
- /// Saves the XmlDocument into the package at the specified Uri.
- ///
- /// The Uri of the component
- /// The XmlDocument to save
- internal void SaveWorkbook(Uri uri, XmlDocument xmlDoc)
- {
- Packaging.ZipPackagePart part = _zipPackage.GetPart(uri);
- if (Workbook.VbaProject == null)
- {
- if (part.ContentType != ContentTypes.contentTypeWorkbookDefault)
- {
- part = _zipPackage.CreatePart(uri, ContentTypes.contentTypeWorkbookDefault, Compression);
- }
- }
- else
- {
- if (part.ContentType != ContentTypes.contentTypeWorkbookMacroEnabled)
- {
- var rels = part.GetRelationships();
- _zipPackage.DeletePart(uri);
- part = ZipPackage.CreatePart(uri, ContentTypes.contentTypeWorkbookMacroEnabled);
- foreach (ZipPackageRelationship rel in rels)
- {
- ZipPackage.DeleteRelationship(rel.Id);
- part.CreateRelationship(rel.TargetUri, rel.TargetMode, rel.RelationshipType);
- }
- }
- }
- var stream = part.GetStream(FileMode.Create, FileAccess.Write);
- xmlDoc.Save(stream);
- }
-
#endregion
#region Dispose
@@ -1210,6 +1179,49 @@ public CompressionLevel Compression
ZipPackage.Compression = value;
}
}
+
+ private eDocumentFormat? _format = null;
+
+ ///
+ /// Gets or sets the file format used when the package is saved.
+ ///
+ /// When a package is loaded, this property is derived from the content type of the
+ /// workbook part, so a file opened as a template (.xltx/.xltm) reports
+ /// .
+ /// .
+ ///
+ ///
+ /// Setting this property overrides the derived value, allowing a loaded template to be
+ /// saved as a workbook or vice versa. Whether the workbook is saved as a macro-enabled
+ /// file is determined automatically by the presence of a VBA project.
+ ///
+ ///
+ public eDocumentFormat DocumentFormat
+ {
+ get
+ {
+ if (_format == null)
+ {
+ _format = ResolveFormatFromPackage();
+ }
+ return _format.Value;
+ }
+ set
+ {
+ _format = value;
+ }
+ }
+
+ private eDocumentFormat ResolveFormatFromPackage()
+ {
+ if (_zipPackage == null) return eDocumentFormat.Workbook;
+
+ var wbPart = _zipPackage.GetPartByContentType(ContentTypes.contentTypeTemplateDefault)
+ ?? _zipPackage.GetPartByContentType(ContentTypes.contentTypeTemplateMacroEnabled);
+
+ return wbPart != null ? eDocumentFormat.Template : eDocumentFormat.Workbook;
+ }
+
CompatibilitySettings _compatibility = null;
///
/// Compatibility settings for older versions of EPPlus.
diff --git a/src/EPPlus/ExcelWorkbook.cs b/src/EPPlus/ExcelWorkbook.cs
index 282f47ff65..07730063c1 100644
--- a/src/EPPlus/ExcelWorkbook.cs
+++ b/src/EPPlus/ExcelWorkbook.cs
@@ -1559,21 +1559,15 @@ internal void Save() // Workbook Save
SetXmlNodeBool("d:calcPr/@fullPrecision", FullPrecision, false);
if(_workbookCreatedInEPPlus == false) EnsureCalculationFeatures(); //Ensure that the calculation features are included in the file to make sure that new functions are supported.
-
- if (_vba == null && !_package.ZipPackage.PartExists(new Uri(ExcelVbaProject.PartUri, UriKind.Relative)))
+
+ bool isMacroEnabled = !(_vba == null &&
+ !_package.ZipPackage.PartExists(new Uri(ExcelVbaProject.PartUri, UriKind.Relative)));
+
+ var targetContentType = GetWorkbookContentType(_package.DocumentFormat, isMacroEnabled);
+
+ if (Part.ContentType != targetContentType)
{
- if (Part.ContentType != ContentTypes.contentTypeWorkbookDefault &&
- Part.ContentType != ContentTypes.contentTypeWorkbookMacroEnabled)
- {
- Part.ContentType = ContentTypes.contentTypeWorkbookDefault;
- }
- }
- else
- {
- if (Part.ContentType != ContentTypes.contentTypeWorkbookMacroEnabled)
- {
- Part.ContentType = ContentTypes.contentTypeWorkbookMacroEnabled;
- }
+ Part.ContentType = targetContentType;
}
UpdateDefinedNamesXml();
@@ -1705,6 +1699,22 @@ internal void Save() // Workbook Save
}
}
+ internal string GetWorkbookContentType(eDocumentFormat format, bool isMacroEnabled)
+ {
+ if (format == eDocumentFormat.Template)
+ {
+ return isMacroEnabled
+ ? ContentTypes.contentTypeTemplateMacroEnabled
+ : ContentTypes.contentTypeTemplateDefault;
+ }
+ else
+ {
+ return isMacroEnabled
+ ? ContentTypes.contentTypeWorkbookMacroEnabled
+ : ContentTypes.contentTypeWorkbookDefault;
+ }
+ }
+
private void HandleLicense()
{
switch (ExcelPackage.License.LicenseType)
diff --git a/src/EPPlus/Packaging/ZipPackage.cs b/src/EPPlus/Packaging/ZipPackage.cs
index 3e2fa34c4f..6cdcf66a36 100644
--- a/src/EPPlus/Packaging/ZipPackage.cs
+++ b/src/EPPlus/Packaging/ZipPackage.cs
@@ -534,7 +534,9 @@ internal void Save(Stream stream)
part.ContentType == ContentTypes.contentTypeRichDataValueStructure ||
part.ContentType == ContentTypes.contentTypeRichDataValue ||
part.ContentType == ContentTypes.contentTypeWorkbookDefault ||
- part.ContentType == ContentTypes.contentTypeWorkbookMacroEnabled)
+ part.ContentType == ContentTypes.contentTypeWorkbookMacroEnabled ||
+ part.ContentType == ContentTypes.contentTypeTemplateDefault || // nytt
+ part.ContentType == ContentTypes.contentTypeTemplateMacroEnabled) // nytt)
{
saveAfterParts.Add(part);
}
diff --git a/src/EPPlusTest/ExcelPackageTests.cs b/src/EPPlusTest/ExcelPackageTests.cs
index 2d26ba33cb..627455cf77 100644
--- a/src/EPPlusTest/ExcelPackageTests.cs
+++ b/src/EPPlusTest/ExcelPackageTests.cs
@@ -26,6 +26,8 @@ Date Author Change
*******************************************************************************
01/27/2020 EPPlus Software AB Initial release EPPlus 5
*******************************************************************************/
+using EPPlusTest.Drawing.Chart.Styling;
+using FakeItEasy.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OfficeOpenXml;
using System;
@@ -37,7 +39,7 @@ Date Author Change
namespace EPPlusTest
{
[TestClass]
- public class ExcelPackageTests
+ public class ExcelPackageTests : TestBase
{
[TestMethod, Ignore]
public void ConstructorWithStringPath()
@@ -87,5 +89,54 @@ public void ShouldEncryptAndDecryptPackage(EncryptionAlgorithm algorithm)
}
}
}
+
+ [TestMethod]
+ public void SaveAsTemplate_Debug()
+ {
+ using (var package = new ExcelPackage())
+ {
+ var ws = package.Workbook.Worksheets.Add("Sheet1");
+ ws.Cells["A1"].Value = "Test";
+
+ package.DocumentFormat = eDocumentFormat.Template;
+ SaveAndCleanup(package);
+ }
+ }
+
+ [TestMethod]
+ public void SaveAsTemplate_WithVba_SetsTemplateMacroEnabledContentType()
+ {
+ using (var package = new ExcelPackage())
+ {
+ var ws = package.Workbook.Worksheets.Add("Sheet1");
+ ws.Cells["A1"].Value = "Test";
+
+ package.Workbook.CreateVBAProject();
+ package.DocumentFormat = eDocumentFormat.Template;
+ SaveAndCleanup(package);
+ }
+ }
+
+ [TestMethod]
+ public void ReadAndConvertToTemplate()
+ {
+ using (var package = OpenTemplatePackage("ExcelTemplateTest.xltx"))
+ {
+ Assert.AreEqual(eDocumentFormat.Template, package.DocumentFormat);
+ package.DocumentFormat = eDocumentFormat.Workbook;
+ SaveAndCleanup(package);
+ }
+ }
+
+ [TestMethod]
+ public void ReadAndConvertWorkbookToTemplate()
+ {
+ using (var package = OpenTemplatePackage("ExcelTemplateTest.xlsx"))
+ {
+ Assert.AreEqual(eDocumentFormat.Workbook, package.DocumentFormat);
+ package.DocumentFormat = eDocumentFormat.Template;
+ SaveAndCleanup(package);
+ }
+ }
}
}