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 /// /// The title of the chart /// [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; } } /// /// The type of chart to display /// [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; } } /// /// The height of the chart that will be displayed /// [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; } } /// /// The width of the chart that will be displayed /// [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; } } /// /// The list to use to chart /// [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; } } /// /// The view of the list to use to chart /// [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; } } /// /// Name of the column to use as the horizontal value /// [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; } } /// /// Name of the column to use as the vertical value /// [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; } } /// /// Group action to perform /// [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; } } /// /// Title of the horizontal values /// [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; } } /// /// Title of the vertical values /// [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; } } /// /// Number of decimal places for the vertical values /// [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; } } /// /// Scaling for the vertical values /// [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; } } /// /// Optional prefix for y axis value display (e.g., $) /// [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; } } /// /// List of colors to use while charting /// [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; } } /// /// The HTML Id of the chart /// [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; } } /// /// do we have to display custom button to export to excel ? /// [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; } } /// /// do we have to display custom button to export to xml ? /// [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 /// /// Create all your controls here for rendering. /// Try to avoid using the RenderWebPart() method. /// 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("
")); } // 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); } } } /// /// Find requested list (& view), and read requested fields, and return plot data /// /// private Plots GetPlotData(ListReader rdr) { List yFieldNames = new List(); yFieldNames.Add(YValue); Plots plots = rdr.GetPlots(XValue, yFieldNames, Action); return plots; } /// /// Get list data and write it to xml format used by Fusion Charts Free /// /// 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; } /// /// Clear all child controls and add an error message for display. /// /// private void HandleException(Exception ex) { this._error = true; this.Controls.Clear(); this.Controls.Add(new LiteralControl("ERROR: " + ex.Message)); } /// /// After Load and PostBack events, PreRender occurs /// /// /// 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(); } /// /// Checks the web part properties (settings) before trying to render the chart /// /// 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; } /// /// 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 /// 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(); } /// /// When the user click on the export to XML button /// so we get to xml, and make it download /// 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 /// /// Write diagnostic info into trace string /// If user has enabled it, trace string will be written to an HTML comment inside page /// /// public void TraceLine(string msg) { _myTrace += msg + "\n"; } /// /// Write version info (and accumulated trace info if any) into HTML comment in page /// 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"; this.Controls.Add(new LiteralControl(message)); } } #endregion } }