2019-11-19 09:54:42 -05:00

244 lines
8.7 KiB
C#

using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using ApplicationServices;
using DataLayer;
using Dinah.Core.Collections.Generic;
using Dinah.Core.DataBinding;
namespace LibationWinForm
{
// INSTRUCTIONS TO UPDATE DATA_GRID_VIEW
// - delete current DataGridView
// - view > other windows > data sources
// - refresh
// OR
// - Add New Data Source
// Object. Next
// LibationWinForm
// AudibleDTO
// GridEntry
// - go to Design view
// - click on Data Sources > ProductItem. drowdown: DataGridView
// - drag/drop ProductItem on design surface
public partial class ProductsGrid : UserControl
{
public event EventHandler<int> VisibleCountChanged;
private DataGridView dataGridView;
private LibationContext context;
public ProductsGrid()
{
InitializeComponent();
Disposed += (_, __) => context?.Dispose();
}
private bool hasBeenDisplayed = false;
public void Display()
{
if (hasBeenDisplayed)
return;
hasBeenDisplayed = true;
dataGridView = gridEntryDataGridView;
dataGridView.Dock = DockStyle.Fill;
dataGridView.AllowUserToAddRows = false;
dataGridView.AllowUserToDeleteRows = false;
dataGridView.AutoGenerateColumns = false;
dataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dataGridView.DefaultCellStyle.WrapMode = DataGridViewTriState.True;
dataGridView.ReadOnly = true;
dataGridView.RowHeadersVisible = false;
// adjust height for 80x80 pictures.
// this must be done before databinding. or can alter later by iterating through rows
dataGridView.RowTemplate.Height = 82;
dataGridView.CellFormatting += replaceFormatted;
dataGridView.CellFormatting += hiddenFormatting;
// sorting breaks filters. must reapply filters after sorting
dataGridView.Sorted += (_, __) => filter();
{ // add tag buttons
var editUserTagsButton = new DataGridViewButtonColumn { HeaderText = "Edit Tags" };
dataGridView.Columns.Add(editUserTagsButton);
// add image and handle click
dataGridView.CellPainting += paintEditTag_TextAndImage;
dataGridView.CellContentClick += dataGridView_GridButtonClick;
}
for (var i = dataGridView.ColumnCount - 1; i >= 0; i--)
{
DataGridViewColumn col = dataGridView.Columns[i];
// initial HeaderText is the lookup name from GridEntry class. any formatting below won't change this
col.Name = col.HeaderText;
if (!(col is DataGridViewImageColumn || col is DataGridViewButtonColumn))
col.SortMode = DataGridViewColumnSortMode.Automatic;
col.HeaderText = col.HeaderText.Replace("_", " ");
col.Width = col.Name switch
{
nameof(GridEntry.Cover) => 80,
nameof(GridEntry.Title) => col.Width * 2,
nameof(GridEntry.Misc) => (int)(col.Width * 1.35),
var n when n.In(nameof(GridEntry.My_Rating), nameof(GridEntry.Product_Rating)) => col.Width + 8,
_ => col.Width
};
}
//
// transform into sorted GridEntry.s BEFORE binding
//
context = LibationContext.Create();
var lib = context.GetLibrary_Flat_WithTracking();
// if no data. hide all columns. return
if (!lib.Any())
{
for (var i = dataGridView.ColumnCount - 1; i >= 0; i--)
dataGridView.Columns.RemoveAt(i);
return;
}
var orderedGridEntries = lib
.Select(lb => new GridEntry(lb)).ToList()
// default load order
.OrderByDescending(ge => ge.Purchase_Date)
//// more advanced example: sort by author, then series, then title
//.OrderBy(ge => ge.Authors)
// .ThenBy(ge => ge.Series)
// .ThenBy(ge => ge.Title)
.ToList();
//
// BIND
//
gridEntryBindingSource.DataSource = orderedGridEntries.ToSortableBindingList();
//
// FILTER
//
filter();
}
private void paintEditTag_TextAndImage(object sender, DataGridViewCellPaintingEventArgs e)
{
// DataGridView Image for Button Column: https://stackoverflow.com/a/36253883
if (e.RowIndex < 0 || !(((DataGridView)sender).Columns[e.ColumnIndex] is DataGridViewButtonColumn))
return;
var gridEntry = getGridEntry(e.RowIndex);
var displayTags = gridEntry.TagsEnumerated.ToList();
if (displayTags.Any())
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = string.Join("\r\n", displayTags);
else // no tags: use image
{
// clear tag text
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = "";
// images from: icons8.com -- search: tags
var image = Properties.Resources.edit_tags_25x25;
e.Paint(e.CellBounds, DataGridViewPaintParts.All);
var w = image.Width;
var h = image.Height;
var x = e.CellBounds.Left + (e.CellBounds.Width - w) / 2;
var y = e.CellBounds.Top + (e.CellBounds.Height - h) / 2;
e.Graphics.DrawImage(image, new Rectangle(x, y, w, h));
e.Handled = true;
}
}
private void dataGridView_GridButtonClick(object sender, DataGridViewCellEventArgs e)
{
// handle grid button click: https://stackoverflow.com/a/13687844
if (e.RowIndex < 0)
return;
if (sender != dataGridView)
throw new Exception($"{nameof(dataGridView_GridButtonClick)} has incorrect sender ...somehow");
if (!(dataGridView.Columns[e.ColumnIndex] is DataGridViewButtonColumn))
return;
var liveGridEntry = getGridEntry(e.RowIndex);
// EditTagsDialog should display better-formatted title
liveGridEntry.TryGetFormatted(nameof(liveGridEntry.Title), out string value);
var editTagsForm = new EditTagsDialog(value, liveGridEntry.Tags);
if (editTagsForm.ShowDialog() != DialogResult.OK)
return;
var qtyChanges = context.UpdateTags(liveGridEntry.GetBook(), editTagsForm.NewTags);
if (qtyChanges == 0)
return;
// force a re-draw, and re-apply filters
// needed to update text colors
dataGridView.InvalidateRow(e.RowIndex);
filter();
}
#region Cell Formatting
private void replaceFormatted(object sender, DataGridViewCellFormattingEventArgs e)
{
var col = ((DataGridView)sender).Columns[e.ColumnIndex];
if (col is DataGridViewTextBoxColumn textCol && getGridEntry(e.RowIndex).TryGetFormatted(textCol.Name, out string value))
e.Value = value;
}
private void hiddenFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
var isHidden = getGridEntry(e.RowIndex).TagsEnumerated.Contains("hidden");
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Style
= isHidden
? new DataGridViewCellStyle { ForeColor = Color.LightGray }
: dataGridView.DefaultCellStyle;
}
#endregion
#region filter
string _filterSearchString;
private void filter() => Filter(_filterSearchString);
public void Filter(string searchString)
{
_filterSearchString = searchString;
if (dataGridView.Rows.Count == 0)
return;
var searchResults = SearchEngineCommands.Search(searchString);
var productIds = searchResults.Docs.Select(d => d.ProductId).ToList();
// https://stackoverflow.com/a/18942430
var currencyManager = (CurrencyManager)BindingContext[dataGridView.DataSource];
currencyManager.SuspendBinding();
{
for (var r = dataGridView.RowCount - 1; r >= 0; r--)
dataGridView.Rows[r].Visible = productIds.Contains(getGridEntry(r).GetBook().AudibleProductId);
}
currencyManager.ResumeBinding();
VisibleCountChanged?.Invoke(this, dataGridView.Rows.Cast<DataGridViewRow>().Count(r => r.Visible));
var luceneSearchString_debug = searchResults.SearchString;
}
#endregion
private GridEntry getGridEntry(int rowIndex) => (GridEntry)dataGridView.Rows[rowIndex].DataBoundItem;
}
}