Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/EPPlus/Constants/ContentTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
17 changes: 17 additions & 0 deletions src/EPPlus/Enums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -252,4 +252,21 @@ public enum eWorkbookVisibility
/// </summary>
Visible
}
/// <summary>
/// Specifies the document format to use when saving a package.
/// </summary>
public enum eDocumentFormat
{
/// <summary>
/// A standard Excel workbook (.xlsx, or .xlsm if the workbook contains a VBA project).
/// This is the default format.
/// </summary>
Workbook,
/// <summary>
/// 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.
/// </summary>
Template
}
}
78 changes: 45 additions & 33 deletions src/EPPlus/ExcelPackage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Date Author Change

#if (!NET35)
using OfficeOpenXml.SensitivityLabels;
using System.Linq;

#endif

#if (Core)
Expand Down Expand Up @@ -881,39 +883,6 @@ internal void SavePart(Uri uri, XmlDocument xmlDoc)
var xmlWriter = XmlWriter.Create(stream, xmlSettings);
xmlDoc.Save(xmlWriter);
}
/// <summary>
/// Saves the XmlDocument into the package at the specified Uri.
/// </summary>
/// <param name="uri">The Uri of the component</param>
/// <param name="xmlDoc">The XmlDocument to save</param>
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
Expand Down Expand Up @@ -1210,6 +1179,49 @@ public CompressionLevel Compression
ZipPackage.Compression = value;
}
}

private eDocumentFormat? _format = null;

/// <summary>
/// Gets or sets the file format used when the package is saved.
/// <para>
/// 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
/// <see cref="OfficeOpenXml.eDocumentFormat.Template"/>.
/// <see cref="OfficeOpenXml.eDocumentFormat.Workbook"/>.
/// </para>
/// <para>
/// 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.
/// </para>
/// </summary>
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;
/// <summary>
/// Compatibility settings for older versions of EPPlus.
Expand Down
38 changes: 24 additions & 14 deletions src/EPPlus/ExcelWorkbook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion src/EPPlus/Packaging/ZipPackage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
53 changes: 52 additions & 1 deletion src/EPPlusTest/ExcelPackageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -37,7 +39,7 @@ Date Author Change
namespace EPPlusTest
{
[TestClass]
public class ExcelPackageTests
public class ExcelPackageTests : TestBase
{
[TestMethod, Ignore]
public void ConstructorWithStringPath()
Expand Down Expand Up @@ -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);
}
}
}
}
Loading