190626PX Adapted LVMoneyTransfers to use CustomListView; Bugfixing

This commit is contained in:
phantomix 2019-06-26 16:54:45 +02:00
parent 6cb075b293
commit f19b546fce
9 changed files with 171 additions and 239 deletions

View File

@ -25,7 +25,7 @@ namespace dezentrale
{
public class Program
{
public static uint VersionNumber { get; private set; } = 0x19062500;
public static uint VersionNumber { get; private set; } = 0x19062600;
public static string VersionString { get; private set; } = $"{VersionNumber:x}";
public static string AppData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);

View File

@ -7,20 +7,19 @@ namespace dezentrale.model
{
[XmlAttribute] public string Name { get; set; } = "";
[XmlAttribute] public string Display { get; set; } = "";
[XmlAttribute] public bool Visible { get; set; } = true;
[XmlAttribute] public int Width { get; set; } = 80;
[XmlAttribute] public System.Windows.Forms.HorizontalAlignment TextAlign { get; set; } = System.Windows.Forms.HorizontalAlignment.Left;
public ConfigLVColumn() : base() { }
public ConfigLVColumn(ConfigLVColumn src)
{
this.Name = src.Name;
this.Display = src.Display;
this.Visible = src.Visible;
this.Width = src.Width;
this.TextAlign = src.TextAlign;
if (src != null)
{
this.Name = src.Name;
this.Visible = src.Visible;
this.Width = src.Width;
}
}
public bool Equals(ConfigLVColumn other)

View File

@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Serialization;
using dezentrale.model;
@ -11,8 +12,10 @@ namespace dezentrale.view
{
public class ConfigLVDataHandler : ConfigLVColumn
{
public Type DataType { get; set; } = typeof(string);
public bool FilterAvailable { get; set; } = false;
[XmlIgnore] public Type DataType { get; set; } = typeof(string);
[XmlIgnore] public bool FilterAvailable { get; set; } = false;
[XmlIgnore] public string Display { get; set; } = "";
[XmlIgnore] public System.Windows.Forms.HorizontalAlignment TextAlign { get; set; } = System.Windows.Forms.HorizontalAlignment.Left;
public delegate ListViewItem.ListViewSubItem ObjToLvsi(ListViewItem lvi, object input);
public delegate string ObjToString(object input);
@ -20,23 +23,24 @@ namespace dezentrale.view
//Delegates to be overwritten for custom data presentation.
//You have the option to overwrite the string generation and/or the generation of the ListViewSubItem itself (for custom lvsi settings, e.g. color dependent on data).
public ObjToLvsi CustomToLvsi { get; set; } = null;
public ObjToString CustomToString { get; set; } = (input => (input ?? "").ToString());
[XmlIgnore] public ObjToLvsi CustomToLvsi { get; set; } = null;
[XmlIgnore] public ObjToString CustomToString { get; set; } = (input => (input ?? "").ToString());
//Initialize CustomToLvsi with default handler to generate ListViewSubItems
public ConfigLVDataHandler()
{
CustomToLvsi = CustomToLvsi ?? ((lvi, o) => new ListViewItem.ListViewSubItem(lvi, CustomToString(o)));
}
public ConfigLVDataHandler(): this(null, null) { }
public ConfigLVDataHandler(ConfigLVColumn src, ConfigLVDataHandler def) : base(src)
{
this.DataType = def.DataType;
this.FilterAvailable = def.FilterAvailable;
this.CustomToLvsi = def.CustomToLvsi;
this.CustomToString = def.CustomToString;
CustomToLvsi = CustomToLvsi ?? ((lvi, o) => new ListViewItem.ListViewSubItem(lvi, CustomToString(o)));
if (def != null)
{
this.DataType = def.DataType;
this.FilterAvailable = def.FilterAvailable;
this.Display = def.Display;
this.TextAlign = def.TextAlign;
this.CustomToLvsi = def.CustomToLvsi;
this.CustomToString = def.CustomToString;
}
}
}
}

View File

@ -39,13 +39,6 @@ namespace dezentrale.view
}
if (col.Visible) this.Columns.Add(new ColumnHeader() { Width = col.Width, Text = col.Display, TextAlign = col.TextAlign, Tag = col, });
}
if (columnConfiguration)
{
internalColumns += 2;
cm.MenuItems.Add("-");
cm.MenuItems.Add("Configure columns...", mnuConfigColumns_Click);
}
}
public CustomListView(List<ConfigLVColumn> actualColumns, EventHandler<ColumnsChangedArgs> ColumnsChanged = null, bool checkBoxes = true, bool columnConfiguration = true) : base()
{
@ -57,33 +50,40 @@ namespace dezentrale.view
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) continue; //this is a column we don't support. Old version? Just throw away.
ConfigLVDataHandler copy = new ConfigLVDataHandler(lvc, def);
this.actualColumns.Add(copy);
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));
}
bool newCols = false;
foreach (ConfigLVColumn c in DefaultColumns)
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, act));
newCols = true;
this.actualColumns.Add(new ConfigLVDataHandler(c, c));
colsChanged = true;
}
}
BuildColumns();
if (columnConfiguration)
{
this.ColumnWidthChanged += CustomListView_ColumnWidthChanged;
if (newCols)
internalColumns += 2;
cm.MenuItems.Add("-");
cm.MenuItems.Add("Configure columns...", mnuConfigColumns_Click);
ColumnWidthChanged += CustomListView_ColumnWidthChanged;
if (colsChanged)
ColumnsChanged?.Invoke(this, new ColumnsChangedArgs() { Columns = this.actualColumns });
}
}
@ -91,11 +91,11 @@ namespace dezentrale.view
private void mnuConfigColumns_Click(object sender, EventArgs e)
{
frmConfigureLVColumns col = new frmConfigureLVColumns(actualColumns);
col.ShowDialog();
if (col.ColumnsChanged)
frmConfigureLVColumns colConfigure = new frmConfigureLVColumns(actualColumns);
colConfigure.ShowDialog();
if (colConfigure.ColumnsChanged)
{
ColumnsChangedArgs cca = new ColumnsChangedArgs() { Columns = col.GetLVColumnList() };
ColumnsChangedArgs cca = new ColumnsChangedArgs() { Columns = colConfigure.GetLVColumnList() };
ColumnsChanged?.Invoke(this, cca);
if (cca.Cancel) return;
actualColumns = cca.Columns;
@ -109,22 +109,19 @@ namespace dezentrale.view
{
ColumnHeader col = this.Columns[e.ColumnIndex];
ConfigLVDataHandler c = (ConfigLVDataHandler)col.Tag;
if (c != null)
if ((c != null) && (c.Width != col.Width))
{
if (c.Width != col.Width)
List<ConfigLVDataHandler> newList = new List<ConfigLVDataHandler>();
foreach (ConfigLVDataHandler lvc in actualColumns)
{
List<ConfigLVDataHandler> newList = new List<ConfigLVDataHandler>();
foreach (ConfigLVDataHandler lvc in actualColumns)
{
ConfigLVDataHandler c2 = new ConfigLVDataHandler(lvc, lvc);
if (c == lvc) c2.Width = col.Width;
newList.Add(c2);
}
ColumnsChangedArgs cca = new ColumnsChangedArgs() { Columns = newList };
ColumnsChanged?.Invoke(this, cca);
if (cca.Cancel) return;
actualColumns = cca.Columns;
ConfigLVDataHandler c2 = new ConfigLVDataHandler(lvc, lvc);
if (c.Name == lvc.Name) c2.Width = col.Width;
newList.Add(c2);
}
ColumnsChangedArgs cca = new ColumnsChangedArgs() { Columns = newList };
ColumnsChanged?.Invoke(this, cca);
if (cca.Cancel) return;
actualColumns = cca.Columns;
}
}

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using dezentrale.model;
namespace dezentrale.view
@ -16,7 +17,6 @@ namespace dezentrale.view
{
Name = "number",
Display = "Member",
Visible = true,
Width = 57, TextAlign = HorizontalAlignment.Right,
CustomToString = ( x => ((Member)x).NumberString),
},
@ -24,7 +24,6 @@ namespace dezentrale.view
{
Name = "nickname",
Display = "name / nickname",
Visible = true,
Width = 160,
CustomToString = ( x => (((Member)x).Nickname ?? "{((Member)x).FirstName} {((Member)x).LastName}") ),
},
@ -32,7 +31,6 @@ namespace dezentrale.view
{
Name = "type",
Display = "type",
Visible = true,
Width = 40,
CustomToString = ( x => (((Member)x).Type == Member.eType.Foerdermitglied ? "F" : "R") ),
},
@ -40,7 +38,6 @@ namespace dezentrale.view
{
Name = "status",
Display = "status",
Visible = true,
Width = 100,
CustomToLvsi = ((lvi, o) =>
@ -55,7 +52,6 @@ namespace dezentrale.view
{
Name = "mail",
Display = "mail",
Visible = true,
Width = 40,
CustomToString = ( x => ((Member)x).EMail.Length < 1 ? "" : (((Member)x).PgpFingerprint.Length < 1 ? "yes" : "pgp") ),
},
@ -70,63 +66,14 @@ namespace dezentrale.view
};
} }
//private List<Member.eStatus> StatusFilter = null;
public LVMembers() : base(Program.config.MemberListColumns, LVMembers_ColumnsChanged)
{
/*StatusFilter = new List<Member.eStatus>()
{
Member.eStatus.Uninitialized,
Member.eStatus.Greeted,
Member.eStatus.Active,
Member.eStatus.Bannend,
Member.eStatus.Disabled,
//Member.eStatus.Deleted,
};
MenuItem mnuStatusFilter = AddMenuItem("Filter by status",null, null, false);
foreach (Member.eStatus status in Enum.GetValues(typeof(Member.eStatus)))
{
MenuItem mi = AddMenuItem($"{status}", mnuStatusFilter_Click, mnuStatusFilter);
mi.Tag = status;
mi.Checked = StatusFilter.Contains(status);
}
this.Refresh();*/
}
public LVMembers() : base(Program.config.MemberListColumns, LVMembers_ColumnsChanged) { }
private static void LVMembers_ColumnsChanged(object sender, ColumnsChangedArgs e)
{
Console.WriteLine("LVMembers_ColumnsChanged");
Program.config.MemberListColumns.Clear();
foreach (ConfigLVDataHandler c in e.Columns) Program.config.MemberListColumns.Add(c);
foreach (ConfigLVDataHandler c in e.Columns) Program.config.MemberListColumns.Add(new ConfigLVColumn(c));
XmlData.SaveToFile(Program.ConfigFile, Program.config);
}
/*private void mnuStatusFilter_Click(object sender, EventArgs e)
{
MenuItem mi = (MenuItem)sender;
mi.Checked = !mi.Checked;
if (mi.Checked)
{
StatusFilter.Add((Member.eStatus)mi.Tag);
foreach(Member m in internalList)
{
if(m.Status == (Member.eStatus)mi.Tag)
this.Items.Add(UpdateLvi(new ListViewItem(), m));
}
}
else
{
StatusFilter.Remove((Member.eStatus)mi.Tag);
List<ListViewItem> toRemove = new List<ListViewItem>();
foreach(ListViewItem lvi in this.Items)
{
if (((Member)lvi.Tag).Status == (Member.eStatus)mi.Tag)
toRemove.Add(lvi);
}
foreach (ListViewItem lvi in toRemove)
this.Items.Remove(lvi);
}
}*/
}
}

View File

@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Windows.Forms;
using dezentrale.model;
@ -10,91 +8,107 @@ using dezentrale.model.money;
namespace dezentrale.view
{
public class LVMoneyTransfers : ListView
public class LVMoneyTransfers : Panel
{
private ContextMenu cm = new ContextMenu();
private List<string> moneyTransfersIds = null;
public LVMoneyTransfers(List<string> moneyTransfersIds = null)
class MT : CustomListView<MoneyTransfer>
{
this.moneyTransfersIds = moneyTransfersIds; //filter
this.View = View.Details; //This gives us a traditional "list" view.
//this.CheckBoxes = true;
this.FullRowSelect = true;
if(Program.config.MTListColumns.Count < 1)
protected override List<ConfigLVDataHandler> DefaultColumns
{
//fill
Program.config.MTListColumns.Add(new ConfigLVColumn() { Name = "id", Display = "Id", Width = 90, });
Program.config.MTListColumns.Add(new ConfigLVColumn() { Name = "number", Display = "Member", Width = 57, });
Program.config.MTListColumns.Add(new ConfigLVColumn() { Name = "type", Display = "Type", Width = 130, });
Program.config.MTListColumns.Add(new ConfigLVColumn() { Name = "date", Display = "Date", Width = 130, });
Program.config.MTListColumns.Add(new ConfigLVColumn() { Name = "amount", Display = "Amount", Width = 70, TextAlign = HorizontalAlignment.Right, });
XmlData.SaveToFile(Program.ConfigFile, Program.config);
}
this.Columns.Add(new ColumnHeader() { Text = "[x]", Width = 0 }); //Checkbox: hide
foreach (ConfigLVColumn col in Program.config.MTListColumns)
{
if (col.Visible)
this.Columns.Add(new ColumnHeader() { Width = col.Width, Text = col.Display, TextAlign = col.TextAlign, Tag = col, });
}
this.ContextMenu = cm;
LoadFromList();
}
private ListViewItem UpdateLvi(ListViewItem lvi, MoneyTransfer t)
{
if (lvi != null && t != null)
{
lvi.Tag = t;
lvi.SubItems.Clear();
foreach (ConfigLVColumn col in Program.config.MemberListColumns)
get
{
if (!col.Visible) continue;
switch (col.Name)
return new List<ConfigLVDataHandler>()
{
case "id": lvi.SubItems.Add(new ListViewItem.ListViewSubItem() { Text = $"{t.Id}" }); break;
case "number": lvi.SubItems.Add(new ListViewItem.ListViewSubItem() { Text = (t.MemberNumber > 0 ? $"{t.MemberNumber:D3}" : "-") }); break;
case "type": lvi.SubItems.Add(new ListViewItem.ListViewSubItem() { Text = $"{t.TransferType}" }); break;
case "date": lvi.SubItems.Add(new ListViewItem.ListViewSubItem() { Text = $"{t.ValutaDate}" }); break;
case "amount": lvi.SubItems.Add(new ListViewItem.ListViewSubItem() { Text = $"{((float)t.Amount / 100)} {t.Currency}" }); break;
default:
Console.WriteLine ($"LVMoneyTransfers(): Column \"{col.Name}\" not found - corrupt configuration data!");
throw new Exception($"LVMoneyTransfers(): Column \"{col.Name}\" not found - corrupt configuration data!");
}
new ConfigLVDataHandler()
{
Name = "id",
Display = "Id",
Width = 90,
CustomToString = ( x => ((MoneyTransfer)x).Id),
},
new ConfigLVDataHandler()
{
Name = "number",
Display = "Member",
Width = 57,
CustomToString = ( x => (((MoneyTransfer)x).MemberNumber > 0 ? $"{((MoneyTransfer)x).MemberNumber:D3}" : "-") ),
},
new ConfigLVDataHandler()
{
Name = "type",
Display = "Type",
Width = 130,
CustomToString = ( x => ($"{((MoneyTransfer)x).TransferType}") ),
//if (t.TransferType == MoneyTransfer.eTransferType.Unassigned) lvi.ForeColor = System.Drawing.Color.DarkRed;
//else lvi.ForeColor = System.Drawing.Color.Black;
},
new ConfigLVDataHandler()
{
Name = "date",
Display = "Date",
Width = 130,
CustomToString = ( x => (((MoneyTransfer)x).ValutaDate.ToString("yyyy-MM-dd")) ),
},
new ConfigLVDataHandler()
{
Name = "amount",
Display = "Amount",
Width = 70, TextAlign = HorizontalAlignment.Right,
CustomToString = ( x => $"{((MoneyTransfer)x).AmountString} {((MoneyTransfer)x).Currency}"),
},
};
}
if (t.TransferType == MoneyTransfer.eTransferType.Unassigned) lvi.ForeColor = System.Drawing.Color.DarkRed;
//else lvi.ForeColor = System.Drawing.Color.Black;
}
return lvi;
public MT() : base(Program.config.MTListColumns, LVMoneyTransfers_ColumnsChanged, false) { }
}
private ListViewItem GetExistingLvi(MoneyTransfer t)
{
foreach (ListViewItem lvi in this.Items) if (lvi.Tag == t) return lvi;
return null;
}
public void LoadFromList()
{
this.SuspendLayout();
this.Items.Clear();
if(Program.MoneyTransfersLoaded)
{
this.BackColor = System.Drawing.Color.White;
foreach (MoneyTransfer t in Program.MoneyTransfers.Entries)
{
if (moneyTransfersIds != null)
{
if (!moneyTransfersIds.Contains(t.Id)) continue;
}
this.Items.Add(UpdateLvi(new ListViewItem(), t));
}
} else
{
this.BackColor = System.Drawing.Color.DarkGray;
}
this.ResumeLayout(false);
private MT mT = new MT() { Dock = DockStyle.Fill, };
private Button btnLoadList = new Button()
{
Text = "Load money transfers from disk",
Anchor = AnchorStyles.None,
Size = new Size(250, 50),
};
public event EventHandler<LoadMoneyTransferArgs> LoadRequest;
public LVMoneyTransfers()
{
btnLoadList.Location = new Point((this.ClientSize.Width - 250) / 2, (this.ClientSize.Height - 50) / 2);
this.Controls.Add(btnLoadList);
this.Controls.Add(mT);
btnLoadList.Click += (sender, e) =>
{
LoadMoneyTransferArgs args = new LoadMoneyTransferArgs();
LoadRequest?.Invoke(this, args);
if (args.Cancel) return;
if (args.Transfers != null)
{
Console.WriteLine($"Loaded {args.Transfers.Count} Money transfers.");
LoadFromList(args.Transfers);
} //else it might be handled this from outside, and just use the event handler on button press
};
}
public MenuItem AddMenuItem(string text, EventHandler handler = null, MenuItem parent = null, bool enabled = true) { return mT.AddMenuItem(text,handler,parent,enabled); }
public void LoadFromList(List<MoneyTransfer> entries)
{
btnLoadList.Visible = false;
mT.LoadFromList(entries);
}
private static void LVMoneyTransfers_ColumnsChanged(object sender, ColumnsChangedArgs e)
{
Console.WriteLine("LVMoneyTransfers_ColumnsChanged");
Program.config.MTListColumns.Clear();
foreach (ConfigLVDataHandler c in e.Columns) Program.config.MTListColumns.Add(new ConfigLVColumn(c));
XmlData.SaveToFile(Program.ConfigFile, Program.config);
}
}
public class LoadMoneyTransferArgs
{
public List<MoneyTransfer> Transfers { get; set; } = null;
public bool Cancel { get; set; } = false;
}
}

View File

@ -57,7 +57,7 @@ namespace dezentrale.view
}
};
foreach (ConfigLVColumn col in allColumns)
foreach (ConfigLVDataHandler col in allColumns)
{
ListViewItem lvi;
columns.Items.Add(lvi = new ListViewItem()

View File

@ -6,7 +6,8 @@ using System.Text;
using System.Windows.Forms;
using dezentrale.model;
using dezentrale.model.money;
namespace dezentrale.view
{
public class frmEditEntry : Form
@ -399,31 +400,15 @@ namespace dezentrale.view
});
}
private void BuildMoneyTransfers(Control parent)
{
if(!Program.MoneyTransfersLoaded)
{
parent.Controls.Add(mtv = new LVMoneyTransfers() { Dock = DockStyle.Fill, });
if (member == null)
mtv.LoadFromList(new List<MoneyTransfer>());
else
{
Button LoadMT = new Button()
{
Text = "Load money transfers from disk",
Anchor = AnchorStyles.None,
Size = new Size(250, 50),
Location = new Point( (parent.ClientSize.Width - 250) / 2, (parent.ClientSize.Height - 50) / 2),
};
parent.Controls.Add(LoadMT);
LoadMT.Click += (sender, e) =>
{
Console.WriteLine($"Loaded {Program.MoneyTransfers.Entries.Count} Money transfers.");
mtv.LoadFromList();
LoadMT.Visible = false;
};
if (Program.MoneyTransfersLoaded) mtv.LoadFromList(Program.MoneyTransfers.Entries.FindAll(x => x.MemberNumber == member.Number));
else mtv.LoadRequest += (sender, e) => { e.Transfers = Program.MoneyTransfers.Entries.FindAll(x => x.MemberNumber == member.Number); };
}
List<string> mti = (member != null) ? member.MoneyTransfersIds : null;
parent.Controls.Add(mtv = new LVMoneyTransfers(mti)
{
Size = parent.ClientSize,
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
});
}
private void BuildLog(Control parent)
{

View File

@ -15,29 +15,9 @@ namespace dezentrale.view
private void BuildMoneyTransfers(Control parent)
{
if (!Program.MoneyTransfersLoaded)
{
Button LoadMT = new Button()
{
Text = "Load money transfers from disk",
Anchor = AnchorStyles.None,
Size = new Size(250, 50),
Location = new Point((parent.ClientSize.Width - 250) / 2, (parent.ClientSize.Height - 50) / 2),
};
parent.Controls.Add(LoadMT);
LoadMT.Click += (sender, e) =>
{
Console.WriteLine($"Loaded {Program.MoneyTransfers.Entries.Count} Money transfers.");
mtv.LoadFromList();
LoadMT.Visible = false;
};
}
parent.Controls.Add(mtv = new LVMoneyTransfers()
{
Size = parent.ClientSize,
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
});
parent.Controls.Add(mtv = new LVMoneyTransfers() { Dock = DockStyle.Fill, });
if (Program.MoneyTransfersLoaded) mtv.LoadFromList(Program.MoneyTransfers.Entries);
else mtv.LoadRequest += (sender, e) => { e.Transfers = Program.MoneyTransfers.Entries; };
}
public frmMain()
@ -283,7 +263,13 @@ namespace dezentrale.view
if (m != null)
{
frmEditEntry edit = new frmEditEntry(m);
bool mtvLoadedOld = Program.MoneyTransfersLoaded;
edit.ShowDialog();
if (!mtvLoadedOld && Program.MoneyTransfersLoaded) mtv.LoadFromList(Program.MoneyTransfers.Entries);
if (edit.DialogResult == DialogResult.OK)
{
//the edit window already updated the data in the member object