210313PX Multiple changes:

Moved logging to a generic XmlLog.cs in order to use it for multiple object types
Renamed "LoadingFromFile" to a more meaningful "SuppressAllLogging"
Added a second "SuppressLogging" to control logging more granular & cleanly
Refactored the frmMv gui code a lot, added Log view
This commit is contained in:
phantomix 2021-03-14 00:02:15 +01:00
parent 4b88de2d15
commit dc77c0c4f7
9 changed files with 165 additions and 113 deletions

View File

@ -206,6 +206,7 @@
<Compile Include="view\LvMv.cs" />
<Compile Include="view\FormWithActionButtons.cs" />
<Compile Include="view\LvMvInvitations.cs" />
<Compile Include="model\XmlLog.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />

View File

@ -125,8 +125,6 @@ namespace dezentrale.model
[XmlElement("MoneyTransferId")] public List<string> MoneyTransfersIds { get; set; } = new List<string>();
[XmlElement("LogEvent")] public List<LogEvent> Log { get; set; } = new List<LogEvent>();
[XmlIgnore] public string AccountBalanceString { get { return $"{((float)accountBalance / 100)}"; } }
[XmlIgnore] public string PaymentAmountString { get { return $"{((float)paymentAmount / 100)}"; } }
@ -144,8 +142,7 @@ namespace dezentrale.model
else
return dueMonth.ToString("yyyy-MM");
}
}
[XmlIgnore] public LogEvent CurrentLog { get; set; } = null;
}
public Member() { }
public Member(uint number)
@ -165,39 +162,6 @@ namespace dezentrale.model
else return number.CompareTo(other.Number);
}
public LogEvent StartLogEvent(string topic, LogEvent.eEventType type, string user = null)
{
FinishLogEvent();
CurrentLog = new LogEvent()
{
Topic = topic,
Type = type,
LocalUser = user ?? Program.config.LocalUser,
};
Log.Add(CurrentLog);
return CurrentLog;
}
private void LogPropertyChange(string propertyName, object oldValue, object newValue)
{
if (CurrentLog == null)
{
if (MemberList.LoadingFromFile) return;
CurrentLog = StartLogEvent($"DataChange, starting with {propertyName}", LogEvent.eEventType.DataChange);
}
string ov = oldValue.ToString();
string nv = newValue.ToString();
if (!ov.Equals(nv))
CurrentLog.SubEvents.Add(new LogSubEvent()
{
Topic = $"{propertyName} changes from \"{oldValue.ToString()}\" to \"{newValue.ToString()}\"",
Type = LogEvent.eEventType.DataChange,
});
}
public void FinishLogEvent()
{
CurrentLog = null;
}
public bool SaveToFile(bool finishLog = true)
{
if (finishLog) FinishLogEvent();

View File

@ -6,8 +6,6 @@ namespace dezentrale.model
{
public class MemberList
{
public static bool LoadingFromFile { get; private set; } = false;
public List<Member> Entries { get; set; } = new List<Member>();
public uint GetFreeNumber()
@ -47,15 +45,7 @@ namespace dezentrale.model
MemberList ml = new MemberList();
foreach (string file in memberFiles)
{
try
{
LoadingFromFile = true;
ml.Entries.Add((Member)XmlData.LoadFromFile(file, typeof(Member)));
} catch(Exception ex)
{
LoadingFromFile = false;
throw ex;
}
ml.Entries.Add((Member)XmlData.LoadFromFile(file, typeof(Member)));
}
ml.Entries.Sort();
return ml;
@ -76,12 +66,12 @@ namespace dezentrale.model
{
Entries.Clear();
Member m;
MemberList.LoadingFromFile = true;
try
{
//the brackets are unnecessary but keep everything tidy.
m = CreateMember(true);
{
m.SuppressLogging = true;
m.Role = Member.eRole.Schatzmeister;
m.Type = Member.eType.Regulaer;
m.Status = Member.eStatus.Active;
@ -105,10 +95,12 @@ namespace dezentrale.model
m.PaymentClass = Member.ePaymentClass.Reduced;
m.PaymentAmount = 995;
m.MemberFormDate = new DateTime(2019, 5, 1);
m.SuppressLogging = false;
}
m = CreateMember(true);
{
m.SuppressLogging = true;
m.Role = Member.eRole.Vorstandsvorsitzender;
m.Type = Member.eType.Regulaer;
m.Status = Member.eStatus.Active;
@ -130,10 +122,12 @@ namespace dezentrale.model
m.PaymentClass = Member.ePaymentClass.Normal;
m.PaymentAmount = 6400;
m.MemberFormDate = new DateTime(2019, 5, 1);
m.SuppressLogging = false;
}
m = CreateMember(true);
{
m.SuppressLogging = true;
m.Role = Member.eRole.Normal;
m.Type = Member.eType.Regulaer;
m.Status = Member.eStatus.Uninitialized;
@ -155,10 +149,12 @@ namespace dezentrale.model
m.PaymentClass = Member.ePaymentClass.Normal;
m.PaymentAmount = 2305;
m.MemberFormDate = new DateTime(2019, 5, 23);
m.SuppressLogging = false;
}
m = CreateMember(true);
{
m.SuppressLogging = true;
m.Role = Member.eRole.Normal;
m.Type = Member.eType.Regulaer;
m.Status = Member.eStatus.Greeted;
@ -180,10 +176,12 @@ namespace dezentrale.model
m.PaymentClass = Member.ePaymentClass.Normal;
m.PaymentAmount = 3200;
m.MemberFormDate = new DateTime(2019, 5, 1);
m.SuppressLogging = false;
}
m = CreateMember(true);
{
m.SuppressLogging = true;
m.Role = Member.eRole.Normal;
m.Type = Member.eType.Regulaer;
m.Remarks = "";
@ -204,14 +202,13 @@ namespace dezentrale.model
m.PaymentClass = Member.ePaymentClass.Normal;
m.PaymentAmount = 3200;
m.MemberFormDate = new DateTime(2019, 5, 1);
m.SuppressLogging = false;
}
SaveToFiles();
} catch(Exception ex)
{
MemberList.LoadingFromFile = false;
throw ex;
}
MemberList.LoadingFromFile = false;
}
#endif
}

View File

@ -37,7 +37,7 @@ namespace dezentrale.model
}
}
public class Mv : IMvInvitationData
public class Mv : XmlLog, IMvInvitationData
{
public enum MvStatus
{
@ -48,12 +48,19 @@ namespace dezentrale.model
Cancelled = 0xFF,
}
[XmlAttribute] public MvStatus Status { get; set; }
[XmlAttribute] public DateTime EventDate { get; set; }
[XmlElement] public string Place { get; set; }
[XmlElement] public string Agenda { get; set; }
[XmlElement] public string InviteHeadline { get; set; }
[XmlElement] public string InviteBody { get; set; }
private MvStatus status = MvStatus.InPreparation;
private DateTime eventDate;
private string place = "";
private string agenda = "";
private string inviteHeadline = "";
private string inviteBody = "";
[XmlAttribute] public MvStatus Status { get { return status; } set { LogPropertyChange("Status", status, value); status = value; } }
[XmlAttribute] public DateTime EventDate { get { return eventDate; } set { LogPropertyChange("EventDate", eventDate, value); eventDate = value; } }
[XmlElement] public string Place { get { return place; } set { LogPropertyChange("Place", place, value); place = value; } }
[XmlElement] public string Agenda { get { return agenda; } set { LogPropertyChange("Agenda", agenda, value); agenda = value; } }
[XmlElement] public string InviteHeadline { get { return inviteHeadline; } set { LogPropertyChange("InviteHeadline", inviteHeadline, value); inviteHeadline = value; } }
[XmlElement] public string InviteBody { get { return inviteBody; } set { LogPropertyChange("InviteBody", inviteBody, value); inviteBody = value; } }
[XmlElement] public List<MvInvitedMember> Members { get; set; } = new List<MvInvitedMember>();
[XmlElement] public List<Blob> Attachments { get; set; } = new List<Blob>();
@ -84,7 +91,7 @@ namespace dezentrale.model
while (dtSuggested.DayOfWeek != DayOfWeek.Sunday)
dtSuggested = dtSuggested.Add(new TimeSpan(1, 0, 0, 0));
Status = MvStatus.InPreparation;
EventDate = new DateTime(dtSuggested.Year, dtSuggested.Month, dtSuggested.Day, 15, 0, 0);
Place = "Räumlichkeiten des dezentrale e.V., Dreilindenstr. 19, 04177 Leipzig";
Agenda = "Bestimmung des Versammlungsleiters sowie Protokollanten\n"
@ -114,7 +121,6 @@ namespace dezentrale.model
+ " regulärem Mitglied am Anfang jeder MV. Fördermitglieder stimmen nicht\n"
+ " mit ab und fallen daher aus dem Quorum (51%) raus. Der Vorstand kann\n"
+ " Auskunft über Deinen Mitgliedsstatus geben.";
}
public FormMail GetInvitationMail(Member m = null, string authCode = null)

View File

@ -7,7 +7,7 @@ using System.Xml.Serialization;
namespace dezentrale.model
{
public class XmlData
public class XmlData : XmlLog
{
[XmlAttribute] public DateTime LastChanged { get; set; } = DateTime.Now;
[XmlAttribute] public string ProgramVersion { get; set; } = "";
@ -49,7 +49,11 @@ namespace dezentrale.model
XmlSerializer ser = new XmlSerializer(type ?? typeof(XmlData));
fs = new FileStream(fileName, FileMode.Open);
XmlLog.SuppressAllLogging = true;
XmlData ds = (XmlData)ser.Deserialize(fs);
XmlLog.SuppressAllLogging = false;
fs.Close();
if (ds.ProgramVersion != Program.VersionString)
{
@ -67,7 +71,8 @@ namespace dezentrale.model
return ds;
}
catch (Exception e)
{
{
XmlLog.SuppressAllLogging = false;
fs?.Close();
throw e.InnerException ?? e;
}

50
model/XmlLog.cs Normal file
View File

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
namespace dezentrale.model
{
public class XmlLog
{
public static bool SuppressAllLogging { get; set; } = false;
[XmlIgnore] public bool SuppressLogging { get; set; } = false;
[XmlElement("LogEvent")] public List<LogEvent> Log { get; set; } = new List<LogEvent>();
[XmlIgnore] public LogEvent CurrentLog { get; set; } = null;
public LogEvent StartLogEvent(string topic, LogEvent.eEventType type, string user = null)
{
FinishLogEvent();
CurrentLog = new LogEvent()
{
Topic = topic,
Type = type,
LocalUser = user ?? Program.config.LocalUser,
};
Log.Add(CurrentLog);
return CurrentLog;
}
protected void LogPropertyChange(string propertyName, object oldValue, object newValue)
{
if (XmlLog.SuppressAllLogging || SuppressLogging) return;
if (CurrentLog == null)
{
CurrentLog = StartLogEvent($"DataChange, starting with {propertyName}", LogEvent.eEventType.DataChange);
}
string ov = oldValue.ToString();
string nv = newValue.ToString();
if (!ov.Equals(nv))
CurrentLog.SubEvents.Add(new LogSubEvent()
{
Topic = $"{propertyName} changes from \"{oldValue.ToString()}\" to \"{newValue.ToString()}\"",
Type = LogEvent.eEventType.DataChange,
});
}
public void FinishLogEvent()
{
CurrentLog = null;
}
}
}

View File

@ -5,7 +5,7 @@ using System.Windows.Forms;
namespace dezentrale.view
{
//Todo: Transform into user control to be able to position & use it like a toolbar
public class FormWithActionButtons : Form
{
protected const int margin = 5;

View File

@ -483,6 +483,8 @@ namespace dezentrale.view
{
int w = parent.ClientSize.Width;
int h = parent.ClientSize.Height - 35;
int tabw = w - 5, tabh = h - 25;
TabControl tc = new TabControl()
{
Size = new Size(w, h),
@ -493,22 +495,22 @@ namespace dezentrale.view
new TabPage()
{
Text = "Member form",
ClientSize = new Size(w - 5, h - 25),
ClientSize = new Size(tabw, tabh),
},
new TabPage()
{
Text = "Metadata",
ClientSize = new Size(w - 5, h - 25),
ClientSize = new Size(tabw, tabh),
},
new TabPage()
{
Text = "Money transfers",
ClientSize = new Size(w - 5, h - 25),
ClientSize = new Size(tabw, tabh),
},
new TabPage()
{
Text = "Log",
ClientSize = new Size(w - 5, h - 25),
ClientSize = new Size(tabw, tabh),
}
}
};

View File

@ -45,6 +45,8 @@ namespace dezentrale.view
private TextBox tbPreviewHeadline;
private TextBox tbPreviewBody;
private TabPage tabLog;
//! \brief UpdateGui() will refresh the GUI components for this
//! form according to the current MV state and visible
//! GUI tab. Having this centralized in one function is
@ -118,25 +120,23 @@ namespace dezentrale.view
RefreshPreview();
}
private TabPage BuildPageInvitationSettings()
private void BuildPageInvitationSettings(Control parent)
{
TabPage page = new TabPage("Invitation Settings");
page.Controls.Add(new Label()
parent.Controls.Add(new Label()
{
Text = "Event date+time:",
Location = new Point(lm, 0 * line + tm + labelOffs),
Size = new Size(110, labelHeight),
TextAlign = ContentAlignment.BottomRight,
});
page.Controls.Add(mvDate = new DateTimePicker()
parent.Controls.Add(mvDate = new DateTimePicker()
{
Location = new Point(lm + 113, 0 * line + tm),
Width = 110,
Anchor = AnchorStyles.Top | AnchorStyles.Left,
Format = DateTimePickerFormat.Short,
});
page.Controls.Add(mvTime = new DateTimePicker()
parent.Controls.Add(mvTime = new DateTimePicker()
{
Location = new Point(lm + 243, 0 * line + tm),
Width = 90,
@ -147,14 +147,14 @@ namespace dezentrale.view
mvDate.ValueChanged += InvitationDataChanged;
mvTime.ValueChanged += InvitationDataChanged;
page.Controls.Add(new Label()
parent.Controls.Add(new Label()
{
Text = "Place:",
Location = new Point(lm, 1 * line + tm + labelOffs),
Size = new Size(110, labelHeight),
TextAlign = ContentAlignment.BottomRight,
});
page.Controls.Add(tbPlace = new TextBox()
parent.Controls.Add(tbPlace = new TextBox()
{
Location = new Point(lm + 113, 1 * line + tm),
Width = 580,
@ -162,14 +162,14 @@ namespace dezentrale.view
});
tbPlace.TextChanged += InvitationDataChanged;
page.Controls.Add(new Label()
parent.Controls.Add(new Label()
{
Text = "Agenda (one item per line, auto-numbered:",
Location = new Point(lm, 2 * line + tm + labelOffs),
Size = new Size(320, labelHeight),
TextAlign = ContentAlignment.BottomRight,
});
page.Controls.Add(tbMvAgenda = new TextBox()
parent.Controls.Add(tbMvAgenda = new TextBox()
{
Location = new Point(0, 3 * line + tm),
Size = new Size(700, 160),
@ -180,14 +180,14 @@ namespace dezentrale.view
});
tbMvAgenda.TextChanged += InvitationDataChanged;
page.Controls.Add(new Label()
parent.Controls.Add(new Label()
{
Text = "Headline:",
Location = new Point(lm, 10 * line + tm + labelOffs),
Size = new Size(110, labelHeight),
TextAlign = ContentAlignment.BottomRight,
});
page.Controls.Add(tbInviteHeadline = new TextBox()
parent.Controls.Add(tbInviteHeadline = new TextBox()
{
Location = new Point(lm + 113, 10 * line + tm),
Width = 580,
@ -195,14 +195,14 @@ namespace dezentrale.view
});
tbInviteHeadline.TextChanged += InvitationDataChanged;
page.Controls.Add(new Label()
parent.Controls.Add(new Label()
{
Text = "Invitation Body:",
Location = new Point(lm, 11 * line + tm + labelOffs),
Size = new Size(110, labelHeight),
TextAlign = ContentAlignment.BottomRight,
});
page.Controls.Add(tbInviteBody = new TextBox()
parent.Controls.Add(tbInviteBody = new TextBox()
{
Location = new Point(0, 12 * line + tm),
Size = new Size(700, 160),
@ -212,17 +212,15 @@ namespace dezentrale.view
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
});
tbInviteBody.TextChanged += InvitationDataChanged;
return page;
}
private TabPage BuildPageMemberInvitation()
private void BuildPageMemberInvitation(Control parent)
{
TabPage page = new TabPage("Member invitation");
SplitContainer split = new SplitContainer()
{
Dock = DockStyle.Fill,
};
page.Controls.Add(split);
parent.Controls.Add(split);
GroupBox grpInvitations = new GroupBox()
{
@ -285,34 +283,72 @@ namespace dezentrale.view
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
});
return page;
}
private TabPage BuildPageRunningMv()
private void BuildPageRunningMv(Control parent)
{
TabPage page = new TabPage("Running MV");
return page;
}
private void BuildLog(Control parent)
{
parent.Controls.Add(new LogView(mv.Log)
{
Size = parent.ClientSize,
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
});
}
private void BuildGui(Control parent)
{
int w = parent.ClientSize.Width;
int h = parent.ClientSize.Height - 35;
int tabw = w - 5, tabh = h - 25;
tabControl = new TabControl()
{
Size = new Size(w, h),
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
TabPages =
{
(tabInvitationSettings = new TabPage()
{
Text = "Invitation settings",
ClientSize = new Size(tabw, tabh),
}),
(tabMemberInvitation = new TabPage()
{
Text = "Member invitation",
ClientSize = new Size(tabw, tabh),
}),
(tabRunningMv = new TabPage()
{
Text = "Running MV",
ClientSize = new Size(tabw, tabh),
}),
(tabLog = new TabPage()
{
Text = "Log",
ClientSize = new Size(tabw, tabh),
}),
}
};
parent.Controls.Add(tabControl);
BuildPageInvitationSettings(tabControl.TabPages[0]);
BuildPageMemberInvitation(tabControl.TabPages[1]);
BuildPageRunningMv(tabControl.TabPages[2]);
BuildLog(tabControl.TabPages[3]);
}
private void Init()
{
DialogResult = DialogResult.Cancel;
this.StartPosition = FormStartPosition.CenterParent;
this.Size = new System.Drawing.Size(742, 600);
this.Text = "dezentrale-members :: Send MV invitation";
this.Controls.Add(tabControl = new TabControl()
{
Location = new Point(8, 0),
Size = new System.Drawing.Size(this.Width - 28, this.Height - 65),
TabPages =
{
( tabInvitationSettings = BuildPageInvitationSettings() ),
( tabMemberInvitation = BuildPageMemberInvitation() ),
( tabRunningMv = BuildPageRunningMv() ),
},
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
});
this.Text = "dezentrale-members :: MV administration";
BuildGui(this);
//In order to update the tool buttons etc, we need to call UpdateGui() here
tabControl.SelectedIndexChanged += (sender, e) => { UpdateGui(); };
@ -366,21 +402,12 @@ namespace dezentrale.view
public frmMv()
{
this.mv = new Mv();
this.mv.SuppressLogging = true;
this.mv.FillDefaults();
this.mv.SuppressLogging = false;
Init();
}
private string GenerateAgenda()
{
string agenda = "Tagesordnung:\n";
string[] items = tbMvAgenda.Text.Split('\n');
for(int i = 0; i < items.Length; i++)
{
agenda += $"{i + 1}. {items[i]}\n";
}
return agenda;
}
private void btnClose_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;