632 lines
24 KiB
C#
632 lines
24 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Web.UI;
|
|
using System.Web.UI.WebControls.WebParts;
|
|
using System.Web.UI.WebControls;
|
|
using Microsoft.SharePoint;
|
|
|
|
namespace FusionCharts.WebParts
|
|
{
|
|
[Guid("3dd2d2e7-b5a3-4165-b3d1-421774fafa0f")]
|
|
public class ChartFromList : WebPart, ITrace
|
|
{
|
|
#region PrivateMembers
|
|
|
|
private bool _error = false;
|
|
private string _chartId = null; // null by default (important)
|
|
private ChartTypeRestricted _chartType;
|
|
private int _chartHeight = Utils.DefaultHeight; // default height
|
|
private int _chartWidth = Utils.DefaultWidth; // default width
|
|
private string _listName = ""; // The name of the list to use
|
|
private string _viewName = ""; // The name of the view to use
|
|
private string _chartTitle = ""; // The title of the chart
|
|
private string _xValue = ""; // The name of the column of the list to use as horizontal value
|
|
private string _xTitle = ""; // The title of hortizontal axis
|
|
private string _yValue = ""; // The name of the column of the list to use as vertical value
|
|
private string _yTitle = ""; // The title of vertical axis
|
|
private int _yDecimalPrecision = 0; // number of decimal places for y axis
|
|
private bool _yNumberScale = false; // y axis scaling option
|
|
private string _yNumberPrefix = ""; // optional prefix for y axis(e.g., "$")
|
|
private string _colors = null; // null by default (important). Colors that will be used
|
|
private bool _excelExport = false; // display/hide the custom button to export chart to excel
|
|
private bool _xmlExport = false; // display/hide the custom button to export chart to xml file
|
|
private GroupAction _action;
|
|
private string _myBuildVersion = "ChartFromList: 2013-02-13-1200";
|
|
private string _myTrace = "";
|
|
|
|
#endregion
|
|
|
|
#region CustomProperties
|
|
|
|
/// <summary>
|
|
/// The title of the chart
|
|
/// </summary>
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDisplayName("Chart Title")]
|
|
[WebDescription("The title of the chart (caption).")]
|
|
public string ChartTitle
|
|
{
|
|
get { return _chartTitle; }
|
|
set { _chartTitle = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The type of chart to display
|
|
/// </summary>
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDisplayName("Chart Type")]
|
|
[WebDescription("The type of chart that will be displayed")]
|
|
public ChartTypeRestricted ChartType
|
|
{
|
|
get { return _chartType; }
|
|
set { _chartType = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The height of the chart that will be displayed
|
|
/// </summary>
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDisplayName("Chart Height")]
|
|
[WebDescription("The height of the chart to display")]
|
|
public int ChartHeight
|
|
{
|
|
get { return _chartHeight; }
|
|
set { _chartHeight = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The width of the chart that will be displayed
|
|
/// </summary>
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDisplayName("Chart Width")]
|
|
[WebDescription("The width of the chart to display")]
|
|
public int ChartWidth
|
|
{
|
|
get { return _chartWidth; }
|
|
set { _chartWidth = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The list to use to chart
|
|
/// </summary>
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDisplayName("List Name (SharePoint List)")]
|
|
[WebDescription("The list to use to chart")]
|
|
public string ListName
|
|
{
|
|
get { return _listName; }
|
|
set { _listName = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The view of the list to use to chart
|
|
/// </summary>
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDisplayName("View Name (SharePoint View). If empty the default view will be used.")]
|
|
[WebDescription("The view (of the list) to use in order to generate a graph")]
|
|
public string ViewName
|
|
{
|
|
get { return _viewName; }
|
|
set { _viewName = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Name of the column to use as the horizontal value
|
|
/// </summary>
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDisplayName("Name of the column to use as horizontal (x) value")]
|
|
[WebDescription("This should be a existing column name of a SharePoint List")]
|
|
public string XValue
|
|
{
|
|
get { return _xValue; }
|
|
set { _xValue = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Name of the column to use as the vertical value
|
|
/// </summary>
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDisplayName("Name of the column to use as vertical (y) value. Leave empty if you select a 'Count' action below")]
|
|
[WebDescription("This should be a existing column name of a SharePoint List")]
|
|
public string YValue
|
|
{
|
|
get { return _yValue; }
|
|
set { _yValue = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Group action to perform
|
|
/// </summary>
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDisplayName("Action to perform over columns")]
|
|
[WebDescription("")]
|
|
public GroupAction Action
|
|
{
|
|
get { return _action; }
|
|
set { _action = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Title of the horizontal values
|
|
/// </summary>
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDisplayName("Horizontal (x) title to display")]
|
|
[WebDescription("Title of the horizontal values that will be displayed on the chart")]
|
|
public string XTitle
|
|
{
|
|
get { return _xTitle; }
|
|
set { _xTitle = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Title of the vertical values
|
|
/// </summary>
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDisplayName("Vertical (y) title to display")]
|
|
[WebDescription("Title of the vertical values that will be displayed on the chart")]
|
|
public string YTitle
|
|
{
|
|
get { return _yTitle; }
|
|
set { _yTitle = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Number of decimal places for the vertical values
|
|
/// </summary>
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDisplayName("Vertical (y) decimal precision")]
|
|
[WebDescription("Number of decimal places to show in vertical values")]
|
|
public int YDecimalPrecision
|
|
{
|
|
get { return _yDecimalPrecision; }
|
|
set { _yDecimalPrecision = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scaling for the vertical values
|
|
/// </summary>
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDisplayName("Vertical (y) scaling")]
|
|
[WebDescription("Scale factor for vertical values (e.g., 1000 for thousands)")]
|
|
public bool YNumberScale
|
|
{
|
|
get { return _yNumberScale; }
|
|
set { _yNumberScale = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Optional prefix for y axis value display (e.g., $)
|
|
/// </summary>
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDisplayName("Vertical (y) prefix")]
|
|
[WebDescription("Prefix for vertical values (e.g., $))")]
|
|
public string YNumberPrefix
|
|
{
|
|
get { return _yNumberPrefix; }
|
|
set { _yNumberPrefix = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// List of colors to use while charting
|
|
/// </summary>
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDisplayName("Colors to use")]
|
|
[WebDescription("List of colors to use when charting")]
|
|
public string Colors
|
|
{
|
|
get
|
|
{
|
|
if (_colors == null)
|
|
{
|
|
_colors = Utils.GetDefaultColors();
|
|
}
|
|
return _colors;
|
|
}
|
|
set { _colors = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The HTML Id of the chart
|
|
/// </summary>
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDisplayName("Chart HTML ID")]
|
|
[WebDescription("The Html ID that will identify the chart")]
|
|
public string ChartID
|
|
{
|
|
get
|
|
{
|
|
if (_chartId == null) // Chart is missing an HTML ID
|
|
{
|
|
// We generate a ID for the chart
|
|
_chartId = "chart" + Utils.GenerateRandomId().ToString();
|
|
}
|
|
return _chartId;
|
|
}
|
|
set { _chartId = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// do we have to display custom button to export to excel ?
|
|
/// </summary>
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDisplayName("Enable excel export")]
|
|
[WebDescription("Display a custom button to export the chart to excel")]
|
|
public bool ExcelExport
|
|
{
|
|
get { return _excelExport; }
|
|
set { _excelExport = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// do we have to display custom button to export to xml ?
|
|
/// </summary>
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDisplayName("Enable XML export")]
|
|
[WebDescription("Display a custom button to export the chart to a xml file")]
|
|
public bool XMLExport
|
|
{
|
|
get { return _xmlExport; }
|
|
set { _xmlExport = value; }
|
|
}
|
|
|
|
public enum DiagnosticSetting { None, IncludeVersion, Trace };
|
|
private DiagnosticSetting _myDiagnostics = DiagnosticSetting.None;
|
|
[Personalizable(PersonalizationScope.Shared)]
|
|
[WebBrowsable(true)]
|
|
[System.ComponentModel.Category("Fusion Charts")]
|
|
[WebDescription("Level of diagnostic reporting (into comment in script in page source)")]
|
|
[Microsoft.SharePoint.WebPartPages.WebPartStorage(Microsoft.SharePoint.WebPartPages.Storage.Shared)]
|
|
public DiagnosticSetting Diagnostics
|
|
{
|
|
get { return _myDiagnostics; }
|
|
set { _myDiagnostics = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Constructors
|
|
|
|
public ChartFromList()
|
|
{
|
|
this.ExportMode = WebPartExportMode.All;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
/// <summary>
|
|
/// Create all your controls here for rendering.
|
|
/// Try to avoid using the RenderWebPart() method.
|
|
/// </summary>
|
|
protected override void CreateChildControls()
|
|
{
|
|
if (!_error)
|
|
{
|
|
try
|
|
{
|
|
// wire up PreRender for diagnostics
|
|
this.PreRender += new EventHandler(OnPreRender);
|
|
|
|
base.CreateChildControls();
|
|
|
|
// We first check all settings
|
|
CheckSettings();
|
|
|
|
ListReader rdr = new ListReader(this, _listName, _viewName);
|
|
rdr.FindListView();
|
|
CheckFieldNames(rdr);
|
|
|
|
// We transform the list into XML Input
|
|
string chartXmlContent = GetXmlFromListData(rdr);
|
|
|
|
// We generate the graph
|
|
string chartHtml = Utils.RenderChartHTML(ChartType, chartXmlContent, ChartID.ToString(), ChartWidth.ToString(), ChartHeight.ToString(), false);
|
|
LiteralControl lc = new LiteralControl(chartHtml);
|
|
this.Controls.Add(lc);
|
|
|
|
// We add a cariage return to display correctly export buttons
|
|
if (this._excelExport || this._xmlExport)
|
|
{
|
|
this.Controls.Add(new LiteralControl("<br />"));
|
|
}
|
|
|
|
// display (or not, depending of the user choice option) the button "export to excel"
|
|
if (this._excelExport)
|
|
{
|
|
Button btnExcel = new Button();
|
|
btnExcel.Text = "Export chart to Excel";
|
|
btnExcel.Click += new System.EventHandler(this.ExportExcelButtonClick);
|
|
btnExcel.Style.Add("font-size", "10");
|
|
btnExcel.Style.Add("margin", "10");
|
|
this.Controls.Add(btnExcel);
|
|
}
|
|
|
|
// display (or not, depending of the user choice option) the button "export to xml"
|
|
if (this._xmlExport)
|
|
{
|
|
Button btnXML = new Button();
|
|
btnXML.Text = "Export chart to XML file";
|
|
btnXML.Click += new System.EventHandler(this.ExportXmlButtonClick);
|
|
btnXML.Style.Add("font-size", "10");
|
|
btnXML.Style.Add("margin", "10");
|
|
this.Controls.Add(btnXML);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
HandleException(ex);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Find requested list (& view), and read requested fields, and return plot data
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private Plots GetPlotData(ListReader rdr)
|
|
{
|
|
List<string> yFieldNames = new List<string>();
|
|
yFieldNames.Add(YValue);
|
|
Plots plots = rdr.GetPlots(XValue, yFieldNames, Action);
|
|
return plots;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get list data and write it to xml format used by Fusion Charts Free
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private string GetXmlFromListData(ListReader rdr)
|
|
{
|
|
// Get series data from list
|
|
Plots plots = GetPlotData(rdr);
|
|
// Write series data into XML string
|
|
ChartXmlWriter writer = new ChartXmlWriter(plots, ChartTitle, XTitle, YTitle, Colors);
|
|
writer.YDecimalPrecision = YDecimalPrecision;
|
|
writer.YNumberScale = YNumberScale;
|
|
writer.YNumberPrefix = YNumberPrefix;
|
|
string xml = writer.WriteXml();
|
|
return xml;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clear all child controls and add an error message for display.
|
|
/// </summary>
|
|
/// <param name="ex"></param>
|
|
private void HandleException(Exception ex)
|
|
{
|
|
this._error = true;
|
|
this.Controls.Clear();
|
|
this.Controls.Add(new LiteralControl("ERROR: " + ex.Message));
|
|
}
|
|
|
|
/// <summary>
|
|
/// After Load and PostBack events, PreRender occurs
|
|
/// </summary>
|
|
/// <param name="obj"></param>
|
|
/// <param name="args"></param>
|
|
private void OnPreRender(object obj, EventArgs args)
|
|
{
|
|
// Add trace info after all controls are loaded
|
|
// and all postback events have fired, so _myTrace
|
|
// has all trace info
|
|
OutputTrace();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks the web part properties (settings) before trying to render the chart
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private void CheckSettings()
|
|
{
|
|
if (_listName == String.Empty)
|
|
{
|
|
throw (new Exception("Please edit the webpart properties to provide a SharePoint List name to use."));
|
|
}
|
|
|
|
if (_xValue == String.Empty)
|
|
{
|
|
throw (new Exception("Please edit the webpart properties to provide a horizontal (x) column name to use."));
|
|
}
|
|
|
|
if (_yValue == String.Empty && Action != GroupAction.COUNT)
|
|
{
|
|
throw (new Exception("Please edit the webpart properties to provide a vertical (y) column name to use."));
|
|
}
|
|
}
|
|
|
|
private void CheckFieldNames(ListReader rdr)
|
|
{
|
|
if (rdr.ParsedList == null)
|
|
{
|
|
throw (new Exception("Please edit the webpart properties to provide a valid SharePoint list name to use."));
|
|
}
|
|
if (rdr.ParsedView == null)
|
|
{
|
|
throw (new Exception("Please edit the webpart properties to provide a valid SharePoint view name to use."));
|
|
}
|
|
_xValue = GetInternalFieldName(rdr.ParsedList, _xValue,
|
|
"Please edit the webpart properties to provide a valid vertical (y) column name to use."
|
|
);
|
|
if (!rdr.ParsedView.ViewFields.Exists(_xValue))
|
|
{
|
|
throw (new Exception("Please edit the webpart properties to use a view that contains the horizontal (x) column chosen."));
|
|
}
|
|
if (Action != GroupAction.COUNT)
|
|
{
|
|
_yValue = GetInternalFieldName(rdr.ParsedList, _yValue,
|
|
"Please edit the webpart properties to provide a valid vertical (y) column name to use."
|
|
);
|
|
if (!rdr.ParsedView.ViewFields.Exists(_yValue))
|
|
{
|
|
throw (new Exception("Please edit the webpart properties to use a view that contains the vertical (y) column chosen."));
|
|
}
|
|
}
|
|
}
|
|
private string GetInternalFieldName(SPList list, string name, string errormsg)
|
|
{
|
|
SPField field = null;
|
|
try
|
|
{
|
|
field = list.Fields.GetFieldByInternalName(name);
|
|
}
|
|
catch
|
|
{
|
|
// try as display name
|
|
field = list.Fields[name];
|
|
}
|
|
if (field == null)
|
|
{
|
|
throw (new Exception(errormsg));
|
|
}
|
|
return field.InternalName;
|
|
}
|
|
|
|
/// <summary>
|
|
/// When the user click on the export to Excel button
|
|
/// so we build a csv and then make it download with good header to make it opened by excel automatically
|
|
/// </summary>
|
|
protected void ExportExcelButtonClick(object sender, EventArgs e)
|
|
{
|
|
// We first check all settings
|
|
CheckSettings();
|
|
|
|
ListReader rdr = new ListReader(this, _listName, _viewName);
|
|
rdr.FindListView();
|
|
CheckFieldNames(rdr);
|
|
|
|
// Get List data
|
|
Plots plots = GetPlotData(rdr);
|
|
|
|
|
|
// we build the csv string
|
|
StringBuilder csv = new StringBuilder();
|
|
csv.AppendLine(((XTitle != "") ? XTitle : "X") + ";" + ((YTitle != "") ? YTitle : "Y"));
|
|
|
|
for (int i = 0; i < plots.Count(); i++)
|
|
{
|
|
csv.AppendLine(plots.GetX(i).Replace(",", " ").Replace(";", " ") + ";" + plots.GetY(i).ToString().Replace(",", " ").Replace(";", " "));
|
|
}
|
|
|
|
Context.Response.Clear();
|
|
Context.Response.ContentType = "application/octet-stream";
|
|
Context.Response.AddHeader("Content-Disposition", "attachment; filename=ExcelExport.csv");
|
|
Context.Response.AddHeader("Content-Length", csv.Length.ToString());
|
|
Context.Response.Write(csv.ToString());
|
|
Context.Response.End();
|
|
}
|
|
|
|
/// <summary>
|
|
/// When the user click on the export to XML button
|
|
/// so we get to xml, and make it download
|
|
/// </summary>
|
|
protected void ExportXmlButtonClick(object sender, EventArgs e)
|
|
{
|
|
// We first check all settings
|
|
CheckSettings();
|
|
|
|
ListReader rdr = new ListReader(this, _listName, _viewName);
|
|
rdr.FindListView();
|
|
CheckFieldNames(rdr);
|
|
|
|
// We transform the list into XML Input
|
|
string chartXmlContent = GetXmlFromListData(rdr);
|
|
|
|
Context.Response.Clear();
|
|
Context.Response.ContentType = "application/octet-stream";
|
|
Context.Response.AddHeader("Content-Disposition", "attachment; filename=XMLExport.xml");
|
|
Context.Response.AddHeader("Content-Length", chartXmlContent.Length.ToString());
|
|
Context.Response.Write(chartXmlContent);
|
|
Context.Response.End();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Developer Diagnostics
|
|
|
|
/// <summary>
|
|
/// Write diagnostic info into trace string
|
|
/// If user has enabled it, trace string will be written to an HTML comment inside page
|
|
/// </summary>
|
|
/// <param name="msg"></param>
|
|
public void TraceLine(string msg)
|
|
{
|
|
_myTrace += msg + "\n";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write version info (and accumulated trace info if any) into HTML comment in page
|
|
/// </summary>
|
|
private void OutputTrace()
|
|
{
|
|
if (_myDiagnostics != DiagnosticSetting.None)
|
|
{
|
|
string tracemsg = "";
|
|
if (_myDiagnostics == DiagnosticSetting.Trace)
|
|
{
|
|
tracemsg = "\nTrace:\n";
|
|
if (_myTrace.Length == 0)
|
|
{
|
|
tracemsg += "No Recorded Trace Info";
|
|
}
|
|
else
|
|
{
|
|
tracemsg += System.Web.HttpUtility.HtmlEncode(_myTrace);
|
|
}
|
|
tracemsg += "\n";
|
|
}
|
|
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
|
|
string message = "<!--\n "
|
|
+ "charts4sharepoint:\n"
|
|
+ "Now: " + DateTime.Now.ToString() + "\n"
|
|
+ "Build String: " + _myBuildVersion + "\n"
|
|
+ "Assembly: " + assembly.FullName + "\n"
|
|
+ "AssemblyFileVersion: " + System.Diagnostics.FileVersionInfo.GetVersionInfo(assembly.Location).FileVersion + "\n"
|
|
+ tracemsg
|
|
+ " -->\n";
|
|
this.Controls.Add(new LiteralControl(message));
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|