210206PX Changed FormWithOkCancel to FormWithActionButtons, more work on frmMv

This commit is contained in:
phantomix 2021-02-16 22:10:22 +01:00
parent 0dd7c66afd
commit 9b822de479
10 changed files with 339 additions and 88 deletions

View File

@ -10,7 +10,6 @@ namespace dezentrale.core
//! \short Data provider for the MV invitation process
public interface IMvInvitationData
{
bool GenerateAuthCode { get; }
string InviteHeadline { get; }
string InviteBody { get; }
DateTime EventDate { get; }
@ -72,10 +71,7 @@ namespace dezentrale.core
LogTarget.StepStarted(step, $"Sending mail for member {m.Nickname}");
m.StartLogEvent("MvInvitationProcess", LogEvent.eEventType.EMail, Program.config.LocalUser);
if(data.GenerateAuthCode)
{
m.MvAuthenticationCode = RandomString(10);
}
m.MvAuthenticationCode = RandomString(10);
m.MvEventDate = data.EventDate;
FormMail fm = new FormMail()

View File

@ -204,6 +204,8 @@
<Compile Include="model\MvList.cs" />
<Compile Include="model\Blob.cs" />
<Compile Include="view\LvMv.cs" />
<Compile Include="view\FormWithActionButtons.cs" />
<Compile Include="view\LvMvInvitations.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />

View File

@ -25,6 +25,8 @@ namespace dezentrale.model
[XmlElement("MemberListColumn")] public List<ConfigLVColumn> MemberListColumns { get; set; } = new List<ConfigLVColumn>();
[XmlElement("MTListColumn")] public List<ConfigLVColumn> MTListColumns { get; set; } = new List<ConfigLVColumn>();
[XmlElement("MvListColumn")] public List<ConfigLVColumn> MvListColumns { get; set; } = new List<ConfigLVColumn>();
[XmlElement("MvInvitationsListColumn")]
public List<ConfigLVColumn> MvInvitationsListColumns{ get; set; } = new List<ConfigLVColumn>();
[XmlElement] public List<KeyValue> MoneyTransferRegEx { get; set; } = new List<KeyValue>(); //This doesn't belong here! Move to new file within db-data!
[XmlElement] public DateTime LastCronjobRun { get; set; } = DateTime.Now; //This doesn't belong here! Move to new file within db-data!

View File

@ -1,15 +1,39 @@
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using dezentrale.core;
namespace dezentrale.model
{
public class MvInvitedMember
{
public int MemberNumber { get; set; }
public uint MemberNumber { get; set; }
public bool Invited { get; set; } = false;
public DateTime InvitationDate { get; set; }
public string AuthCode { get; set; } = "";
public bool AttendedMv { get; set; } = false;
[XmlIgnore] public string InvitedString { get { return Invited ? "Yes" : "No"; } }
private Member member = null;
[XmlIgnore] public Member Member
{
get
{
if(member == null)
{
member = Program.members.Find(MemberNumber);
}
return member;
}
}
public MvInvitedMember() { }
public MvInvitedMember(Member m)
{
member = m;
MemberNumber = m.Number;
}
}
public class Mv : XmlData, IMvInvitationData
@ -25,20 +49,77 @@ namespace dezentrale.model
public MvStatus Status { get; set; }
public DateTime EventDate { get; set; }
public string InviteHeadline { get; set; }
public string InviteBody { get; set; } //Todo: Generation on-the-fly
public string Introduction { get; set; }
public string Place { get; set; }
public bool GenerateAuthCode { get; set; }
public string Agenda { get; set; }
public string AdditionalInfo { get; set; }
public string InviteHeadline { get; set; }
public string InviteBody { get; set; }
public List<MvInvitedMember> Invited { get; set; } = new List<MvInvitedMember>();
public List<Blob> Attachments { get; set; } = new List<Blob>();
[XmlIgnore] public string AgendaNumberedString
{
get
{
string ret = "";
string[] AgendaPoints = Agenda.Split('\n');
for(int i = 1; i <= AgendaPoints.Length; i++)
{
if (ret.Length > 0) ret += '\n';
ret += $"{i}. {AgendaPoints[i-1]}";
}
return ret;
}
}
public FormMail BuildInvitation()
{
return null;
}
public void FillDefaults()
{
DateTime inTwoWeeks = DateTime.Now.Add(new TimeSpan(14, 0, 0, 0));
DateTime dtSuggested = inTwoWeeks.Hour < 15 ? inTwoWeeks : inTwoWeeks.Add(new TimeSpan(1, 0, 0, 0));
while (dtSuggested.DayOfWeek != DayOfWeek.Sunday)
dtSuggested = dtSuggested.Add(new TimeSpan(1, 0, 0, 0));
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"
+ "Feststellung der ordnungsgemäßen Einberufung\n"
+ "Feststellung der Beschlussfähigkeit\n"
+ "Genehmigung der Tagesordnung\n"
+ "Genehmigung des Protokolls der letzten Mitgliederversammlung\n"
+ "Berichte des Vorstandes\n"
+ "Entlastung des Vorstandes\n"
+ "Neuwahl des Vorstandes\n"
+ "Verschiedenes";
InviteHeadline = "Einladung zur Mitgliederversammlung des dezentrale e.V. am {EventDate}";
InviteBody = "Hallo {EMailName},\n\nhiermit möchte ich Dich als Mitglied\n"
+ "des dezentrale e.V. zur Mitgliederversammlung einladen.\n\n"
+ "Ort: {Place}\n"
+ "Datum und Uhrzeit: {EventDate}\n"
+ "Dein Authentifizierungscode: {MvAuthenticationCode}\n\n"
+ "Agenda:\n-------\n"
+ "{AgendaNumberedString}\n\n"
+ "Bitte denkt daran, dass für die Beschlussfähigkeit 51% der regulären Mitglieder vonnöten sind.\n\n"
+ "Liebe Grüße,\n\n\n"
+ $"{Program.config.LocalUser}";
}
public FormMail GetInvitationMail(Member m = null, string authCode = null)
{
FormMail fm = new FormMail()
{
Subject = this.InviteHeadline,
Body = this.InviteBody,
};
fm = fm.ReplaceReflect(this);
if(m != null) fm = fm.ReplaceReflect(m);
return fm;
}
}
}

View File

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace dezentrale.view
{
public class FormWithActionButtons : Form
{
protected const int margin = 5;
protected const int lm = margin; //Left margin
protected const int tm = margin; //Top margin
protected const int rm = 20; //Right margin
protected const int line = 20 + margin; //lineheight
protected const int labelHeight = 14;
protected const int labelOffs = 3;
protected List<Button> buttons = new List<Button>();
//protected Button btnOk, btnCancel;
protected Button AddButton(string text, EventHandler clickEvent, bool enabled = true)
{
//determine button width
int buttonWidth = 80;
//shift the old buttons to the left
foreach(Button btn in buttons)
{
btn.Left -= buttonWidth + margin;
}
//add new button to the right
Button b = new Button()
{
Text = text,
Location = new System.Drawing.Point(this.Width - buttonWidth - rm, this.Height - 57),
Width = buttonWidth,
Anchor = AnchorStyles.Right | AnchorStyles.Bottom,
Enabled = enabled,
};
buttons.Add(b);
this.Controls.Add(b);
if(clickEvent != null) b.Click += clickEvent;
return b;
}
protected void ClearButtons()
{
foreach(Button b in buttons)
{
this.Controls.Remove(b);
}
buttons.Clear();
}
}
}

View File

@ -7,40 +7,15 @@ using System.Windows.Forms;
namespace dezentrale.view
{
public class FormWithOkCancel : Form
[Obsolete("Use FormWithActionButtons directly")]
public class FormWithOkCancel : FormWithActionButtons
{
protected const int margin = 5;
protected const int lm = margin; //Left margin
protected const int tm = margin; //Top margin
protected const int rm = 20; //Right margin
protected const int line = 20 + margin; //lineheight
protected const int labelHeight = 14;
protected const int labelOffs = 3;
protected Button btnOk, btnCancel;
protected void AddOkCancel(Control parent, EventHandler okEvent, EventHandler cancelEvent, bool writeEnabled = true)
protected void AddOkCancel(EventHandler okEvent, EventHandler cancelEvent)
{
//Console.WriteLine($"frmMoneyTransfer.AddOkCancel(writeEnabled={writeEnabled})");
btnOk = new Button()
{
Text = "OK",
Location = new System.Drawing.Point(parent.Width - 160 - rm, parent.Height - 57),
Anchor = AnchorStyles.Right | AnchorStyles.Bottom,
Enabled = writeEnabled,
};
if (writeEnabled) btnOk.Click += okEvent;
btnCancel = new Button()
{
Text = "Cancel",
Location = new System.Drawing.Point(parent.Width - 75 - rm, parent.Height - 57),
Anchor = AnchorStyles.Right | AnchorStyles.Bottom,
};
btnCancel.Click += cancelEvent;
parent.Controls.Add(btnOk);
parent.Controls.Add(btnCancel);
btnOk = AddButton("OK", okEvent);
btnCancel = AddButton("Cancel", cancelEvent);
}
}
}

46
view/LvMvInvitations.cs Normal file
View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using dezentrale.model;
namespace dezentrale.view
{
public class LvMvInvitations : CustomListView<MvInvitedMember>
{
protected override List<ConfigLVDataHandler> DefaultColumns
{
get
{
return new List<ConfigLVDataHandler>()
{
new ConfigLVDataHandler()
{
Name = "invited",
Display = "Invited",
Width = 57, TextAlign = HorizontalAlignment.Right,
CustomToString = ( x => ((MvInvitedMember)x).InvitedString)),
},
new ConfigLVDataHandler()
{
Name = "date",
Display = "Date",
Width = 160,
CustomToString = ( x => (((MvInvitedMember)x).EventDate.ToString()) ),
},
};
}
}
public LvMvInvitations() : base(Program.config.MemberListColumns, LvMvInvitations_ColumnsChanged) { }
private static void LvMvInvitations_ColumnsChanged(object sender, ColumnsChangedArgs e)
{
Console.WriteLine("LvMvInvitations_ColumnsChanged");
Program.config.MvInvitationsListColumns.Clear();
foreach (ConfigLVDataHandler c in e.Columns) Program.config.MvInvitationsListColumns.Add(new ConfigLVColumn(c));
XmlData.SaveToFile(Program.ConfigFile, Program.config);
}
}
}

View File

@ -10,7 +10,7 @@ using dezentrale.model;
namespace dezentrale.view
{
public class frmConfiguration : FormWithOkCancel
public class frmConfiguration : FormWithActionButtons
{
//Generic settings
private TextBox tbDbDirectory;
@ -432,7 +432,8 @@ namespace dezentrale.view
BuildImportExportGui(),
}
});
AddOkCancel(this, btnOK_Click, btnCancel_Click);
AddButton("OK", btnOK_Click);
AddButton("Cancel", btnCancel_Click);
}
private void btnOK_Click(object sender, EventArgs e)
{

View File

@ -15,7 +15,7 @@ namespace dezentrale.view
* This form contains multiple tabs to handle the aspects of a
* MV, starting from invitation up to running the MV.
*/
public class frmMv : FormWithOkCancel
public class frmMv : FormWithActionButtons
{
private Mv mv;
private TabControl tabControl;
@ -41,6 +41,53 @@ namespace dezentrale.view
//textbox to hold an external MV protocol URL and/or
//[rich] textbox for MV protocol
//Button to finish MV
private TextBox tbPreviewHeadline;
private TextBox tbPreviewBody;
private void UpdateButtons()
{
ClearButtons();
switch(mv.Status)
{
case Mv.MvStatus.InPreparation:
AddButton("Refresh preview", null);
break;
case Mv.MvStatus.InvitationSent:
case Mv.MvStatus.Started:
case Mv.MvStatus.Ended:
case Mv.MvStatus.Cancelled:
break;
}
AddButton("Close", btnClose_Click);
}
private void RefreshPreview()
{
Console.WriteLine("frmMv.RefreshPreview()");
FormMail fm = mv.GetInvitationMail();
tbPreviewHeadline.Text = fm.Subject;
tbPreviewBody.Text = fm.Body;
//Console.WriteLine(mv.InviteHeadline);
//Console.WriteLine(mv.InviteBody);
}
private bool programmaticChange = true;
private void InvitationDataChanged(object sender, EventArgs e)
{
Console.WriteLine($"frmMv.InvitationDataChanged(): programmatic = {programmaticChange}");
if (programmaticChange) return;
if (sender == mvDate || sender == mvTime)
mv.EventDate = new DateTime( mvDate.Value.Year, mvDate.Value.Month, mvDate.Value.Day,
mvTime.Value.Hour, mvTime.Value.Minute, mvTime.Value.Second);
else if (sender == tbPlace) mv.Place = tbPlace.Text;
else if (sender == tbMvAgenda) mv.Agenda = tbMvAgenda.Text;
else if (sender == tbInviteHeadline) mv.InviteHeadline = tbInviteHeadline.Text;
else if (sender == tbInviteBody) mv.InviteBody = tbInviteBody.Text;
RefreshPreview();
}
private TabPage BuildPageInvitationSettings()
{
@ -68,9 +115,8 @@ namespace dezentrale.view
Format = DateTimePickerFormat.Time,
});
mvDate.Value = this.mv.EventDate;
mvTime.Value = this.mv.EventDate;
mvDate.ValueChanged += InvitationDataChanged;
mvTime.ValueChanged += InvitationDataChanged;
page.Controls.Add(new Label()
{
@ -83,9 +129,9 @@ namespace dezentrale.view
{
Location = new Point(lm + 113, 1 * line + tm),
Width = 580,
Text = "Räumlichkeiten des dezentrale e.V., Dreilindenstr. 19, 04177 Leipzig",
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
});
tbPlace.TextChanged += InvitationDataChanged;
page.Controls.Add(new Label()
{
@ -101,18 +147,9 @@ namespace dezentrale.view
Multiline = true,
ScrollBars = ScrollBars.Both,
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
Text = "Bestimmung des Versammlungsleiters sowie Protokollanten\n" +
"Feststellung der ordnungsgemäßen Einberufung\n" +
"Feststellung der Beschlussfähigkeit\n" +
"Genehmigung der Tagesordnung\n" +
"Genehmigung des Protokolls der letzten Mitgliederversammlung\n" +
"Berichte des Vorstandes\n" +
"Entlastung des Vorstandes\n" +
"Neuwahl des Vorstandes\n" +
"Verschiedenes",
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
});
tbMvAgenda.TextChanged += InvitationDataChanged;
page.Controls.Add(new Label()
{
@ -125,9 +162,10 @@ namespace dezentrale.view
{
Location = new Point(lm + 113, 10 * line + tm),
Width = 580,
Text = "Einladung zur Mitgliederversammlung des dezentrale e.V. am {EventDate}",
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
});
tbInviteHeadline.TextChanged += InvitationDataChanged;
page.Controls.Add(new Label()
{
Text = "Invitation Body:",
@ -142,32 +180,76 @@ namespace dezentrale.view
Multiline = true,
ScrollBars = ScrollBars.Both,
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
Text = "Hallo {EMailName},\n\nhiermit möchte ich Dich als Mitglied\n"
+ "des dezentrale e.V. zur Mitgliederversammlung einladen.\n\n"
+ "Ort: {Place}\n"
+ "Datum und Uhrzeit: {EventDate}\n"
+ "Dein Authentifizierungscode: {MvAuthenticationCode}\n\n"
+ "Agenda:\n-------\n"
+ "{AgendaNumberedString}\n\n"
+ "Bitte denkt daran, dass für die Beschlussfähigkeit 51% der regulären Mitglieder vonnöten sind.\n\n"
+ "Liebe Grüße,\n\n\n"
+ $"{Program.config.LocalUser}",
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
});
});
tbInviteBody.TextChanged += InvitationDataChanged;
return page;
}
private TabPage BuildPageMemberInvitation()
{
TabPage page = new TabPage("Member invitation");
SplitContainer split = new SplitContainer()
{
Dock = DockStyle.Fill,
};
page.Controls.Add(split);
GroupBox grpInvitations = new GroupBox()
{
Dock = DockStyle.Fill,
Text = "Invitations",
Width = 500,
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
};
split.Panel1.Controls.Add(grpInvitations);
GroupBox grpPreview = new GroupBox()
{
Location = new Point(300, 0),
Size = new Size(400, 600),
Text = "Testtext",
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
Dock = DockStyle.Fill,
Text = "Invitation mail preview",
Width = 500,
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
};
page.Controls.Add(grpPreview);
split.Panel2.Controls.Add(grpPreview);
grpInvitations.Controls.Add(null);
grpPreview.Controls.Add(new Label()
{
Text = "Subject:",
Location = new Point(lm, 1 * line + tm + labelOffs),
Size = new Size(110, labelHeight),
TextAlign = ContentAlignment.BottomRight,
});
grpPreview.Controls.Add(tbPreviewHeadline = new TextBox()
{
Location = new Point(lm + 113, 1 * line + tm),
Width = 340,
ReadOnly = true,
BackColor = Color.LightGray,
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
});
/*grpPreview.Controls.Add(new Label()
{
Text = "Body:",
Location = new Point(lm, 2 * line + tm + labelOffs),
Size = new Size(110, labelHeight),
TextAlign = ContentAlignment.BottomRight,
});*/
grpPreview.Controls.Add(tbPreviewBody = new TextBox()
{
Location = new Point(8, 2 * line + tm),
Size = new Size(452, 440),
Multiline = true,
ScrollBars = ScrollBars.Both,
ReadOnly = true,
BackColor = Color.LightGray,
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
//Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
});
return page;
}
@ -182,11 +264,12 @@ namespace dezentrale.view
{
DialogResult = DialogResult.Cancel;
this.StartPosition = FormStartPosition.CenterParent;
this.Size = new System.Drawing.Size(730, 600);
this.Size = new System.Drawing.Size(742, 600);
this.Text = "dezentrale-members :: Send MV invitation";
this.Controls.Add(tabControl = new TabControl()
{
Size = new System.Drawing.Size(this.Width - 16, this.Height - 95),
Location = new Point(8, 0),
Size = new System.Drawing.Size(this.Width - 28, this.Height - 65),
TabPages =
{
BuildPageInvitationSettings(),
@ -196,7 +279,17 @@ namespace dezentrale.view
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
});
AddOkCancel(this, btnOK_Click, btnCancel_Click);
//Setup all controls values
mvDate.Value = this.mv.EventDate;
mvTime.Value = this.mv.EventDate;
tbPlace.Text = this.mv.Place;
tbMvAgenda.Text = this.mv.Agenda;
tbInviteHeadline.Text = this.mv.InviteHeadline;
tbInviteBody.Text = this.mv.InviteBody;
UpdateButtons();
programmaticChange = false;
RefreshPreview();
}
public frmMv(Mv mv)
{
@ -206,12 +299,7 @@ namespace dezentrale.view
public frmMv()
{
this.mv = new Mv();
DateTime inTwoWeeks = DateTime.Now.Add(new TimeSpan(14, 0, 0, 0));
DateTime dtSuggested = inTwoWeeks.Hour < 15 ? inTwoWeeks : inTwoWeeks.Add(new TimeSpan(1, 0, 0, 0));
while (dtSuggested.DayOfWeek != DayOfWeek.Sunday)
dtSuggested = dtSuggested.Add(new TimeSpan(1, 0, 0, 0));
this.mv.EventDate = new DateTime(dtSuggested.Year, dtSuggested.Month, dtSuggested.Day, 15, 0, 0);
this.mv.FillDefaults();
Init();
}
@ -226,7 +314,7 @@ namespace dezentrale.view
return agenda;
}
private void btnOK_Click(object sender, EventArgs e)
private void btnClose_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
/*

View File

@ -29,7 +29,7 @@ namespace dezentrale.view
base.WndProc(ref m);
}
}
public class frmPaymentReceipts : FormWithOkCancel, IPaymentReceiptProcessData
public class frmPaymentReceipts : FormWithActionButtons, IPaymentReceiptProcessData
{
public List<Member> MemberList { get; set; } = null;
public bool AllMembers { get; set; } = false;
@ -55,8 +55,13 @@ namespace dezentrale.view
private CheckBox chkSendEmail;
private CheckBox chkWriteProtectPdf;
private Button btnOk;
public frmPaymentReceipts()
{
btnOk = AddButton("OK", btnOK_Click);
AddButton("Cancel", btnCancel_Click);
DialogResult = DialogResult.Cancel;
this.StartPosition = FormStartPosition.CenterParent;
this.Size = new System.Drawing.Size(483, 320);
@ -215,8 +220,6 @@ namespace dezentrale.view
Location = new Point(lm + 113, 9 * line + tm),
});
AddOkCancel(this, btnOK_Click, btnCancel_Click);
//We must run the filling of the data fields in the load event, as they
//might have been changed after the constructor is executed
this.Load += (sender, e) =>