/* Copyright (c) 2020, Kevin Pope, John Lewin, Lars Brubaker All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project. */ using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Text.RegularExpressions; using CsvHelper; using MatterHackers.Agg; using MatterHackers.Agg.Platform; using MatterHackers.Agg.UI; using MatterHackers.Localizations; using MatterHackers.MatterControl.CustomWidgets; using MatterHackers.MatterControl.DataStorage; using MatterHackers.MatterControl.DesignTools; using MatterHackers.MatterControl.PartPreviewWindow; using MatterHackers.MatterControl.PrintQueue; using MatterHackers.MatterControl.SettingsManagement; using Newtonsoft.Json; namespace MatterHackers.MatterControl.PrintHistory { public class PrintHistoryListItem : ListViewItemBase { public PrintHistoryListItem(ListViewItem listViewItem, int thumbWidth, int thumbHeight, PrintTask printTask, ThemeConfig theme) : base(listViewItem, thumbWidth, thumbHeight, theme) { this.HAnchor = HAnchor.Stretch; this.VAnchor = VAnchor.Fit; this.Padding = new BorderDouble(0); this.Margin = new BorderDouble(6, 0, 6, 6); this.printTask = printTask; var mainContainer = new GuiWidget { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit }; { indicator = new GuiWidget { VAnchor = VAnchor.Stretch, Width = 15 }; SetIndicatorColor(); var middleColumn = new FlowLayoutWidget(FlowDirection.TopToBottom) { HAnchor = HAnchor.Stretch, Padding = new BorderDouble(6, 3) }; var labelContainer = new FlowLayoutWidget { HAnchor = HAnchor.Stretch }; printInfoWidget = new TextWidget(GetPrintInfo(), pointSize: 12) { TextColor = Color.Black, AutoExpandBoundsToText = true, }; labelContainer.AddChild(printInfoWidget); middleColumn.AddChild(labelContainer); var timeTextColor = new Color(34, 34, 34); var detailsRow = new FlowLayoutWidget { Margin = new BorderDouble(0), HAnchor = HAnchor.Stretch }; { var timeLabel = new TextWidget("Time".Localize().ToUpper() + ": ", pointSize: 8) { TextColor = timeTextColor }; TextWidget timeIndicator; int minutes = printTask.PrintTimeMinutes; if (minutes < 0) { timeIndicator = new TextWidget("Unknown".Localize()); } else if (minutes > 60) { timeIndicator = new TextWidget("{0}hrs {1}min".FormatWith(printTask.PrintTimeMinutes / 60, printTask.PrintTimeMinutes % 60), pointSize: 12); } else { timeIndicator = new TextWidget(string.Format("{0}min", printTask.PrintTimeMinutes), pointSize: 12); } if (printTask.PercentDone > 0) { timeIndicator.AutoExpandBoundsToText = true; timeIndicator.Text += $" ({printTask.PercentDone:0.0}%)"; if (printTask.RecoveryCount > 0) { if (printTask.RecoveryCount == 1) { timeIndicator.Text += " - " + "recovered once".Localize(); } else { timeIndicator.Text += " - " + "recovered {0} times".FormatWith(printTask.RecoveryCount); } } } if (printTask.PrintCanceled) { timeIndicator.Text += " - Canceled"; } timeIndicator.Margin = new BorderDouble(right: 6); timeIndicator.TextColor = timeTextColor; detailsRow.AddChild(timeLabel); detailsRow.AddChild(timeIndicator); detailsRow.AddChild(new HorizontalSpacer()); middleColumn.AddChild(detailsRow); } var primaryContainer = new GuiWidget { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit }; var primaryFlow = new FlowLayoutWidget(FlowDirection.LeftToRight) { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit }; primaryFlow.AddChild(indicator); primaryFlow.AddChild(middleColumn); primaryContainer.AddChild(primaryFlow); AddTimeStamp(printTask, timeTextColor, primaryFlow); mainContainer.AddChild(primaryContainer); this.AddChild(mainContainer); } this.BackgroundColor = new Color(255, 255, 255, 255); } private void SetIndicatorColor() { if (printTask.PrintComplete) { if (printTask.QualityWasSet && printTask.PrintQuality == 0) { indicator.BackgroundColor = new Color(252, 38, 51, 180); } else { indicator.BackgroundColor = new Color(38, 147, 51, 180); } } else if (printTask.PrintCanceled) { indicator.BackgroundColor = new Color(252, 209, 22, 180); } else { indicator.BackgroundColor = Color.LightGray; } } private string GetPrintInfo() { TextInfo textInfo = new CultureInfo("en-US", false).TextInfo; var labelName = ""; if (!string.IsNullOrEmpty(printTask.PrinterName)) { labelName = printTask.PrinterName + ":\n" + labelName; } labelName += textInfo.ToTitleCase(printTask.PrintName).Replace('_', ' '); string groupNames = printTask.ItemsPrinted(); if (!string.IsNullOrEmpty(groupNames)) { labelName += "\n" + groupNames; } if (printTask.QualityWasSet) { labelName += "\n" + "Print Quality".Localize() + ": " + PrintHistoryEditor.QualityNames[printTask.PrintQuality]; } if (!string.IsNullOrWhiteSpace(printTask.Note)) { labelName += "\n" + printTask.Note; } return labelName; } protected override void OnClick(MouseEventArgs mouseEvent) { if (mouseEvent.Button == MouseButtons.Right) { var theme = ApplicationController.Instance.MenuTheme; var printTasks = PrintHistoryData.Instance.GetHistoryItems(1000); var popupMenu = new PopupMenu(theme); var printHistoryEditor = new PrintHistoryEditor(null, theme, printTask, printTasks); var qualityWidget = PrintHistoryEditor.GetQualityWidget(theme, printTask, () => { popupMenu.Unfocus(); printInfoWidget.Text = GetPrintInfo(); SetIndicatorColor(); }, theme.DefaultFontSize); var menuItem = new PopupMenu.MenuItem(qualityWidget, theme) { HAnchor = HAnchor.Fit | HAnchor.Stretch, VAnchor = VAnchor.Fit, HoverColor = Color.Transparent, }; popupMenu.AddChild(menuItem); printHistoryEditor.AddNotesMenu(popupMenu, printTasks, () => { printInfoWidget.Text = GetPrintInfo(); }); popupMenu.CreateSeparator(); AddExportMenu(popupMenu, printTasks); popupMenu.CreateSeparator(); AddClearHistorMenu(popupMenu, printTasks); popupMenu.ShowMenu(this, mouseEvent); } base.OnClick(mouseEvent); } private void AddClearHistorMenu(PopupMenu popupMenu, IEnumerable printTasks) { var clearPrintHistory = popupMenu.CreateMenuItem("Clear History".Localize()); clearPrintHistory.Enabled = printTasks.Any(); clearPrintHistory.Click += (s, e) => { // clear history StyledMessageBox.ShowMessageBox( (clearHistory) => { if (clearHistory) { PrintHistoryData.Instance.ClearHistory(); } }, "Are you sure you want to clear your print history?".Localize(), "Clear History?".Localize(), StyledMessageBox.MessageType.YES_NO, "Clear History".Localize()); }; } private void AddExportMenu(PopupMenu popupMenu, IEnumerable printTasks) { var exportPrintHistory = popupMenu.CreateMenuItem("Export History".Localize() + "..."); exportPrintHistory.Enabled = printTasks.Any(); exportPrintHistory.Click += (s, e) => { if (ApplicationController.Instance.IsMatterControlPro()) { ExportToCsv(printTasks); } else // upsell MatterControl Pro { string text = "Exporting print history is a {0} feature. Upgrade to Pro to unlock MatterControl Pro.".Localize().FormatWith(OemSettings.Instance.RegisteredProductName); WebCache.RetrieveText( "https://matterhackers.github.io/MatterControl-Docs/ProContent/Unlock_Export_Print_History.md", (markDown) => { // push the new text into the widget text = markDown; }); StyledMessageBox.ShowMessageBox(text, "Upgrade to Pro".Localize(), StyledMessageBox.MessageType.OK, useMarkdown: true, width: 540, height: 400); } }; } public class RowData { public string Printer { get; set; } public string QualitySettingsName { get; set; } public string MaterialSettingsName { get; set; } public string Name { get; set; } public DateTime Start { get; set; } public DateTime End { get; set; } public int Minutes { get; set; } public bool Completed { get; set; } public bool Canceled { get; internal set; } public double RecoveryCount { get; set; } public string ItemsPrinted { get; set; } public string Notes { get; set; } public string Guid { get; set; } public int PrintQuality { get; set; } } private static void ExportToCsv(IEnumerable printTasks) { // right click success or fail // user settings that are different var records = new List(); // do the export foreach (var printTask in printTasks) { string groupNames = printTask.ItemsPrinted(); records.Add(new RowData() { Printer = printTask.PrinterName, Name = printTask.PrintName, Start = printTask.PrintStart, End = printTask.PrintEnd, Completed = printTask.PrintComplete, Canceled = printTask.PrintCanceled, PrintQuality = printTask.PrintQuality, ItemsPrinted = groupNames, Minutes = printTask.PrintTimeMinutes, RecoveryCount = printTask.RecoveryCount, QualitySettingsName = printTask.QualitySettingsName, MaterialSettingsName = printTask.MaterialSettingsName, Notes = printTask.Note, Guid = printTask.Guid, }); } AggContext.FileDialogs.SaveFileDialog( new SaveFileDialogParams("MatterControl Printer Export|*.printer", title: "Export Printer Settings") { FileName = "Printer History.csv", Filter = "CSV Files|*.csv" }, (saveParams) => { try { if (!string.IsNullOrWhiteSpace(saveParams.FileName)) { using (var writer = new StreamWriter(saveParams.FileName)) { using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)) { csv.WriteRecords(records); } } } } catch (Exception e2) { UiThread.RunOnIdle(() => { StyledMessageBox.ShowMessageBox(e2.Message, "Couldn't save file".Localize()); }); } }); } private void AddTimeStamp(PrintTask printTask, Color timeTextColor, FlowLayoutWidget primaryFlow) { var timestampColumn = new FlowLayoutWidget(FlowDirection.TopToBottom) { VAnchor = VAnchor.Stretch, BackgroundColor = Color.LightGray, Padding = new BorderDouble(6, 0) }; var startTimeContainer = new FlowLayoutWidget { HAnchor = HAnchor.Stretch, Padding = new BorderDouble(0, 3) }; string startLabelFull = "{0}:".FormatWith("Start".Localize().ToUpper()); var startLabel = new TextWidget(startLabelFull, pointSize: 8) { TextColor = timeTextColor }; string startTimeString = printTask.PrintStart.ToString("MMM d yyyy h:mm ") + printTask.PrintStart.ToString("tt").ToLower(); var startDate = new TextWidget(startTimeString, pointSize: 12) { TextColor = timeTextColor }; startTimeContainer.AddChild(startLabel); startTimeContainer.AddChild(new HorizontalSpacer()); startTimeContainer.AddChild(startDate); var endTimeContainer = new FlowLayoutWidget { HAnchor = HAnchor.Stretch, Padding = new BorderDouble(0, 3) }; string endLabelFull = "{0}:".FormatWith("End".Localize().ToUpper()); var endLabel = new TextWidget(endLabelFull, pointSize: 8) { TextColor = timeTextColor }; string endTimeString; if (printTask.PrintEnd != DateTime.MinValue) { endTimeString = printTask.PrintEnd.ToString("MMM d yyyy h:mm ") + printTask.PrintEnd.ToString("tt").ToLower(); } else { endTimeString = "Unknown".Localize(); } var endDate = new TextWidget(endTimeString, pointSize: 12) { TextColor = timeTextColor }; endTimeContainer.AddChild(endLabel); endTimeContainer.AddChild(new HorizontalSpacer()); endTimeContainer.AddChild(endDate); var horizontalLine = new HorizontalLine { BackgroundColor = Color.Gray }; timestampColumn.AddChild(endTimeContainer); timestampColumn.AddChild(horizontalLine); timestampColumn.AddChild(startTimeContainer); timestampColumn.HAnchor = HAnchor.Stretch; timestampColumn.Padding = new BorderDouble(5, 0, 15, 0); primaryFlow.AddChild(timestampColumn); } private PrintTask printTask; private GuiWidget indicator; private TextWidget printInfoWidget; } }