From 290b30f916f91923070d18fcb13ef4f35240cb1c Mon Sep 17 00:00:00 2001 From: CoderCow Date: Thu, 27 Jun 2013 10:48:18 +0200 Subject: [PATCH] Added PaginationTools class to greatly simplify sending multiple pages of data to a player. --- TShockAPI/PaginationTools.cs | 253 ++++++++++++++++++++++ TShockAPI/TShockAPI.csproj | 393 ++++++++++++++++++----------------- 2 files changed, 450 insertions(+), 196 deletions(-) create mode 100644 TShockAPI/PaginationTools.cs diff --git a/TShockAPI/PaginationTools.cs b/TShockAPI/PaginationTools.cs new file mode 100644 index 00000000..f7ab193c --- /dev/null +++ b/TShockAPI/PaginationTools.cs @@ -0,0 +1,253 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace TShockAPI { + public static class PaginationTools { + public delegate Tuple LineFormatterDelegate(object lineData, int lineIndex, int pageNumber); + + #region [Nested: Settings Class] + public class Settings { + public bool IncludeHeader { get; set; } + + private string headerFormat; + public string HeaderFormat + { + get { return this.headerFormat; } + set + { + if (value == null) + throw new ArgumentNullException(); + + this.headerFormat = value; + } + } + + public Color HeaderTextColor { get; set; } + public bool IncludeFooter { get; set; } + + private string footerFormat; + public string FooterFormat + { + get { return this.footerFormat; } + set + { + if (value == null) + throw new ArgumentNullException(); + + this.footerFormat = value; + } + } + + public Color FooterTextColor { get; set; } + public string NothingToDisplayString { get; set; } + public LineFormatterDelegate LineFormatter { get; set; } + public Color LineTextColor { get; set; } + + private int maxLinesPerPage; + + public int MaxLinesPerPage + { + get { return this.maxLinesPerPage; } + set + { + if (value <= 0) + throw new ArgumentException("The value has to be greater than zero."); + + this.maxLinesPerPage = value; + } + } + + private int pageLimit; + + public int PageLimit + { + get { return this.pageLimit; } + set + { + if (value < 0) + throw new ArgumentException("The value has to be greater than or equal to zero."); + + this.pageLimit = value; + } + } + + + public Settings() + { + this.IncludeHeader = true; + this.headerFormat = "Page {0} of {1}"; + this.HeaderTextColor = Color.Green; + this.IncludeFooter = true; + this.footerFormat = "Type / {0} for more."; + this.FooterTextColor = Color.Yellow; + this.NothingToDisplayString = null; + this.LineFormatter = null; + this.LineTextColor = Color.White; + this.maxLinesPerPage = 4; + this.pageLimit = 0; + } + } + #endregion + + public static void SendPage( + TSPlayer player, int pageNumber, IEnumerable dataToPaginate, int dataToPaginateCount, Settings settings = null) + { + if (settings == null) + settings = new Settings(); + + if (dataToPaginateCount == 0) + { + if (settings.NothingToDisplayString != null) + player.SendMessage(settings.NothingToDisplayString, settings.HeaderTextColor); + + return; + } + + int pageCount = ((dataToPaginateCount - 1) / settings.MaxLinesPerPage) + 1; + if (settings.PageLimit > 0 && pageCount > settings.PageLimit) + pageCount = settings.PageLimit; + if (pageNumber > pageCount) + pageNumber = pageCount; + + if (settings.IncludeHeader) + player.SendMessage(string.Format(settings.HeaderFormat, pageNumber, pageCount), settings.HeaderTextColor); + + int listOffset = (pageNumber - 1) * settings.MaxLinesPerPage; + int offsetCounter = 0; + int lineCounter = 0; + foreach (object lineData in dataToPaginate) + { + if (lineData == null) + continue; + if (offsetCounter++ < listOffset) + continue; + if (lineCounter++ == settings.MaxLinesPerPage) + break; + + string lineMessage; + Color lineColor = settings.LineTextColor; + if (lineData is Tuple) + { + var lineFormat = (Tuple)lineData; + lineMessage = lineFormat.Item1; + lineColor = lineFormat.Item2; + } + else if (settings.LineFormatter != null) + { + try + { + Tuple lineFormat = settings.LineFormatter(lineData, offsetCounter, pageNumber); + if (lineFormat == null) + continue; + + lineMessage = lineFormat.Item1; + lineColor = lineFormat.Item2; + } + catch (Exception ex) + { + throw new InvalidOperationException( + "The method referenced by LineFormatter has thrown an exception. See inner exception for details.", ex); + } + } + else + { + lineMessage = lineData.ToString(); + } + + if (lineMessage != null) + player.SendMessage(lineMessage, lineColor); + } + + if (lineCounter == 0) + { + if (settings.NothingToDisplayString != null) + player.SendMessage(settings.NothingToDisplayString, settings.HeaderTextColor); + } + else if (settings.IncludeFooter && pageNumber + 1 <= pageCount) + { + player.SendMessage(string.Format(settings.FooterFormat, pageNumber + 1, pageNumber, pageCount), settings.FooterTextColor); + } + } + + public static void SendPage(TSPlayer player, int pageNumber, IList dataToPaginate, Settings settings = null) + { + PaginationTools.SendPage(player, pageNumber, dataToPaginate, dataToPaginate.Count, settings); + } + + public static List BuildLinesFromTerms( + IEnumerable terms, Func termFormatter = null, string separator = ", ", int maxCharsPerLine = 80) + { + List lines = new List(); + StringBuilder lineBuilder = new StringBuilder(); + foreach (object term in terms) + { + if (term == null && termFormatter == null) + continue; + + string termString; + if (termFormatter != null) + { + try { + termString = termFormatter(term); + + if (termString == null) + continue; + } catch (Exception ex) + { + throw new ArgumentException( + "The method represented by termFormatter has thrown an exception. See inner exception for details.", ex); + } + } + else + { + termString = term.ToString(); + } + + bool goesOnNextLine = (lineBuilder.Length + termString.Length > maxCharsPerLine); + if (!goesOnNextLine) + { + if (lineBuilder.Length > 0) { + lineBuilder.Append(separator); + } + lineBuilder.Append(termString); + } + else + { + // A separator should always be at the end of a line as we know it is followed by another line. + lineBuilder.Append(separator); + lines.Add(lineBuilder.ToString()); + lineBuilder.Clear(); + + lineBuilder.Append(termString); + } + } + if (lineBuilder.Length > 0) + lines.Add(lineBuilder.ToString()); + + return lines; + } + + public static bool TryParsePageNumber( + List commandParameters, int expectedParamterIndex, TSPlayer errorMessageReceiver, out int pageNumber) + { + pageNumber = 1; + if (commandParameters.Count <= expectedParamterIndex) + return true; + + string pageNumberRaw = commandParameters[expectedParamterIndex]; + if (!int.TryParse(pageNumberRaw, out pageNumber) || pageNumber < 1) + { + if (errorMessageReceiver != null) + errorMessageReceiver.SendErrorMessage(string.Format("\"{0}\" is not a valid page number.", pageNumberRaw)); + + pageNumber = 1; + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj index 01ff3b32..b98c1645 100644 --- a/TShockAPI/TShockAPI.csproj +++ b/TShockAPI/TShockAPI.csproj @@ -1,203 +1,204 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {49606449-072B-4CF5-8088-AA49DA586694} - Library - Properties - TShockAPI - TShockAPI - v4.0 - 512 - false - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - true - bin\Debug\TShockAPI.XML - - - pdbonly - true - bin\Release\ - TRACE;COMPAT_SIGS - prompt - 4 - true - bin\Release\TShockAPI.XML - - - - ..\HttpBins\HttpServer.dll - - - ..\SqlBins\Mono.Data.Sqlite.dll - - - False - ..\SqlBins\MySql.Data.dll - True - - - False - ..\SqlBins\MySql.Web.dll - True - - - .\Newtonsoft.Json.dll - - - - - - - - - - ..\TerrariaServerBins\TerrariaServer.exe - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - True - Resources.resx - - - - - - - - - - - - - - - - - - - - - - - - - ResXFileCodeGenerator - Designer - Resources.Designer.cs - - - - - False - Microsoft .NET Framework 4 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - False - Windows Installer 3.1 - true - - - - - - - - - - - - - "$(ProjectDir)postbuild.bat" - - - - - - + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {49606449-072B-4CF5-8088-AA49DA586694} + Library + Properties + TShockAPI + TShockAPI + v4.0 + 512 + false + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + bin\Debug\TShockAPI.XML + + + pdbonly + true + bin\Release\ + TRACE;COMPAT_SIGS + prompt + 4 + true + bin\Release\TShockAPI.XML + + + + ..\HttpBins\HttpServer.dll + + + ..\SqlBins\Mono.Data.Sqlite.dll + + + False + ..\SqlBins\MySql.Data.dll + True + + + False + ..\SqlBins\MySql.Web.dll + True + + + .\Newtonsoft.Json.dll + + + + + + + + + + ..\TerrariaServerBins\TerrariaServer.exe + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + + + + + + + + + + + + + + + + + + + + ResXFileCodeGenerator + Designer + Resources.Designer.cs + + + + + False + Microsoft .NET Framework 4 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + False + Windows Installer 3.1 + true + + + + + + + + + + + + + "$(ProjectDir)postbuild.bat" + + + + + + + --> \ No newline at end of file