blob: 78609e17158403a09df1d1b068cebd66df8e0597 [file] [log] [blame]
/*
* You may amend and distribute as you like, but don't remove this header!
*
* EPPlus provides server-side generation of Excel 2007 spreadsheets.
* See http://www.codeplex.com/EPPlus for details.
*
* All rights reserved.
*
* EPPlus is an Open Source project provided under the
* GNU General Public License (GPL) as published by the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* The GNU General Public License can be viewed at http://www.opensource.org/licenses/gpl-license.php
* If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
*
* The code for this project may be used and redistributed by any means PROVIDING it is
* not sold for profit without the author's written consent, and providing that this notice
* and the author's name and all copyright notices remain intact.
*
* All code and executables are provided "as is" with no warranty either express or implied.
* The author accepts no liability for any damage or loss of business that this product may cause.
*
* Code change notes:
*
* Author Change Date
* ******************************************************************************
* Jan Källman Added 2012-05-01
*******************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using OfficeOpenXml;
using System.Security.Cryptography.X509Certificates;
using System.Drawing;
using OfficeOpenXml.Style;
using OfficeOpenXml.Drawing.Chart;
namespace EPPlusSamples
{
class Sample15
{
public static void VBASample(DirectoryInfo outputDir)
{
//Create a macro-enabled workbook from scratch.
VBASample1(outputDir);
//Open Sample 1 and add code to change the chart to a bubble chart.
VBASample2(outputDir);
//Simple battleships game from scratch.
VBASample3(outputDir);
}
private static void VBASample1(DirectoryInfo outputDir)
{
ExcelPackage pck = new ExcelPackage();
//Add a worksheet.
var ws=pck.Workbook.Worksheets.Add("VBA Sample");
ws.Drawings.AddShape("VBASampleRect", eShapeStyle.RoundRect);
//Create a vba project
pck.Workbook.CreateVBAProject();
//Now add some code to update the text of the shape...
var sb = new StringBuilder();
sb.AppendLine("Private Sub Workbook_Open()");
sb.AppendLine(" [VBA Sample].Shapes(\"VBASampleRect\").TextEffect.Text = \"This text is set from VBA!\"");
sb.AppendLine("End Sub");
pck.Workbook.CodeModule.Code = sb.ToString();
//And Save as xlsm
pck.SaveAs(new FileInfo(outputDir.FullName + @"\sample15-1.xlsm"));
}
private static void VBASample2(DirectoryInfo outputDir)
{
//Open Sample 1 again
ExcelPackage pck = new ExcelPackage(new FileInfo(outputDir.FullName + @"\sample1.xlsx"));
//Create a vba project
pck.Workbook.CreateVBAProject();
//Now add some code that creates a bubble chart...
var sb = new StringBuilder();
sb.AppendLine("Public Sub CreateBubbleChart()");
sb.AppendLine("Dim co As ChartObject");
sb.AppendLine("Set co = Inventory.ChartObjects.Add(10, 100, 400, 200)");
sb.AppendLine("co.Chart.SetSourceData Source:=Range(\"'Inventory'!$B$1:$E$5\")");
sb.AppendLine("co.Chart.ChartType = xlBubble3DEffect 'Add a bubblechart");
sb.AppendLine("End Sub");
//Create a new module and set the code
var module = pck.Workbook.VbaProject.Modules.AddModule("EPPlusGeneratedCode");
module.Code = sb.ToString();
//Call the newly created sub from the workbook open event
pck.Workbook.CodeModule.Code = "Private Sub Workbook_Open()\r\nCreateBubbleChart\r\nEnd Sub";
//Optionally, Sign the code with your company certificate.
/*
X509Store store = new X509Store(StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
pck.Workbook.VbaProject.Signature.Certificate = store.Certificates[0];
*/
//And Save as xlsm
pck.SaveAs(new FileInfo(outputDir.FullName + @"\sample15-2.xlsm"));
}
private static void VBASample3(DirectoryInfo outputDir)
{
//Now, lets do something a little bit more fun.
//We are going to create a simple battleships game from scratch.
ExcelPackage pck = new ExcelPackage();
//Add a worksheet.
var ws = pck.Workbook.Worksheets.Add("Battleship");
ws.View.ShowGridLines = false;
ws.View.ShowHeaders = false;
ws.DefaultColWidth = 3;
ws.DefaultRowHeight = 15;
int gridSize=10;
//Create the boards
var board1 = ws.Cells[2, 2, 2 + gridSize - 1, 2 + gridSize - 1];
var board2 = ws.Cells[2, 4+gridSize-1, 2 + gridSize-1, 4 + (gridSize-1)*2];
CreateBoard(board1);
CreateBoard(board2);
ws.Select("B2");
ws.Protection.IsProtected = true;
ws.Protection.AllowSelectLockedCells = true;
//Create the VBA Project
pck.Workbook.CreateVBAProject();
//Password protect your code
pck.Workbook.VbaProject.Protection.SetPassword("EPPlus");
//Add all the code from the textfiles in the Vba-Code sub-folder.
pck.Workbook.CodeModule.Code = File.ReadAllText("..\\..\\VBA-Code\\ThisWorkbook.txt");
//Add the sheet code
ws.CodeModule.Code = File.ReadAllText("..\\..\\VBA-Code\\BattleshipSheet.txt");
var m1=pck.Workbook.VbaProject.Modules.AddModule("Code");
string code = File.ReadAllText("..\\..\\VBA-Code\\CodeModule.txt");
//Insert your ships on the right board. you can changes these, but don't cheat ;)
var ships = new string[]{
"N3:N7",
"P2:S2",
"V9:V11",
"O10:Q10",
"R11:S11"};
//Note: For security reasons you should never mix external data and code(to avoid code injections!), especially not on a webserver.
//If you deside to do that anyway, be very careful with the validation of the data.
//Be extra carefull if you sign the code.
//Read more here http://en.wikipedia.org/wiki/Code_injection
code = string.Format(code, ships[0],ships[1],ships[2],ships[3],ships[4], board1.Address, board2.Address); //Ships are injected into the constants in the module
m1.Code = code;
//Ships are displayed with a black background
string shipsaddress = string.Join(",", ships);
ws.Cells[shipsaddress].Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
ws.Cells[shipsaddress].Style.Fill.BackgroundColor.SetColor(Color.Black);
var m2 = pck.Workbook.VbaProject.Modules.AddModule("ComputerPlay");
m2.Code = File.ReadAllText("..\\..\\VBA-Code\\ComputerPlayModule.txt");
var c1 = pck.Workbook.VbaProject.Modules.AddClass("Ship",false);
c1.Code = File.ReadAllText("..\\..\\VBA-Code\\ShipClass.txt");
//Add the info text shape.
var tb = ws.Drawings.AddShape("txtInfo", eShapeStyle.Rect);
tb.SetPosition(1, 0, 27, 0);
tb.Fill.Color = Color.LightSlateGray;
var rt1 = tb.RichText.Add("Battleships");
rt1.Bold = true;
tb.RichText.Add("\r\nDouble-click on the left board to make your move. Find and sink all ships to win!");
//Set the headers.
ws.SetValue("B1", "Computer Grid");
ws.SetValue("M1", "Your Grid");
ws.Row(1).Style.Font.Size = 18;
AddChart(ws.Cells["B13"], "chtHitPercent", "Player");
AddChart(ws.Cells["M13"], "chtComputerHitPercent", "Computer");
ws.Names.Add("LogStart", ws.Cells["B24"]);
ws.Cells["B24:X224"].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.Black);
ws.Cells["B25:X224"].Style.Font.Name = "Consolas";
ws.SetValue("B24", "Log");
ws.Cells["B24"].Style.Font.Bold = true;
ws.Cells["B24:X24"].Style.Border.BorderAround(ExcelBorderStyle.Thin, Color.Black);
var cf=ws.Cells["B25:B224"].ConditionalFormatting.AddContainsText();
cf.Text = "hit";
cf.Style.Font.Color.Color = Color.Red;
//If you have a valid certificate for code signing you can use this code to set it.
///*** Try to find a cert valid for signing... ***/
//X509Store store = new X509Store(StoreLocation.CurrentUser);
//store.Open(OpenFlags.ReadOnly);
//foreach (var cert in store.Certificates)
//{
// if (cert.HasPrivateKey && cert.NotBefore <= DateTime.Today && cert.NotAfter >= DateTime.Today)
// {
// pck.Workbook.VbaProject.Signature.Certificate = cert;
// break;
// }
//}
pck.SaveAs(new FileInfo(outputDir.FullName + @"\sample15-3.xlsm"));
}
private static void AddChart(ExcelRange rng,string name, string prefix)
{
var chrt = (ExcelPieChart)rng.Worksheet.Drawings.AddChart(name, eChartType.Pie);
chrt.SetPosition(rng.Start.Row-1, 0, rng.Start.Column-1, 0);
chrt.To.Row = rng.Start.Row+9;
chrt.To.Column = rng.Start.Column + 9;
chrt.Style = eChartStyle.Style18;
chrt.DataLabel.ShowPercent = true;
var serie = chrt.Series.Add(rng.Offset(2, 2, 1, 2), rng.Offset(1, 2, 1, 2));
serie.Header = "Hits";
chrt.Title.Text = "Hit ratio";
var n1 = rng.Worksheet.Names.Add(prefix + "Misses", rng.Offset(2, 2));
n1.Value = 0;
var n2 = rng.Worksheet.Names.Add(prefix + "Hits", rng.Offset(2, 3));
n2.Value = 0;
rng.Offset(1, 2).Value = "Misses";
rng.Offset(1, 3).Value = "Hits";
}
private static void CreateBoard(ExcelRange rng)
{
//Create a gradiant background with one dark and one light blue color
rng.Style.Fill.Gradient.Color1.SetColor(Color.FromArgb(0x80, 0x80, 0XFF));
rng.Style.Fill.Gradient.Color2.SetColor(Color.FromArgb(0x20, 0x20, 0XFF));
rng.Style.Fill.Gradient.Type = ExcelFillGradientType.None;
for (int col = 0; col <= rng.End.Column - rng.Start.Column; col++)
{
for (int row = 0; row <= rng.End.Row - rng.Start.Row; row++)
{
if (col % 4 == 0)
{
rng.Offset(row, col, 1, 1).Style.Fill.Gradient.Degree = 45;
}
if (col % 4 == 1)
{
rng.Offset(row, col, 1, 1).Style.Fill.Gradient.Degree = 70;
}
if (col % 4 == 2)
{
rng.Offset(row, col, 1, 1).Style.Fill.Gradient.Degree = 110;
}
else
{
rng.Offset(row, col, 1, 1).Style.Fill.Gradient.Degree = 135;
}
}
}
//Set the inner cell border to thin, light gray
rng.Style.Border.Top.Style = ExcelBorderStyle.Thin;
rng.Style.Border.Top.Color.SetColor(Color.Gray);
rng.Style.Border.Right.Style = ExcelBorderStyle.Thin;
rng.Style.Border.Right.Color.SetColor(Color.Gray);
rng.Style.Border.Left.Style = ExcelBorderStyle.Thin;
rng.Style.Border.Left.Color.SetColor(Color.Gray);
rng.Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
rng.Style.Border.Bottom.Color.SetColor(Color.Gray);
//Solid black border around the board.
rng.Style.Border.BorderAround(ExcelBorderStyle.Medium, Color.Black);
}
}
}