286 lines
11 KiB
C#
286 lines
11 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
|
|
using dezentrale.model;
|
|
|
|
namespace dezentrale.view
|
|
{
|
|
public abstract class CustomListView<T> : ListView where T : class
|
|
{
|
|
protected abstract List<ConfigLVDataHandler> DefaultColumns { get; }
|
|
|
|
protected List<T> internalList = null;
|
|
private ContextMenu cm = new ContextMenu();
|
|
|
|
private List<ConfigLVDataHandler> actualColumns = null;
|
|
private bool checkBoxes = true;
|
|
private bool columnConfiguration = true;
|
|
private int internalColumns = 0;
|
|
|
|
protected void BuildColumns()
|
|
{
|
|
this.Columns.Add(new ColumnHeader() { Text = checkBoxes ? "[x]" : "", Width = checkBoxes ? 24 : 0, }); //LVI column is always there!
|
|
this.ItemCheck += (sender, e) =>
|
|
{
|
|
//This is a workaround for checkboxes keep changing when MultiSelect with Shift
|
|
if ((ModifierKeys & (Keys.Shift | Keys.Control)) != 0)
|
|
e.NewValue = e.CurrentValue;
|
|
};
|
|
|
|
//todo: Add column-filtering (implementation with search dialog)
|
|
// MenuItem filterMenu = cm.MenuItems.Add("Filter by column...");
|
|
foreach (ConfigLVDataHandler col in actualColumns)
|
|
{
|
|
if(col.FilterAvailable)
|
|
{
|
|
//Process filter settings from DataHandler --> add menu entries
|
|
}
|
|
if (col.Visible) this.Columns.Add(new ColumnHeader() { Width = col.Width, Text = col.Display, TextAlign = col.TextAlign, Tag = col, });
|
|
}
|
|
//todo: Add column-filtering (implementation with search dialog)
|
|
/* if(filterMenu.MenuItems.Count < 1)
|
|
{
|
|
MenuItem unavailable = new MenuItem("unavailable");
|
|
unavailable.Enabled = false;
|
|
filterMenu.MenuItems.Add(unavailable);
|
|
}
|
|
*/
|
|
}
|
|
public CustomListView(List<ConfigLVColumn> actualColumns, EventHandler<ColumnsChangedArgs> ColumnsChanged = null, bool checkBoxes = false, bool columnConfiguration = true) : base()
|
|
{
|
|
this.ColumnsChanged = ColumnsChanged;
|
|
this.checkBoxes = checkBoxes;
|
|
this.columnConfiguration = columnConfiguration;
|
|
this.View = View.Details; //This gives us a traditional "list" view.
|
|
this.CheckBoxes = checkBoxes;
|
|
this.FullRowSelect = true;
|
|
this.ContextMenu = cm;
|
|
|
|
bool colsChanged = false;
|
|
this.actualColumns = new List<ConfigLVDataHandler>();
|
|
foreach (ConfigLVColumn lvc in actualColumns)
|
|
{
|
|
ConfigLVDataHandler def = DefaultColumns.Find(x => x.Name == lvc.Name);
|
|
if (def == null)
|
|
{
|
|
colsChanged = true;
|
|
continue; //this is a column we don't support. Old version? Just throw away.
|
|
}
|
|
|
|
this.actualColumns.Add(new ConfigLVDataHandler(lvc, def));
|
|
}
|
|
|
|
foreach (ConfigLVDataHandler c in DefaultColumns)
|
|
{
|
|
ConfigLVDataHandler act = this.actualColumns.Find(x => x.Name == c.Name);
|
|
if (act == null)
|
|
{
|
|
//this is a column we expect but didn't find in the serialized data. Old version? Just add it here.
|
|
this.actualColumns.Add(new ConfigLVDataHandler(c, c));
|
|
colsChanged = true;
|
|
}
|
|
}
|
|
|
|
BuildColumns();
|
|
if (columnConfiguration)
|
|
{
|
|
internalColumns += 2;
|
|
cm.MenuItems.Add("-");
|
|
cm.MenuItems.Add("Configure columns...", mnuConfigColumns_Click);
|
|
|
|
ColumnWidthChanged += CustomListView_ColumnWidthChanged;
|
|
MouseUp += CustomListView_MouseUp;
|
|
if (colsChanged)
|
|
ColumnsChanged?.Invoke(this, new ColumnsChangedArgs() { Columns = this.actualColumns });
|
|
}
|
|
}
|
|
public event EventHandler<ColumnsChangedArgs> ColumnsChanged;
|
|
|
|
private void mnuConfigColumns_Click(object sender, EventArgs e)
|
|
{
|
|
frmConfigureLVColumns colConfigure = new frmConfigureLVColumns(actualColumns);
|
|
colConfigure.ShowDialog();
|
|
if (colConfigure.ColumnsChanged)
|
|
{
|
|
ColumnsChangedArgs cca = new ColumnsChangedArgs() { Columns = colConfigure.GetLVColumnList() };
|
|
ColumnsChanged?.Invoke(this, cca);
|
|
if (cca.Cancel) return;
|
|
actualColumns = cca.Columns;
|
|
this.Items.Clear();
|
|
this.Columns.Clear();
|
|
BuildColumns();
|
|
LoadFromList(internalList);
|
|
}
|
|
}
|
|
|
|
private void SetNewColWidth(ConfigLVDataHandler c, int newWidth)
|
|
{
|
|
Console.WriteLine($"SetNewColWidth({c},{newWidth})");
|
|
List<ConfigLVDataHandler> newList = new List<ConfigLVDataHandler>();
|
|
foreach (ConfigLVDataHandler lvc in actualColumns)
|
|
{
|
|
ConfigLVDataHandler c2 = new ConfigLVDataHandler(lvc, lvc);
|
|
if (c.Name == lvc.Name) c2.Width = newWidth;
|
|
newList.Add(c2);
|
|
}
|
|
ColumnsChangedArgs cca = new ColumnsChangedArgs() { Columns = newList };
|
|
ColumnsChanged?.Invoke(this, cca);
|
|
if (cca.Cancel) return;
|
|
actualColumns = cca.Columns;
|
|
}
|
|
|
|
|
|
private bool resizeWhileMouseDown = false;
|
|
private ConfigLVDataHandler resizedWhileMouseDown = null;
|
|
private void CustomListView_ColumnWidthChanged(object sender, ColumnWidthChangedEventArgs e)
|
|
{
|
|
ColumnHeader col = this.Columns[e.ColumnIndex];
|
|
ConfigLVDataHandler c = (ConfigLVDataHandler)col.Tag;
|
|
if ((c != null) && (c.Width != col.Width))
|
|
{
|
|
if(Control.MouseButtons == MouseButtons.None)
|
|
SetNewColWidth(c, col.Width);
|
|
else
|
|
{
|
|
//Just remember that setting for later
|
|
//Console.WriteLine($"ColumnWidthChanged(): MouseButtons={Control.MouseButtons}");
|
|
c.NewWidth = col.Width;
|
|
resizeWhileMouseDown = true;
|
|
resizedWhileMouseDown = c;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CustomListView_MouseUp(object sender, MouseEventArgs e)
|
|
{
|
|
//Console.WriteLine($"MouseUp(): MouseButtons={Control.MouseButtons}");
|
|
if (resizeWhileMouseDown && (resizedWhileMouseDown != null))
|
|
{
|
|
//mono: Store new width.
|
|
resizeWhileMouseDown = false;
|
|
SetNewColWidth(resizedWhileMouseDown, resizedWhileMouseDown.NewWidth);
|
|
}
|
|
}
|
|
|
|
|
|
protected ListViewItem GetExistingLvi(T tag)
|
|
{
|
|
foreach (ListViewItem lvi in this.Items)
|
|
{
|
|
if (lvi.Tag == tag) return lvi;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
protected ListViewItem UpdateLvi(ListViewItem lvi, T t)
|
|
{
|
|
if (lvi != null && t != null)
|
|
{
|
|
lvi.Tag = t;
|
|
lvi.SubItems.Clear();
|
|
|
|
foreach (ConfigLVDataHandler col in actualColumns)
|
|
{
|
|
if (!col.Visible) continue;
|
|
lvi.SubItems.Add(col.CustomToLvsi(lvi, t));
|
|
}
|
|
}
|
|
return lvi;
|
|
}
|
|
|
|
public void AddEntry(T t) { this.Items.Add(UpdateLvi(new ListViewItem(), t)); }
|
|
public void UpdateEntry(T t) { UpdateLvi(GetExistingLvi(t), t); }
|
|
public void RemoveEntry(T t) { ListViewItem lvi = GetExistingLvi(t); if (lvi != null) this.Items.Remove(lvi); }
|
|
public void DeSelectEntry(T t, bool sel = true) { ListViewItem lvi = GetExistingLvi(t); if (lvi != null) lvi.Selected = sel; }
|
|
public T GetFirstSelectedItem()
|
|
{
|
|
if (this.SelectedItems.Count < 1) return null;
|
|
return (T)this.SelectedItems[0].Tag;
|
|
}
|
|
public List<T> GetAllItems()
|
|
{
|
|
List<T> ret = new List<T>();
|
|
for (int i = 0; i < this.Items.Count; i++)
|
|
ret.Add((T)this.Items[i].Tag);
|
|
return ret;
|
|
}
|
|
public List<T> GetSelectedItems()
|
|
{
|
|
List<T> ret = new List<T>();
|
|
for(int i = 0; i < this.SelectedItems.Count; i++)
|
|
ret.Add((T)this.SelectedItems[i].Tag);
|
|
|
|
return ret;
|
|
}
|
|
public List<T> GetCheckedItems()
|
|
{
|
|
List<T> ret = new List<T>();
|
|
foreach (ListViewItem lvi in this.CheckedItems)
|
|
ret.Add((T)lvi.Tag);
|
|
return ret;
|
|
}
|
|
|
|
public bool ItemSelection(T entry, bool selected)
|
|
{
|
|
foreach (ListViewItem lvi in this.Items)
|
|
if (lvi.Tag.Equals(entry))
|
|
{
|
|
lvi.Selected = selected;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public MenuItem AddMenuItem(string text, EventHandler handler = null, MenuItem parent = null, bool enabled = true)
|
|
{
|
|
MenuItem mi = new MenuItem() { Text = text };
|
|
mi.Enabled = enabled;
|
|
|
|
if (handler != null) mi.Click += handler;
|
|
|
|
if (parent != null) parent.MenuItems.Add(mi);
|
|
else
|
|
{
|
|
cm.MenuItems.Add((cm.MenuItems.Count - internalColumns), mi);
|
|
}
|
|
return mi;
|
|
}
|
|
public void ClearMenuItems()
|
|
{
|
|
while(cm.MenuItems.Count > internalColumns)
|
|
{
|
|
cm.MenuItems.RemoveAt(0);
|
|
}
|
|
}
|
|
|
|
public void LoadFromList(List<T> entries)
|
|
{
|
|
this.SuspendLayout();
|
|
this.Items.Clear();
|
|
internalList = entries;
|
|
|
|
foreach (T t in entries)
|
|
{
|
|
//TBD implement generic filtering
|
|
/*
|
|
if (StatusFilter != null)
|
|
{
|
|
if (!StatusFilter.Contains(t.Status)) continue;
|
|
}*/
|
|
this.Items.Add(UpdateLvi(new ListViewItem(), t));
|
|
}
|
|
this.ResumeLayout(false);
|
|
}
|
|
}
|
|
|
|
public class ColumnsChangedArgs
|
|
{
|
|
public List<ConfigLVDataHandler> Columns { get; set; } = null;
|
|
public bool Cancel { get; set; } = false;
|
|
}
|
|
}
|