Added a multi-line state to the text elements

This commit is contained in:
Thorsten Sommer 2022-09-17 19:23:11 +02:00
parent 72aa94bed5
commit 0aeec1885f
Signed by: tsommer
GPG Key ID: 371BBA77A02C0108
13 changed files with 361 additions and 29 deletions

View File

@ -47,6 +47,7 @@ public sealed class DataContext : DbContext, IDataContext
modelBuilder.Entity<TextElement>().HasIndex(n => n.Id);
modelBuilder.Entity<TextElement>().HasIndex(n => n.Code);
modelBuilder.Entity<TextElement>().HasIndex(n => n.Name);
modelBuilder.Entity<TextElement>().HasIndex(n => n.IsMultiLine);
modelBuilder.Entity<TextElement>().Navigation(n => n.Section).AutoInclude();
#endregion

View File

@ -11,6 +11,8 @@ public sealed class TextElement
public string Code { get; set; } = string.Empty;
public bool IsMultiLine { get; set; } = false;
public Section Section { get; set; }
public List<Translation> Translations { get; set; } = new();

View File

@ -0,0 +1,206 @@
// <auto-generated />
using System;
using DataModel.Database.Common;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace DataModel.Migrations
{
[DbContext(typeof(DataContext))]
[Migration("20220917132808_202209AddMultiLineOption")]
partial class _202209AddMultiLineOption
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.9");
modelBuilder.Entity("DataModel.Database.Section", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("DataKey")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("Depth")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int?>("ParentId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("DataKey");
b.HasIndex("Depth");
b.HasIndex("Id");
b.HasIndex("Name");
b.HasIndex("ParentId");
b.ToTable("Sections");
});
modelBuilder.Entity("DataModel.Database.Setting", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("BoolValue")
.HasColumnType("INTEGER");
b.Property<string>("Code")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("GuidValue")
.HasColumnType("TEXT");
b.Property<int>("IntegerValue")
.HasColumnType("INTEGER");
b.Property<string>("TextValue")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("BoolValue");
b.HasIndex("Code")
.IsUnique();
b.HasIndex("GuidValue");
b.HasIndex("Id");
b.HasIndex("IntegerValue");
b.HasIndex("TextValue");
b.ToTable("Settings");
});
modelBuilder.Entity("DataModel.Database.TextElement", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Code")
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("IsMultiLine")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("SectionId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("Code");
b.HasIndex("Id");
b.HasIndex("IsMultiLine");
b.HasIndex("Name");
b.HasIndex("SectionId");
b.ToTable("TextElements");
});
modelBuilder.Entity("DataModel.Database.Translation", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Culture")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Text")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("TextElementId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("Culture");
b.HasIndex("Id");
b.HasIndex("Text");
b.HasIndex("TextElementId");
b.ToTable("Translations");
});
modelBuilder.Entity("DataModel.Database.Section", b =>
{
b.HasOne("DataModel.Database.Section", "Parent")
.WithMany()
.HasForeignKey("ParentId");
b.Navigation("Parent");
});
modelBuilder.Entity("DataModel.Database.TextElement", b =>
{
b.HasOne("DataModel.Database.Section", "Section")
.WithMany("TextElements")
.HasForeignKey("SectionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Section");
});
modelBuilder.Entity("DataModel.Database.Translation", b =>
{
b.HasOne("DataModel.Database.TextElement", "TextElement")
.WithMany("Translations")
.HasForeignKey("TextElementId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("TextElement");
});
modelBuilder.Entity("DataModel.Database.Section", b =>
{
b.Navigation("TextElements");
});
modelBuilder.Entity("DataModel.Database.TextElement", b =>
{
b.Navigation("Translations");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,35 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace DataModel.Migrations
{
public partial class _202209AddMultiLineOption : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "IsMultiLine",
table: "TextElements",
type: "INTEGER",
nullable: false,
defaultValue: false);
migrationBuilder.CreateIndex(
name: "IX_TextElements_IsMultiLine",
table: "TextElements",
column: "IsMultiLine");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_TextElements_IsMultiLine",
table: "TextElements");
migrationBuilder.DropColumn(
name: "IsMultiLine",
table: "TextElements");
}
}
}

View File

@ -15,7 +15,7 @@ namespace DataModel.Migrations
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.5");
modelBuilder.HasAnnotation("ProductVersion", "6.0.9");
modelBuilder.Entity("DataModel.Database.Section", b =>
{
@ -103,6 +103,9 @@ namespace DataModel.Migrations
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("IsMultiLine")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
@ -116,6 +119,8 @@ namespace DataModel.Migrations
b.HasIndex("Id");
b.HasIndex("IsMultiLine");
b.HasIndex("Name");
b.HasIndex("SectionId");

View File

@ -26,7 +26,7 @@ public static class TextElementProcessor
}
// Adds a new text element:
public static async Task<ProcessorResult<TextElement>> AddTextElement(string? currentSectionKey, string elementName)
public static async Task<ProcessorResult<TextElement>> AddTextElement(string? currentSectionKey, string elementName, bool isMultiLine)
{
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
@ -45,6 +45,7 @@ public static class TextElementProcessor
Name = elementName,
Code = code,
Section = currentSection,
IsMultiLine = isMultiLine,
};
// Add the new element to the database:
@ -62,15 +63,31 @@ public static class TextElementProcessor
}
}
// Renames a text element:
public static async Task<ProcessorResult<TextElement>> RenameTextElement(int id, string newName)
// Updates the multi-line flag of a text element:
public static async Task<ProcessorResult<TextElement>> UpdateTextElementState(int id, bool isMultiLine)
{
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
var textElement = await db.TextElements.FirstAsync(n => n.Id == id);
if (textElement is null)
throw new ArgumentOutOfRangeException(nameof(id));
textElement.IsMultiLine = isMultiLine;
try
{
// Save the changes:
await db.SaveChangesAsync();
return new ProcessorResult<TextElement>(textElement);
}
catch (DbUpdateException updateException)
{
return updateException.ToProcessorResult<TextElement>();
}
}
// Renames a text element:
public static async Task<ProcessorResult<TextElement>> RenameTextElement(int id, string newName, bool isMultiLine)
{
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
var textElement = await db.TextElements.FirstAsync(n => n.Id == id);
// Get the corresponding section:
var section = (await db.TextElements.FirstAsync(n => n.Id == id)).Section;
@ -79,6 +96,7 @@ public static class TextElementProcessor
textElement.Name = newName;
textElement.Code = code;
textElement.IsMultiLine = isMultiLine;
// Save the changes:
try

View File

@ -40,6 +40,7 @@
this.listTextElements = new System.Windows.Forms.ListView();
this.column = new System.Windows.Forms.ColumnHeader();
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.buttonChangeMultiLine = new System.Windows.Forms.Button();
this.tableLayout.SuspendLayout();
this.flowLayoutToolbar.SuspendLayout();
this.SuspendLayout();
@ -62,7 +63,7 @@
this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F));
this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F));
this.tableLayout.Size = new System.Drawing.Size(706, 201);
this.tableLayout.Size = new System.Drawing.Size(706, 302);
this.tableLayout.TabIndex = 0;
//
// flowLayoutToolbar
@ -70,13 +71,14 @@
this.flowLayoutToolbar.Controls.Add(this.buttonAdd);
this.flowLayoutToolbar.Controls.Add(this.buttonRemove);
this.flowLayoutToolbar.Controls.Add(this.buttonRename);
this.flowLayoutToolbar.Controls.Add(this.buttonChangeMultiLine);
this.flowLayoutToolbar.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutToolbar.FlowDirection = System.Windows.Forms.FlowDirection.BottomUp;
this.flowLayoutToolbar.Location = new System.Drawing.Point(0, 0);
this.flowLayoutToolbar.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutToolbar.Name = "flowLayoutToolbar";
this.tableLayout.SetRowSpan(this.flowLayoutToolbar, 3);
this.flowLayoutToolbar.Size = new System.Drawing.Size(66, 201);
this.flowLayoutToolbar.Size = new System.Drawing.Size(66, 302);
this.flowLayoutToolbar.TabIndex = 0;
//
// buttonAdd
@ -85,7 +87,7 @@
this.buttonAdd.FlatAppearance.BorderSize = 0;
this.buttonAdd.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.buttonAdd.Image = global::UI_WinForms.Resources.Icons.icons8_add_tag_512;
this.buttonAdd.Location = new System.Drawing.Point(3, 138);
this.buttonAdd.Location = new System.Drawing.Point(3, 239);
this.buttonAdd.Name = "buttonAdd";
this.buttonAdd.Size = new System.Drawing.Size(60, 60);
this.buttonAdd.TabIndex = 0;
@ -99,7 +101,7 @@
this.buttonRemove.FlatAppearance.BorderSize = 0;
this.buttonRemove.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.buttonRemove.Image = global::UI_WinForms.Resources.Icons.icons8_remove_tag_512;
this.buttonRemove.Location = new System.Drawing.Point(3, 72);
this.buttonRemove.Location = new System.Drawing.Point(3, 173);
this.buttonRemove.Name = "buttonRemove";
this.buttonRemove.Size = new System.Drawing.Size(60, 60);
this.buttonRemove.TabIndex = 2;
@ -113,7 +115,7 @@
this.buttonRename.FlatAppearance.BorderSize = 0;
this.buttonRename.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.buttonRename.Image = global::UI_WinForms.Resources.Icons.icons8_rename_512;
this.buttonRename.Location = new System.Drawing.Point(3, 6);
this.buttonRename.Location = new System.Drawing.Point(3, 107);
this.buttonRename.Name = "buttonRename";
this.buttonRename.Size = new System.Drawing.Size(60, 60);
this.buttonRename.TabIndex = 1;
@ -124,7 +126,7 @@
// textBoxFilter
//
this.textBoxFilter.Dock = System.Windows.Forms.DockStyle.Fill;
this.textBoxFilter.Location = new System.Drawing.Point(149, 164);
this.textBoxFilter.Location = new System.Drawing.Point(149, 265);
this.textBoxFilter.Name = "textBoxFilter";
this.textBoxFilter.Size = new System.Drawing.Size(554, 34);
this.textBoxFilter.TabIndex = 2;
@ -135,7 +137,7 @@
//
this.labelFilter.AutoSize = true;
this.labelFilter.Dock = System.Windows.Forms.DockStyle.Fill;
this.labelFilter.Location = new System.Drawing.Point(69, 161);
this.labelFilter.Location = new System.Drawing.Point(69, 262);
this.labelFilter.Name = "labelFilter";
this.labelFilter.Size = new System.Drawing.Size(74, 40);
this.labelFilter.TabIndex = 3;
@ -166,7 +168,7 @@
this.listTextElements.Location = new System.Drawing.Point(69, 43);
this.listTextElements.MultiSelect = false;
this.listTextElements.Name = "listTextElements";
this.listTextElements.Size = new System.Drawing.Size(634, 115);
this.listTextElements.Size = new System.Drawing.Size(634, 216);
this.listTextElements.TabIndex = 5;
this.listTextElements.UseCompatibleStateImageBehavior = false;
this.listTextElements.View = System.Windows.Forms.View.SmallIcon;
@ -184,6 +186,20 @@
this.toolTip.ToolTipIcon = System.Windows.Forms.ToolTipIcon.Info;
this.toolTip.ToolTipTitle = "Help";
//
// buttonChangeMultiLine
//
this.buttonChangeMultiLine.Enabled = false;
this.buttonChangeMultiLine.FlatAppearance.BorderSize = 0;
this.buttonChangeMultiLine.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.buttonChangeMultiLine.Image = global::UI_WinForms.Resources.Icons.icons8_align_text_left_512;
this.buttonChangeMultiLine.Location = new System.Drawing.Point(3, 41);
this.buttonChangeMultiLine.Name = "buttonChangeMultiLine";
this.buttonChangeMultiLine.Size = new System.Drawing.Size(60, 60);
this.buttonChangeMultiLine.TabIndex = 3;
this.toolTip.SetToolTip(this.buttonChangeMultiLine, "Toggles the selected element\'s multi-line state");
this.buttonChangeMultiLine.UseVisualStyleBackColor = true;
this.buttonChangeMultiLine.Click += new System.EventHandler(this.buttonChangeMultiLine_Click);
//
// TextElements
//
this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F);
@ -191,7 +207,7 @@
this.Controls.Add(this.tableLayout);
this.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
this.Name = "TextElements";
this.Size = new System.Drawing.Size(706, 201);
this.Size = new System.Drawing.Size(706, 302);
this.tableLayout.ResumeLayout(false);
this.tableLayout.PerformLayout();
this.flowLayoutToolbar.ResumeLayout(false);
@ -212,5 +228,6 @@
private Label labelSectionPath;
private ListView listTextElements;
private ColumnHeader column;
private Button buttonChangeMultiLine;
}
}

View File

@ -22,6 +22,7 @@ public partial class TextElements : UserControl
var imgList = new ImageList();
imgList.ImageSize = new Size(45, 45);
imgList.ColorDepth = ColorDepth.Depth32Bit;
imgList.Images.Add(Icons.icons8_row_512);
imgList.Images.Add(Icons.icons8_align_text_left_512);
// Set the image list to the list box:
@ -33,8 +34,8 @@ public partial class TextElements : UserControl
this.currentSection = section;
this.currentTextElement = null;
this.buttonAdd.Enabled = this.currentSection is not null;
this.buttonRename.Enabled = this.buttonRemove.Enabled = false;
this.buttonRename.Enabled = this.buttonRemove.Enabled = this.buttonChangeMultiLine.Enabled = false;
if (this.currentSection is null)
return;
@ -47,7 +48,12 @@ public partial class TextElements : UserControl
AppEvents.WhenTextElementChanged += (sender, textElement) =>
{
this.currentTextElement = textElement;
this.buttonRename.Enabled = this.buttonRemove.Enabled = this.currentTextElement is not null;
this.buttonRename.Enabled = this.buttonRemove.Enabled = this.buttonChangeMultiLine.Enabled = this.currentTextElement is not null;
if (this.currentTextElement is not null && this.currentTextElement.IsMultiLine)
this.buttonChangeMultiLine.Image = Icons.icons8_row_512;
else
this.buttonChangeMultiLine.Image = Icons.icons8_align_text_left_512;
};
}
@ -63,7 +69,7 @@ public partial class TextElements : UserControl
// Update the list:
this.listTextElements.Items.Clear();
foreach (var textElement in textElements)
this.listTextElements.Items.Add(new ListViewItem(textElement.Name, 0)
this.listTextElements.Items.Add(new ListViewItem(textElement.Name, textElement.IsMultiLine ? 1 : 0)
{
Tag = textElement.Id,
});
@ -80,21 +86,22 @@ public partial class TextElements : UserControl
Message: "Please type the desired text element's name.",
Title: "Add a text element",
Placeholder: "My text element",
ShowQuestionCheckbox: false
ShowQuestionCheckbox: true,
QuestionCheckboxText: "Is multi-line?"
));
if(result.DialogResult == DialogResult.Cancel)
return;
// Add the text element to the database into the current section:
var newTextElement = await TextElementProcessor.AddTextElement(this.currentSection?.DataKey, result.Text);
var newTextElement = await TextElementProcessor.AddTextElement(this.currentSection?.DataKey, result.Text, result.AnswerToQuestion);
newTextElement.ProcessError();
if(!newTextElement.Successful)
return;
// Add the text element to the list:
this.listTextElements.Items.Add(new ListViewItem(newTextElement.Result!.Name, 0)
this.listTextElements.Items.Add(new ListViewItem(newTextElement.Result!.Name, newTextElement.Result.IsMultiLine ? 1 : 0)
{
Tag = newTextElement.Result.Id,
});
@ -131,16 +138,39 @@ public partial class TextElements : UserControl
var result = InputDialog.Show(new InputDialog.Options(
Message: "Please edit the text element's name.",
PreloadedText: this.currentTextElement!.Name,
ShowQuestionCheckbox: false,
Title: "Rename text element"
ShowQuestionCheckbox: true,
Title: "Rename text element",
QuestionCheckboxText: "Is multi-line?",
QuestionCheckboxState: this.currentTextElement.IsMultiLine
));
// If the user canceled, return:
if(result.DialogResult == DialogResult.Cancel)
return;
ProcessorResult<TextElement> alteredTextElement;
if(this.currentTextElement.Name == result.Text)
// Update the multi-line state:
alteredTextElement = await TextElementProcessor.UpdateTextElementState(this.currentTextElement.Id, result.AnswerToQuestion);
else
// Rename the text element:
alteredTextElement = await TextElementProcessor.RenameTextElement(this.currentTextElement.Id, result.Text, result.AnswerToQuestion);
// Rename the text element:
var alteredTextElement = await TextElementProcessor.RenameTextElement(this.currentTextElement.Id, result.Text);
alteredTextElement.ProcessError();
if(!alteredTextElement.Successful)
return;
// Reload the text elements:
await this.LoadTextElements();
}
private async void buttonChangeMultiLine_Click(object sender, EventArgs e)
{
if(this.DesignMode)
return;
// Update the multi-line state:
var alteredTextElement = await TextElementProcessor.UpdateTextElementState(this.currentTextElement!.Id, !this.currentTextElement.IsMultiLine);
alteredTextElement.ProcessError();
if(!alteredTextElement.Successful)

View File

@ -60,4 +60,7 @@
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

View File

@ -10,7 +10,8 @@ public partial class InputDialog : Form
string OkButtonText = "Ok",
string CancelButtonText = "Cancel",
bool ShowQuestionCheckbox = false,
string QuestionCheckboxText = ""
string QuestionCheckboxText = "",
bool QuestionCheckboxState = false
);
private InputDialog()
@ -29,6 +30,7 @@ public partial class InputDialog : Form
inputDialog.buttonCancel.Text = options.CancelButtonText;
inputDialog.checkBoxQuestion.Visible = options.ShowQuestionCheckbox;
inputDialog.checkBoxQuestion.Text = options.QuestionCheckboxText;
inputDialog.checkBoxQuestion.Checked = options.QuestionCheckboxState;
// Ensure, that the text box is focused on load:
inputDialog.textBoxInput.Select();

View File

@ -280,6 +280,16 @@ namespace UI_WinForms.Resources {
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap icons8_row_512 {
get {
object obj = ResourceManager.GetObject("icons8_row_512", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>

View File

@ -184,6 +184,9 @@
<data name="icons8_rename_512" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons8-rename-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="icons8_row_512" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons8-row-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="icons8_settings_svg" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons8-settings.svg.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB