commit 95364c8a310822b2a61f38b6c2ae3e911a8ab4af Author: Mateusz Skoczek Date: Sun Mar 12 12:32:26 2023 +0100 Project creation, basics diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0809395 --- /dev/null +++ b/.gitignore @@ -0,0 +1,135 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.svclog +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.pubxml +*.azurePubxml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +packages/ +## TODO: If the tool you use requires repositories.config, also uncomment the next line +!packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +![Ss]tyle[Cc]op.targets +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml + +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac desktop service store files +.DS_Store + +_NCrunch* + +.vs/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/TimetableDesigner.Core/Class.cs b/TimetableDesigner.Core/Class.cs new file mode 100644 index 0000000..ff5275b --- /dev/null +++ b/TimetableDesigner.Core/Class.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TimetableDesigner.Core +{ + public class Class + { + #region PROPERTIES + + public string Name { get; set; } + public string Description { get; set; } + public Teacher Teacher { get; set; } + public Subgroup Subgroup { get; set; } + public Classroom Classroom { get; set; } + + #endregion + } +} diff --git a/TimetableDesigner.Core/Classroom.cs b/TimetableDesigner.Core/Classroom.cs new file mode 100644 index 0000000..a3d7573 --- /dev/null +++ b/TimetableDesigner.Core/Classroom.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading.Tasks; + +namespace TimetableDesigner.Core +{ + public class Classroom + { + #region PROPERTIES + + public string Name { get; set; } + public string Description { get; set; } + public bool IsCapacityLimited { get; set; } + public uint Capacity { get; set; } + + #endregion + + + + #region CONSTRUCTORS + + public Classroom() + { + Name = string.Empty; + Description = string.Empty; + IsCapacityLimited = false; + Capacity = 1; + } + + #endregion + } +} diff --git a/TimetableDesigner.Core/Group.cs b/TimetableDesigner.Core/Group.cs new file mode 100644 index 0000000..dd3321f --- /dev/null +++ b/TimetableDesigner.Core/Group.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TimetableDesigner.Core +{ + public class Group + { + #region PROPERTIES + + public string Name { get; set; } + public string Description { get; set; } + public Subgroup MainSubgroup { get; set; } + public ICollection AssignedSubgroups { get; set; } + + #endregion + } +} diff --git a/TimetableDesigner.Core/Project.cs b/TimetableDesigner.Core/Project.cs new file mode 100644 index 0000000..5f2d38a --- /dev/null +++ b/TimetableDesigner.Core/Project.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TimetableDesigner.Core +{ + [Serializable] + public class Project + { + #region PROPERTIES + + public string Name { get; set; } + public string Author { get; set; } + public string Description { get; set; } + public TimetableTemplate TimetableTemplate { get; set; } + public ICollection Classrooms { get; set; } + public ICollection Teachers { get; set; } + public ICollection Groups { get; set; } + public ICollection Subgroups { get; set; } + public ICollection Classes { get; set; } + + #endregion + + + + #region CONSTRUCTORS + + public Project() + { + Name = string.Empty; + Author = string.Empty; + Description = string.Empty; + TimetableTemplate = new TimetableTemplate(); + Classrooms = new List(); + Teachers = new List(); + } + + #endregion + } +} diff --git a/TimetableDesigner.Core/Subgroup.cs b/TimetableDesigner.Core/Subgroup.cs new file mode 100644 index 0000000..268358c --- /dev/null +++ b/TimetableDesigner.Core/Subgroup.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TimetableDesigner.Core +{ + public class Subgroup + { + #region PROPERTIES + + public string Name { get; set; } + public string Description { get; set; } + + #endregion + } +} diff --git a/TimetableDesigner.Core/Teacher.cs b/TimetableDesigner.Core/Teacher.cs new file mode 100644 index 0000000..fb0cacb --- /dev/null +++ b/TimetableDesigner.Core/Teacher.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TimetableDesigner.Core +{ + public class Teacher + { + #region PROPERTIES + + public string Name { get; set; } + public string Description { get; set; } + + #endregion + } +} diff --git a/TimetableDesigner.Core/TimetableDay.cs b/TimetableDesigner.Core/TimetableDay.cs new file mode 100644 index 0000000..a3d19a9 --- /dev/null +++ b/TimetableDesigner.Core/TimetableDay.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TimetableDesigner.Core +{ + public struct TimetableDay + { + #region PROPERTIES + + public string Name { get; set; } + + #endregion + + + + #region CONSTRUCTORS + + public TimetableDay(string name) + { + Name = name; + } + + #endregion + } +} diff --git a/TimetableDesigner.Core/TimetableDesigner.Core.csproj b/TimetableDesigner.Core/TimetableDesigner.Core.csproj new file mode 100644 index 0000000..cb6a55a --- /dev/null +++ b/TimetableDesigner.Core/TimetableDesigner.Core.csproj @@ -0,0 +1,9 @@ + + + + net7.0-windows + enable + enable + + + diff --git a/TimetableDesigner.Core/TimetableSlot.cs b/TimetableDesigner.Core/TimetableSlot.cs new file mode 100644 index 0000000..8bac068 --- /dev/null +++ b/TimetableDesigner.Core/TimetableSlot.cs @@ -0,0 +1,75 @@ +using System; + +namespace TimetableDesigner.Core +{ + [Serializable] + public struct TimetableSlot + { + #region PROPERTIES + + public TimeOnly From { get; private set; } + public TimeOnly To { get; private set; } + + #endregion + + + + #region CONSTRUCTORS + + public TimetableSlot(TimeOnly from, TimeOnly to) + { + if (to <= from) + { + throw new ArgumentException("\"to\" cannot be less or equal to \"from\""); + } + + From = from; + To = to; + } + + #endregion + + + + #region PUBLIC METHODS + + internal TimetableSlotsCollision CheckCollision(TimetableSlot slot) + { + if (slot.To <= this.From) + { + return TimetableSlotsCollision.CheckedSlotBefore; + } + else if (this.To <= slot.From) + { + return TimetableSlotsCollision.CheckedSlotAfter; + } + else + { + if (this.From < slot.From && slot.To < this.To) + { + return TimetableSlotsCollision.CheckedSlotIn; + } + else if (this.From < slot.From && slot.From < this.To && this.To < slot.To) + { + return TimetableSlotsCollision.CheckedSlotFromIn; + } + else if (slot.From < this.From && this.From < slot.To && slot.To < this.To) + { + return TimetableSlotsCollision.CheckedSlotToIn; + } + else + { + throw new ArgumentException("Unknown collision"); + } + } + } + + public override bool Equals(object? obj) => obj is TimetableSlot slot && From == slot.From && To == slot.To; + + public override int GetHashCode() => HashCode.Combine(From, To); + + public override string? ToString() => $"{From}-{To}"; + + #endregion + } +} diff --git a/TimetableDesigner.Core/TimetableSlotsCollision.cs b/TimetableDesigner.Core/TimetableSlotsCollision.cs new file mode 100644 index 0000000..c698a1e --- /dev/null +++ b/TimetableDesigner.Core/TimetableSlotsCollision.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TimetableDesigner.Core +{ + internal enum TimetableSlotsCollision + { + CheckedSlotBefore, + CheckedSlotAfter, + CheckedSlotIn, + CheckedSlotFromIn, + CheckedSlotToIn + } +} diff --git a/TimetableDesigner.Core/TimetableTemplate.cs b/TimetableDesigner.Core/TimetableTemplate.cs new file mode 100644 index 0000000..a242915 --- /dev/null +++ b/TimetableDesigner.Core/TimetableTemplate.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TimetableDesigner.Core +{ + [Serializable] + public class TimetableTemplate + { + #region FIELDS + + private List _days; + private List _slots; + + #endregion + + + + #region PROPERTIES + + public IEnumerable Days => _days; + public IEnumerable Slots => _slots; + + #endregion + + + + #region CONSTRUCTORS + + public TimetableTemplate() + { + _days = new List(); + _slots = new List(); + } + + #endregion + + + + #region PUBLIC METHODS + + public void AddDay(TimetableDay name) + { + _days.Add(name); + } + + public bool RemoveDay(TimetableDay day) + { + return _days.Remove(day); + } + + public void AddSlot(TimetableSlot slot) + { + int i = 0; + if (_slots.Count > 0) + { + bool done = false; + while (i < _slots.Count && !done) + { + switch (slot.CheckCollision(_slots[i])) + { + case TimetableSlotsCollision.CheckedSlotBefore: i++; break; + case TimetableSlotsCollision.CheckedSlotAfter: done ^= true; break; + default: throw new ArgumentException("Slot collide with another slot"); + } + } + } + _slots.Insert(i, slot); + } + + public bool RemoveSlot(TimetableSlot slot) + { + return _slots.Remove(slot); + } + + #endregion + } +} diff --git a/TimetableDesigner.MessageBox/MessageBoxService.cs b/TimetableDesigner.MessageBox/MessageBoxService.cs new file mode 100644 index 0000000..3b722b0 --- /dev/null +++ b/TimetableDesigner.MessageBox/MessageBoxService.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Versioning; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using TimetableDesigner.MessageBox.Properties; + +namespace TimetableDesigner.MessageBox +{ + public static class MessageBoxService + { + #region PUBLIC METHODS + + public static void ShowError(string message) => System.Windows.MessageBox.Show(message, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); + + public static MessageBoxYesNoCancelResult ShowYesNoCancelQuestion(string message) + { + MessageBoxResult result = System.Windows.MessageBox.Show(message, Resources.Error, MessageBoxButton.YesNoCancel, MessageBoxImage.Question); + switch (result) + { + case MessageBoxResult.Yes: return MessageBoxYesNoCancelResult.Yes; + case MessageBoxResult.No: return MessageBoxYesNoCancelResult.No; + case MessageBoxResult.Cancel: return MessageBoxYesNoCancelResult.Cancel; + default: return MessageBoxYesNoCancelResult.None; + } + } + + #endregion + + } +} diff --git a/TimetableDesigner.MessageBox/MessageBoxYesNoCancelResult.cs b/TimetableDesigner.MessageBox/MessageBoxYesNoCancelResult.cs new file mode 100644 index 0000000..0ac9306 --- /dev/null +++ b/TimetableDesigner.MessageBox/MessageBoxYesNoCancelResult.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TimetableDesigner.MessageBox +{ + public enum MessageBoxYesNoCancelResult + { + Yes, + No, + Cancel, + None + } +} diff --git a/TimetableDesigner.MessageBox/Properties/Resources.Designer.cs b/TimetableDesigner.MessageBox/Properties/Resources.Designer.cs new file mode 100644 index 0000000..29b46ad --- /dev/null +++ b/TimetableDesigner.MessageBox/Properties/Resources.Designer.cs @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace TimetableDesigner.MessageBox.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TimetableDesigner.MessageBox.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Error. + /// + internal static string Error { + get { + return ResourceManager.GetString("Error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Question. + /// + internal static string Question { + get { + return ResourceManager.GetString("Question", resourceCulture); + } + } + } +} diff --git a/TimetableDesigner.MessageBox/Properties/Resources.resx b/TimetableDesigner.MessageBox/Properties/Resources.resx new file mode 100644 index 0000000..5a67b65 --- /dev/null +++ b/TimetableDesigner.MessageBox/Properties/Resources.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Error + + + Question + + \ No newline at end of file diff --git a/TimetableDesigner.MessageBox/TimetableDesigner.MessageBox.csproj b/TimetableDesigner.MessageBox/TimetableDesigner.MessageBox.csproj new file mode 100644 index 0000000..9201700 --- /dev/null +++ b/TimetableDesigner.MessageBox/TimetableDesigner.MessageBox.csproj @@ -0,0 +1,24 @@ + + + + net7.0-windows + enable + true + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + diff --git a/TimetableDesigner.Tests/TimetableDesigner.Tests.csproj b/TimetableDesigner.Tests/TimetableDesigner.Tests.csproj new file mode 100644 index 0000000..97a0658 --- /dev/null +++ b/TimetableDesigner.Tests/TimetableDesigner.Tests.csproj @@ -0,0 +1,22 @@ + + + + net7.0-windows + enable + enable + + false + + + + + + + + + + + + + + diff --git a/TimetableDesigner.Tests/TimetableTest.cs b/TimetableDesigner.Tests/TimetableTest.cs new file mode 100644 index 0000000..dc97190 --- /dev/null +++ b/TimetableDesigner.Tests/TimetableTest.cs @@ -0,0 +1,167 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Diagnostics; +using TimetableDesigner.Core; + +namespace TimetableDesigner.Tests +{ + [TestClass] + public class TimetableTest + { + [TestMethod] + public void CreateValidSlotTest() + { + TimetableSlot slot = new TimetableSlot(new TimeOnly(8, 0), new TimeOnly(9, 0)); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentException))] + public void CreateInvalidSlotTest() + { + TimetableSlot slot = new TimetableSlot(new TimeOnly(9, 0), new TimeOnly(8, 0)); + + Assert.Fail(); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentException))] + public void CreateSlotWithZeroLengthTest() + { + TimetableSlot slot = new TimetableSlot(new TimeOnly(8, 0), new TimeOnly(8, 0)); + + Assert.Fail(); + } + + [TestMethod] + public void CreateModelTest() + { + TimetableTemplate model = new TimetableTemplate(); + } + + [TestMethod] + public void AddDayTest() + { + TimetableTemplate model = new TimetableTemplate(); + + TimetableDay day = new TimetableDay + { + Name = "Monday" + }; + + model.AddDay(day); + + Assert.AreEqual(1, model.Days.Count()); + Assert.AreEqual(day, model.Days.ToList()[0]); + } + + [TestMethod] + public void AddSlotTest() + { + TimetableTemplate model = new TimetableTemplate(); + + TimetableSlot slot = new TimetableSlot(new TimeOnly(8, 0), new TimeOnly(9, 0)); + + model.AddSlot(slot); + + Assert.AreEqual(1, model.Slots.Count()); + Assert.AreEqual(new TimetableSlot(new TimeOnly(8, 0), new TimeOnly(9, 0)), model.Slots.ToList()[0]); + } + + [TestMethod] + public void AddNoCollidingSlotsTest() + { + TimetableTemplate model = new TimetableTemplate(); + + TimetableSlot slot1 = new TimetableSlot(new TimeOnly(8, 15), new TimeOnly(9, 0)); + TimetableSlot slot2 = new TimetableSlot(new TimeOnly(9, 15), new TimeOnly(10, 0)); + + model.AddSlot(slot1); + model.AddSlot(slot2); + + Assert.AreEqual(2, model.Slots.Count()); + Assert.AreEqual(new TimetableSlot(new TimeOnly(8, 15), new TimeOnly(9, 0)), model.Slots.ToList()[0]); + Assert.AreEqual(new TimetableSlot(new TimeOnly(9, 15), new TimeOnly(10, 0)), model.Slots.ToList()[1]); + } + + [TestMethod] + public void AddSlotsWithoutBreakTest() + { + TimetableTemplate model = new TimetableTemplate(); + + TimetableSlot slot1 = new TimetableSlot(new TimeOnly(8, 0), new TimeOnly(9, 0)); + TimetableSlot slot2 = new TimetableSlot(new TimeOnly(9, 0), new TimeOnly(10, 0)); + + model.AddSlot(slot1); + model.AddSlot(slot2); + + Assert.AreEqual(2, model.Slots.Count()); + Assert.AreEqual(new TimetableSlot(new TimeOnly(8, 0), new TimeOnly(9, 0)), model.Slots.ToList()[0]); + Assert.AreEqual(new TimetableSlot(new TimeOnly(9, 0), new TimeOnly(10, 0)), model.Slots.ToList()[1]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentException))] + public void AddCollidingSlotsTest() + { + TimetableTemplate model = new TimetableTemplate(); + + TimetableSlot slot1 = new TimetableSlot(new TimeOnly(8, 0), new TimeOnly(9, 30)); + TimetableSlot slot2 = new TimetableSlot(new TimeOnly(8, 30), new TimeOnly(10, 0)); + + model.AddSlot(slot1); + model.AddSlot(slot2); + + Assert.Fail(); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentException))] + public void AddBetweenCollidingSlotsTest() + { + TimetableTemplate model = new TimetableTemplate(); + + TimetableSlot slot1 = new TimetableSlot(new TimeOnly(8, 0), new TimeOnly(9, 0)); + TimetableSlot slot2 = new TimetableSlot(new TimeOnly(10, 0), new TimeOnly(11, 0)); + TimetableSlot slot3 = new TimetableSlot(new TimeOnly(8, 59), new TimeOnly(10, 1)); + + model.AddSlot(slot1); + model.AddSlot(slot2); + model.AddSlot(slot3); + + Assert.Fail(); + } + + [TestMethod] + public void SortSlotsTest() + { + TimetableTemplate model = new TimetableTemplate(); + + TimetableSlot slot1 = new TimetableSlot(new TimeOnly(12, 0), new TimeOnly(13, 0)); + TimetableSlot slot2 = new TimetableSlot(new TimeOnly(8, 0), new TimeOnly(9, 0)); + TimetableSlot slot3 = new TimetableSlot(new TimeOnly(10, 0), new TimeOnly(11, 0)); + TimetableSlot slot4 = new TimetableSlot(new TimeOnly(14, 0), new TimeOnly(15, 0)); + TimetableSlot slot5 = new TimetableSlot(new TimeOnly(13, 0), new TimeOnly(14, 0)); + TimetableSlot slot6 = new TimetableSlot(new TimeOnly(9, 0), new TimeOnly(10, 0)); + TimetableSlot slot7 = new TimetableSlot(new TimeOnly(11, 0), new TimeOnly(12, 0)); + + model.AddSlot(slot1); + model.AddSlot(slot2); + model.AddSlot(slot3); + model.AddSlot(slot4); + model.AddSlot(slot5); + model.AddSlot(slot6); + model.AddSlot(slot7); + + List slots = model.Slots.ToList(); + + TimetableSlot testSlot = slots[0]; + for (int i = 1; i < slots.Count; i++) + { + if (testSlot.To > slots[i].From) + { + Assert.Fail(); + } + testSlot = slots[i]; + } + } + } +} diff --git a/TimetableDesigner.sln b/TimetableDesigner.sln new file mode 100644 index 0000000..ca65abf --- /dev/null +++ b/TimetableDesigner.sln @@ -0,0 +1,61 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TimetableDesigner", "TimetableDesigner\TimetableDesigner.csproj", "{739E5B4E-09D0-468C-9FA0-4BB6D89C1FE0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TimetableDesigner.Core", "TimetableDesigner.Core\TimetableDesigner.Core.csproj", "{A00B17BE-238D-4241-BECC-30119F8CBEE0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TimetableDesigner.Tests", "TimetableDesigner.Tests\TimetableDesigner.Tests.csproj", "{A9B4DB89-A007-472A-9C80-B6340458AC1B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TimetableDesigner.MessageBox", "TimetableDesigner.MessageBox\TimetableDesigner.MessageBox.csproj", "{95992646-6D81-4FF4-885E-8F0BE2312D54}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {739E5B4E-09D0-468C-9FA0-4BB6D89C1FE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {739E5B4E-09D0-468C-9FA0-4BB6D89C1FE0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {739E5B4E-09D0-468C-9FA0-4BB6D89C1FE0}.Debug|x64.ActiveCfg = Debug|x64 + {739E5B4E-09D0-468C-9FA0-4BB6D89C1FE0}.Debug|x64.Build.0 = Debug|x64 + {739E5B4E-09D0-468C-9FA0-4BB6D89C1FE0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {739E5B4E-09D0-468C-9FA0-4BB6D89C1FE0}.Release|Any CPU.Build.0 = Release|Any CPU + {739E5B4E-09D0-468C-9FA0-4BB6D89C1FE0}.Release|x64.ActiveCfg = Release|x64 + {739E5B4E-09D0-468C-9FA0-4BB6D89C1FE0}.Release|x64.Build.0 = Release|x64 + {A00B17BE-238D-4241-BECC-30119F8CBEE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A00B17BE-238D-4241-BECC-30119F8CBEE0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A00B17BE-238D-4241-BECC-30119F8CBEE0}.Debug|x64.ActiveCfg = Debug|Any CPU + {A00B17BE-238D-4241-BECC-30119F8CBEE0}.Debug|x64.Build.0 = Debug|Any CPU + {A00B17BE-238D-4241-BECC-30119F8CBEE0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A00B17BE-238D-4241-BECC-30119F8CBEE0}.Release|Any CPU.Build.0 = Release|Any CPU + {A00B17BE-238D-4241-BECC-30119F8CBEE0}.Release|x64.ActiveCfg = Release|Any CPU + {A00B17BE-238D-4241-BECC-30119F8CBEE0}.Release|x64.Build.0 = Release|Any CPU + {A9B4DB89-A007-472A-9C80-B6340458AC1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A9B4DB89-A007-472A-9C80-B6340458AC1B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A9B4DB89-A007-472A-9C80-B6340458AC1B}.Debug|x64.ActiveCfg = Debug|Any CPU + {A9B4DB89-A007-472A-9C80-B6340458AC1B}.Debug|x64.Build.0 = Debug|Any CPU + {A9B4DB89-A007-472A-9C80-B6340458AC1B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A9B4DB89-A007-472A-9C80-B6340458AC1B}.Release|Any CPU.Build.0 = Release|Any CPU + {A9B4DB89-A007-472A-9C80-B6340458AC1B}.Release|x64.ActiveCfg = Release|Any CPU + {A9B4DB89-A007-472A-9C80-B6340458AC1B}.Release|x64.Build.0 = Release|Any CPU + {95992646-6D81-4FF4-885E-8F0BE2312D54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {95992646-6D81-4FF4-885E-8F0BE2312D54}.Debug|Any CPU.Build.0 = Debug|Any CPU + {95992646-6D81-4FF4-885E-8F0BE2312D54}.Debug|x64.ActiveCfg = Debug|Any CPU + {95992646-6D81-4FF4-885E-8F0BE2312D54}.Debug|x64.Build.0 = Debug|Any CPU + {95992646-6D81-4FF4-885E-8F0BE2312D54}.Release|Any CPU.ActiveCfg = Release|Any CPU + {95992646-6D81-4FF4-885E-8F0BE2312D54}.Release|Any CPU.Build.0 = Release|Any CPU + {95992646-6D81-4FF4-885E-8F0BE2312D54}.Release|x64.ActiveCfg = Release|Any CPU + {95992646-6D81-4FF4-885E-8F0BE2312D54}.Release|x64.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {948AE685-3476-4374-9ADE-9F57FDE2D8D7} + EndGlobalSection +EndGlobal diff --git a/TimetableDesigner/App.xaml b/TimetableDesigner/App.xaml new file mode 100644 index 0000000..15164af --- /dev/null +++ b/TimetableDesigner/App.xaml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/TimetableDesigner/App.xaml.cs b/TimetableDesigner/App.xaml.cs new file mode 100644 index 0000000..8114ebc --- /dev/null +++ b/TimetableDesigner/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace TimetableDesigner +{ + public partial class App : Application + { + public App() + { + } + } +} diff --git a/TimetableDesigner/AssemblyInfo.cs b/TimetableDesigner/AssemblyInfo.cs new file mode 100644 index 0000000..8b5504e --- /dev/null +++ b/TimetableDesigner/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/TimetableDesigner/Commands/RelayCommand.cs b/TimetableDesigner/Commands/RelayCommand.cs new file mode 100644 index 0000000..4873f1b --- /dev/null +++ b/TimetableDesigner/Commands/RelayCommand.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace TimetableDesigner.Commands +{ + public class RelayCommand : ICommand + { + #region FIELDS + + private readonly Action _execute; + private readonly Predicate _canExecute; + + #endregion + + + + #region CONSTRUCTORS + + public RelayCommand(Action execute) : this(execute, null) { } + + public RelayCommand(Action execute, Predicate canExecute) + { + if (execute == null) + throw new ArgumentNullException("execute"); + + _execute = execute; + _canExecute = canExecute; + } + + #endregion + + + + #region PUBLIC METHODS + + public bool CanExecute(object parameter) => _canExecute == null || _canExecute((T)parameter); + + public void Execute(object parameter) + { + _execute((T)parameter); + } + + #endregion + + + + #region EVENTS + + public event EventHandler CanExecuteChanged + { + add { CommandManager.RequerySuggested += value; } + remove { CommandManager.RequerySuggested -= value; } + } + + #endregion + } +} diff --git a/TimetableDesigner/Converters/IsNotNullToBooleanConverter.cs b/TimetableDesigner/Converters/IsNotNullToBooleanConverter.cs new file mode 100644 index 0000000..f619a64 --- /dev/null +++ b/TimetableDesigner/Converters/IsNotNullToBooleanConverter.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Data; + +namespace TimetableDesigner.Converters +{ + public class IsNotNullToBooleanConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return value is not null; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/TimetableDesigner/Converters/IsNullToVisibilityConverter.cs b/TimetableDesigner/Converters/IsNullToVisibilityConverter.cs new file mode 100644 index 0000000..b707449 --- /dev/null +++ b/TimetableDesigner/Converters/IsNullToVisibilityConverter.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Data; + +namespace TimetableDesigner.Converters +{ + public class IsNullToVisibilityConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return value is null ? Visibility.Collapsed : Visibility.Visible; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/TimetableDesigner/Converters/ViewModelToViewConverter.cs b/TimetableDesigner/Converters/ViewModelToViewConverter.cs new file mode 100644 index 0000000..880572f --- /dev/null +++ b/TimetableDesigner/Converters/ViewModelToViewConverter.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Data; +using TimetableDesigner.ViewModels; +using TimetableDesigner.ViewModels.Base; +using TimetableDesigner.Views; + +namespace TimetableDesigner.Converters +{ + public class ViewModelToViewConverter : IValueConverter + { + #region FIELDS + + private static readonly Dictionary _viewModelViewPairs = new Dictionary + { + { typeof(MainViewModel), typeof(MainWindow) }, + { typeof(WelcomeTabViewModel), typeof(WelcomeTabView) }, + { typeof(ProjectSettingsTabViewModel), typeof(ProjectSettingsTabView) }, + { typeof(ClassroomEditTabViewModel), typeof(ClassroomEditTabView) }, + }; + + #endregion + + + + #region PUBLIC METHODS + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + BaseViewModel? viewModel = value as BaseViewModel; + if (viewModel is not null) + { + Type view = _viewModelViewPairs[viewModel.GetType()]; + FrameworkElement? viewInstance = Activator.CreateInstance(view) as FrameworkElement; + if (viewInstance is not null ) + { + viewInstance.DataContext = viewModel; + return viewInstance; + } + } + return null; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + + #endregion + } +} diff --git a/TimetableDesigner/Properties/Resources.Designer.cs b/TimetableDesigner/Properties/Resources.Designer.cs new file mode 100644 index 0000000..a4ad81d --- /dev/null +++ b/TimetableDesigner/Properties/Resources.Designer.cs @@ -0,0 +1,441 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace TimetableDesigner.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TimetableDesigner.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Capacity. + /// + public static string ClassroomEdit_Capacity { + get { + return ResourceManager.GetString("ClassroomEdit.Capacity", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Is limited?. + /// + public static string ClassroomEdit_CapacityIsLimited { + get { + return ResourceManager.GetString("ClassroomEdit.CapacityIsLimited", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Description. + /// + public static string ClassroomEdit_Description { + get { + return ResourceManager.GetString("ClassroomEdit.Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Name. + /// + public static string ClassroomEdit_Name { + get { + return ResourceManager.GetString("ClassroomEdit.Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New classroom. + /// + public static string Global_DefaultClassroomName { + get { + return ResourceManager.GetString("Global.DefaultClassroomName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New project. + /// + public static string Global_DefaultProjectName { + get { + return ResourceManager.GetString("Global.DefaultProjectName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to no project loaded. + /// + public static string Global_NoProjectLoadedTitle { + get { + return ResourceManager.GetString("Global.NoProjectLoadedTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Project is loaded. Do you want to save?. + /// + public static string Main_Message_SaveCurrentProject { + get { + return ResourceManager.GetString("Main.Message.SaveCurrentProject", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to File. + /// + public static string Main_Ribbon_File { + get { + return ResourceManager.GetString("Main.Ribbon.File", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New/Open. + /// + public static string Main_Ribbon_File_NewOpen { + get { + return ResourceManager.GetString("Main.Ribbon.File.NewOpen", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New. + /// + public static string Main_Ribbon_File_NewOpen_New { + get { + return ResourceManager.GetString("Main.Ribbon.File.NewOpen.New", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Open. + /// + public static string Main_Ribbon_File_NewOpen_Open { + get { + return ResourceManager.GetString("Main.Ribbon.File.NewOpen.Open", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Open recent. + /// + public static string Main_Ribbon_File_NewOpen_OpenRecent { + get { + return ResourceManager.GetString("Main.Ribbon.File.NewOpen.OpenRecent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Save. + /// + public static string Main_Ribbon_File_Save { + get { + return ResourceManager.GetString("Main.Ribbon.File.Save", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Save. + /// + public static string Main_Ribbon_File_Save_Save { + get { + return ResourceManager.GetString("Main.Ribbon.File.Save.Save", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Save as. + /// + public static string Main_Ribbon_File_Save_SaveAs { + get { + return ResourceManager.GetString("Main.Ribbon.File.Save.SaveAs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Project. + /// + public static string Main_Ribbon_Project { + get { + return ResourceManager.GetString("Main.Ribbon.Project", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New. + /// + public static string Main_Ribbon_Project_New { + get { + return ResourceManager.GetString("Main.Ribbon.Project.New", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New class. + /// + public static string Main_Ribbon_Project_New_NewClass { + get { + return ResourceManager.GetString("Main.Ribbon.Project.New.NewClass", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New classroom. + /// + public static string Main_Ribbon_Project_New_NewClassroom { + get { + return ResourceManager.GetString("Main.Ribbon.Project.New.NewClassroom", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New group. + /// + public static string Main_Ribbon_Project_New_NewGroup { + get { + return ResourceManager.GetString("Main.Ribbon.Project.New.NewGroup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New subgroup. + /// + public static string Main_Ribbon_Project_New_NewSubgroup { + get { + return ResourceManager.GetString("Main.Ribbon.Project.New.NewSubgroup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New teacher. + /// + public static string Main_Ribbon_Project_New_NewTeacher { + get { + return ResourceManager.GetString("Main.Ribbon.Project.New.NewTeacher", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Settings. + /// + public static string Main_Ribbon_Project_Settings { + get { + return ResourceManager.GetString("Main.Ribbon.Project.Settings", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Project settings. + /// + public static string Main_Ribbon_Project_Settings_ProjectSettings { + get { + return ResourceManager.GetString("Main.Ribbon.Project.Settings.ProjectSettings", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Classrooms. + /// + public static string Main_Treeview_Classrooms { + get { + return ResourceManager.GetString("Main.Treeview.Classrooms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Edit classroom. + /// + public static string Main_Treeview_Classrooms_ContextMenu_Edit { + get { + return ResourceManager.GetString("Main.Treeview.Classrooms.ContextMenu.Edit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Edit timetable. + /// + public static string Main_Treeview_ContextMenu_EditTimetable { + get { + return ResourceManager.GetString("Main.Treeview.ContextMenu.EditTimetable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Remove. + /// + public static string Main_Treeview_ContextMenu_Remove { + get { + return ResourceManager.GetString("Main.Treeview.ContextMenu.Remove", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error. + /// + public static string MessageBox_Error { + get { + return ResourceManager.GetString("MessageBox.Error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Author. + /// + public static string ProjectSettings_Author { + get { + return ResourceManager.GetString("ProjectSettings.Author", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Basics. + /// + public static string ProjectSettings_Basics { + get { + return ResourceManager.GetString("ProjectSettings.Basics", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Days. + /// + public static string ProjectSettings_Days { + get { + return ResourceManager.GetString("ProjectSettings.Days", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Description. + /// + public static string ProjectSettings_Description { + get { + return ResourceManager.GetString("ProjectSettings.Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Hours. + /// + public static string ProjectSettings_Hours { + get { + return ResourceManager.GetString("ProjectSettings.Hours", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Length of the class have to be higher than 0 minutes. + /// + public static string ProjectSettings_Message_FromHigherThanTo { + get { + return ResourceManager.GetString("ProjectSettings.Message.FromHigherThanTo", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Slot collide with another slot. + /// + public static string ProjectSettings_Message_SlotCollision { + get { + return ResourceManager.GetString("ProjectSettings.Message.SlotCollision", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Name. + /// + public static string ProjectSettings_Name { + get { + return ResourceManager.GetString("ProjectSettings.Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Timetable model. + /// + public static string ProjectSettings_TimetableModel { + get { + return ResourceManager.GetString("ProjectSettings.TimetableModel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Classroom editing. + /// + public static string Tabs_ClassroomEdit { + get { + return ResourceManager.GetString("Tabs.ClassroomEdit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Project settings. + /// + public static string Tabs_ProjectSettings { + get { + return ResourceManager.GetString("Tabs.ProjectSettings", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Welcome. + /// + public static string Tabs_Welcome { + get { + return ResourceManager.GetString("Tabs.Welcome", resourceCulture); + } + } + } +} diff --git a/TimetableDesigner/Properties/Resources.pl-PL.Designer.cs b/TimetableDesigner/Properties/Resources.pl-PL.Designer.cs new file mode 100644 index 0000000..8022880 --- /dev/null +++ b/TimetableDesigner/Properties/Resources.pl-PL.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace TimetableDesigner.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Resources___Copy { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources___Copy() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TimetableDesigner.Properties.Resources - Copy", typeof(Resources___Copy).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/TimetableDesigner/Properties/Resources.pl-PL.resx b/TimetableDesigner/Properties/Resources.pl-PL.resx new file mode 100644 index 0000000..4fdb1b6 --- /dev/null +++ b/TimetableDesigner/Properties/Resources.pl-PL.resx @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/TimetableDesigner/Properties/Resources.resx b/TimetableDesigner/Properties/Resources.resx new file mode 100644 index 0000000..fba3efd --- /dev/null +++ b/TimetableDesigner/Properties/Resources.resx @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Capacity + + + Is limited? + + + Description + + + Name + + + New classroom + + + New project + + + no project loaded + + + Project is loaded. Do you want to save? + + + File + + + New/Open + + + New + + + Open + + + Open recent + + + Save + + + Save + + + Save as + + + Project + + + New + + + New class + + + New classroom + + + New group + + + New subgroup + + + New teacher + + + Settings + + + Project settings + + + Classrooms + + + Edit classroom + + + Edit timetable + + + Remove + + + Error + + + Author + + + Basics + + + Days + + + Description + + + Hours + + + Length of the class have to be higher than 0 minutes + + + Slot collide with another slot + + + Name + + + Timetable model + + + Classroom editing + + + Project settings + + + Welcome + + \ No newline at end of file diff --git a/TimetableDesigner/Resources/Converters.xaml b/TimetableDesigner/Resources/Converters.xaml new file mode 100644 index 0000000..c98d563 --- /dev/null +++ b/TimetableDesigner/Resources/Converters.xaml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/TimetableDesigner/Resources/Images.xaml b/TimetableDesigner/Resources/Images.xaml new file mode 100644 index 0000000..89c8dbe --- /dev/null +++ b/TimetableDesigner/Resources/Images.xaml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TimetableDesigner/Resources/Images/Add.png b/TimetableDesigner/Resources/Images/Add.png new file mode 100644 index 0000000..0032cb4 Binary files /dev/null and b/TimetableDesigner/Resources/Images/Add.png differ diff --git a/TimetableDesigner/Resources/Images/Classroom.png b/TimetableDesigner/Resources/Images/Classroom.png new file mode 100644 index 0000000..30f764c Binary files /dev/null and b/TimetableDesigner/Resources/Images/Classroom.png differ diff --git a/TimetableDesigner/Resources/Images/ClassroomAdd.png b/TimetableDesigner/Resources/Images/ClassroomAdd.png new file mode 100644 index 0000000..31fa5bc Binary files /dev/null and b/TimetableDesigner/Resources/Images/ClassroomAdd.png differ diff --git a/TimetableDesigner/Resources/Images/Close.png b/TimetableDesigner/Resources/Images/Close.png new file mode 100644 index 0000000..8417c2f Binary files /dev/null and b/TimetableDesigner/Resources/Images/Close.png differ diff --git a/TimetableDesigner/Resources/Images/New.png b/TimetableDesigner/Resources/Images/New.png new file mode 100644 index 0000000..61b1d2a Binary files /dev/null and b/TimetableDesigner/Resources/Images/New.png differ diff --git a/TimetableDesigner/Resources/Images/Open.png b/TimetableDesigner/Resources/Images/Open.png new file mode 100644 index 0000000..1a927a6 Binary files /dev/null and b/TimetableDesigner/Resources/Images/Open.png differ diff --git a/TimetableDesigner/Resources/Images/OpenRecent.png b/TimetableDesigner/Resources/Images/OpenRecent.png new file mode 100644 index 0000000..a560659 Binary files /dev/null and b/TimetableDesigner/Resources/Images/OpenRecent.png differ diff --git a/TimetableDesigner/Resources/Images/Project.png b/TimetableDesigner/Resources/Images/Project.png new file mode 100644 index 0000000..efc1053 Binary files /dev/null and b/TimetableDesigner/Resources/Images/Project.png differ diff --git a/TimetableDesigner/Resources/Images/ProjectSettings.png b/TimetableDesigner/Resources/Images/ProjectSettings.png new file mode 100644 index 0000000..2efceaa Binary files /dev/null and b/TimetableDesigner/Resources/Images/ProjectSettings.png differ diff --git a/TimetableDesigner/Resources/Images/Remove.png b/TimetableDesigner/Resources/Images/Remove.png new file mode 100644 index 0000000..969ede3 Binary files /dev/null and b/TimetableDesigner/Resources/Images/Remove.png differ diff --git a/TimetableDesigner/Resources/Images/Save.png b/TimetableDesigner/Resources/Images/Save.png new file mode 100644 index 0000000..b551de1 Binary files /dev/null and b/TimetableDesigner/Resources/Images/Save.png differ diff --git a/TimetableDesigner/Resources/Images/SaveAs.png b/TimetableDesigner/Resources/Images/SaveAs.png new file mode 100644 index 0000000..e1f8fd1 Binary files /dev/null and b/TimetableDesigner/Resources/Images/SaveAs.png differ diff --git a/TimetableDesigner/TimetableDesigner.csproj b/TimetableDesigner/TimetableDesigner.csproj new file mode 100644 index 0000000..736ee59 --- /dev/null +++ b/TimetableDesigner/TimetableDesigner.csproj @@ -0,0 +1,103 @@ + + + + WinExe + net7.0-windows + enable + true + AnyCPU;x64 + + + + + + + + + + + + + + + + + + + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + + + + + + + + + + + + + + Always + + + + + + Resources.pl-PL.resx + True + True + + + True + True + Resources.resx + + + + + + Resources.pl-PL.Designer.cs + PublicResXFileCodeGenerator + + + PublicResXFileCodeGenerator + Resources.Designer.cs + + + + diff --git a/TimetableDesigner/ViewModels/Base/BaseTabViewModel.cs b/TimetableDesigner/ViewModels/Base/BaseTabViewModel.cs new file mode 100644 index 0000000..b1b5798 --- /dev/null +++ b/TimetableDesigner/ViewModels/Base/BaseTabViewModel.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Media; + +namespace TimetableDesigner.ViewModels.Base +{ + public abstract class BaseTabViewModel : BaseViewModel + { + #region FIELDS + + private ImageSource _tabImage; + private string _tabTitle; + private bool _isTabClosable; + + #endregion + + + + #region PROPERTIES + + public ImageSource TabImage + { + get => _tabImage; + set + { + _tabImage = value; + NotifyPropertyChanged(nameof(TabImage)); + } + } + public string TabTitle + { + get => _tabTitle; + set + { + _tabTitle = value; + NotifyPropertyChanged(nameof(TabTitle)); + } + } + public bool IsTabClosable + { + get => _isTabClosable; + set + { + _isTabClosable = value; + NotifyPropertyChanged(nameof(IsTabClosable)); + } + } + + #endregion + } +} diff --git a/TimetableDesigner/ViewModels/Base/BaseViewModel.cs b/TimetableDesigner/ViewModels/Base/BaseViewModel.cs new file mode 100644 index 0000000..c996524 --- /dev/null +++ b/TimetableDesigner/ViewModels/Base/BaseViewModel.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TimetableDesigner.ViewModels.Base +{ + public abstract class BaseViewModel : INotifyPropertyChanged + { + #region PROTECTED METHODS + + protected void NotifyPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + + #endregion + + + + #region EVENTS + + public event PropertyChangedEventHandler? PropertyChanged; + + #endregion + } +} diff --git a/TimetableDesigner/ViewModels/ClassroomEditTabViewModel.cs b/TimetableDesigner/ViewModels/ClassroomEditTabViewModel.cs new file mode 100644 index 0000000..6e15a52 --- /dev/null +++ b/TimetableDesigner/ViewModels/ClassroomEditTabViewModel.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TimetableDesigner.ViewModels.Base; +using TimetableDesigner.ViewModels.Models; + +namespace TimetableDesigner.ViewModels +{ + public class ClassroomEditTabViewModel : BaseTabViewModel + { + #region FIELDS + + private ClassroomViewModel _classroom; + + #endregion + + + + #region PROPERTIES + + public ClassroomViewModel Classroom + { + get => _classroom; + set + { + if (_classroom != value) + { + _classroom = value; + NotifyPropertyChanged(nameof(Classroom)); + } + } + } + + #endregion + + + + #region CONSTRUCTORS + + public ClassroomEditTabViewModel() : this(new ClassroomViewModel(new Core.Classroom())) + { } + + public ClassroomEditTabViewModel(ClassroomViewModel classroom) + { + _classroom = classroom; + } + + #endregion + } +} diff --git a/TimetableDesigner/ViewModels/MainViewModel.cs b/TimetableDesigner/ViewModels/MainViewModel.cs new file mode 100644 index 0000000..70c3c6b --- /dev/null +++ b/TimetableDesigner/ViewModels/MainViewModel.cs @@ -0,0 +1,214 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; +using System.Windows.Input; +using TimetableDesigner.Commands; +using TimetableDesigner.ViewModels.Base; +using System.Windows.Navigation; +using TimetableDesigner.Core; +using System.Windows; +using TimetableDesigner.Properties; +using TimetableDesigner.MessageBox; +using System.Reflection; +using TimetableDesigner.ViewModels.Models; +using System.Windows.Data; + +namespace TimetableDesigner.ViewModels +{ + class MainViewModel : BaseViewModel + { + #region FIELDS + + private ProjectViewModel? _project; + + private ObservableCollection _tabs; + private BaseTabViewModel? _selectedTab; + + #endregion + + + + #region PROPERTIES + + public string Version { get; set; } + + public ICommand CloseTabCommand { get; set; } + public ICommand NewProjectCommand { get; set; } + public ICommand OpenProjectCommand { get; set; } + public ICommand ProjectSettingsCommand { get; set; } + public ICommand NewClassroomCommand { get; set; } + public ICommand EditClassroomCommand { get; set; } + public ICommand RemoveClassroomCommand { get; set; } + + public ObservableCollection Tabs + { + get => _tabs; + set + { + _tabs = value; + NotifyPropertyChanged(nameof(Tabs)); + } + } + public BaseTabViewModel? SelectedTab + { + get => _selectedTab; + set + { + _selectedTab = value; + NotifyPropertyChanged(nameof(SelectedTab)); + } + } + + public ProjectViewModel? Project + { + get => _project; + set + { + if (value != _project) + { + _project = value; + NotifyPropertyChanged(nameof(Project)); + } + } + } + + #endregion + + + + #region CONSTRUCTORS + + public MainViewModel() + { + Version = Assembly.GetExecutingAssembly().GetName().Version.ToString(); + + CloseTabCommand = new RelayCommand(CloseTab); + NewProjectCommand = new RelayCommand(param => NewProject()); + OpenProjectCommand = new RelayCommand(param => OpenProject()); + ProjectSettingsCommand = new RelayCommand(param => ProjectSettings()); + NewClassroomCommand = new RelayCommand(param => NewClassroom()); + EditClassroomCommand = new RelayCommand(EditClassroom); + RemoveClassroomCommand = new RelayCommand(DeleteClassroom); + + _tabs = new ObservableCollection + { + new WelcomeTabViewModel() { TabTitle = Resources.Tabs_Welcome } + }; + _selectedTab = Tabs.Last(); + } + + #endregion + + + + #region PUBLIC METHODS + + private void CloseTab(BaseTabViewModel tab) + { + if (SelectedTab == tab) + { + int index = Tabs.IndexOf(tab); + int before = index - 1; + int after = index + 1; + + BaseTabViewModel newSelectedTab = null; + if (before >= 0) + { + newSelectedTab = Tabs[before]; + } + else if (after >= 0 && after < Tabs.Count - 1) + { + newSelectedTab = Tabs[after]; + } + SelectedTab = newSelectedTab; + } + Tabs.Remove(tab); + } + + private void OpenProject() + { + } + + private void NewProject() + { + if (Project is not null) + { + MessageBoxYesNoCancelResult result = MessageBoxService.ShowYesNoCancelQuestion(Resources.Main_Message_SaveCurrentProject); + + switch (result) + { + case MessageBoxYesNoCancelResult.Yes: break; + case MessageBoxYesNoCancelResult.No: break; + default: return; + } + } + Tabs.Clear(); + + Project project = new Project() + { + Name = Resources.Global_DefaultProjectName, + }; + Project = new ProjectViewModel(project); + ProjectSettings(); + } + + private void ProjectSettings() + { + if (Project is not null) + { + ProjectSettingsTabViewModel projectSettingsTabVM = new ProjectSettingsTabViewModel() + { + Project = Project, + TabTitle = Resources.Tabs_ProjectSettings, + IsTabClosable = true, + }; + Tabs.Add(projectSettingsTabVM); + SelectedTab = Tabs.Last(); + } + } + + private void NewClassroom() + { + if (Project is not null) + { + Classroom classroom = new Classroom() + { + Name = Resources.Global_DefaultClassroomName + }; + ClassroomViewModel classroomVM = new ClassroomViewModel(classroom); + Project.Classrooms.Add(classroomVM); + EditClassroom(classroomVM); + } + } + + private void EditClassroom(ClassroomViewModel classroomViewModel) + { + Debug.WriteLine("textedit"); + ClassroomEditTabViewModel classroomEdit = new ClassroomEditTabViewModel() + { + Classroom = classroomViewModel, + TabTitle = $"{Resources.Tabs_ClassroomEdit}: {classroomViewModel.Name}", + IsTabClosable = true + }; + Tabs.Add(classroomEdit); + SelectedTab = classroomEdit; + } + + private void DeleteClassroom(ClassroomViewModel classroomViewModel) + { + Debug.WriteLine("textdelete"); + if (Project is not null) + { + Project.Classrooms.Remove(classroomViewModel); + } + } + + #endregion + } +} diff --git a/TimetableDesigner/ViewModels/Models/ClassroomViewModel.cs b/TimetableDesigner/ViewModels/Models/ClassroomViewModel.cs new file mode 100644 index 0000000..60ca273 --- /dev/null +++ b/TimetableDesigner/ViewModels/Models/ClassroomViewModel.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TimetableDesigner.Core; +using TimetableDesigner.ViewModels.Base; + +namespace TimetableDesigner.ViewModels.Models +{ + public class ClassroomViewModel : BaseViewModel + { + #region FIELDS + + private Classroom _classroom; + + #endregion + + + + #region PROPERTIES + + public Classroom Classroom => _classroom; + + public string Name + { + get => _classroom.Name; + set + { + if (_classroom.Name != value) + { + _classroom.Name = value; + NotifyPropertyChanged(nameof(Name)); + } + } + } + public string Description + { + get => _classroom.Description; + set + { + if (_classroom.Description != value) + { + _classroom.Description = value; + NotifyPropertyChanged(nameof(Description)); + } + } + } + public bool IsCapacityLimited + { + get => _classroom.IsCapacityLimited; + set + { + if (_classroom.IsCapacityLimited != value) + { + _classroom.IsCapacityLimited = value; + NotifyPropertyChanged(nameof(IsCapacityLimited)); + } + } + } + public uint Capacity + { + get => _classroom.Capacity; + set + { + if (_classroom.Capacity != value) + { + _classroom.Capacity = value; + NotifyPropertyChanged(nameof(Capacity)); + } + } + } + + #endregion + + + + #region CONSTRUCTORS + + public ClassroomViewModel(Classroom classroom) + { + _classroom = classroom; + } + + #endregion + } +} diff --git a/TimetableDesigner/ViewModels/Models/ProjectViewModel.cs b/TimetableDesigner/ViewModels/Models/ProjectViewModel.cs new file mode 100644 index 0000000..b4a5b2d --- /dev/null +++ b/TimetableDesigner/ViewModels/Models/ProjectViewModel.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TimetableDesigner.Core; +using TimetableDesigner.ViewModels.Base; + +namespace TimetableDesigner.ViewModels.Models +{ + public class ProjectViewModel : BaseViewModel + { + #region FIELDS + + private Project _project; + + #endregion + + + + #region PROPERTIES + + public Project Project => _project; + + public string Name + { + get => Project.Name; + set + { + if (Project.Name != value) + { + Project.Name = value; + NotifyPropertyChanged(nameof(Name)); + } + } + } + public string Author + { + get => Project.Author; + set + { + if (Project.Author != value) + { + Project.Author = value; + NotifyPropertyChanged(nameof(Author)); + } + } + } + public string Description + { + get => Project.Description; + set + { + if (Project.Description != value) + { + Project.Description = value; + NotifyPropertyChanged(nameof(Description)); + } + } + } + public TimetableTemplateViewModel TimetableTemplate { get; set; } + public ObservableCollection Classrooms { get; set; } + + #endregion + + + + #region CONSTRUCTORS + + public ProjectViewModel(Project project) + { + _project = project; + + TimetableTemplate = new TimetableTemplateViewModel(_project.TimetableTemplate); + + Classrooms = new ObservableCollection(); + Classrooms.CollectionChanged += Classrooms_CollectionChanged; + } + + #endregion + + + + #region PRIVATE METHODS + + private void Classrooms_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + IList? added = e.NewItems as IList; + IList? removed = e.OldItems as IList; + + if (removed is not null) + { + foreach (ClassroomViewModel vm in removed) + { + _project.Classrooms.Remove(vm.Classroom); + } + } + + if (added is not null) + { + foreach (ClassroomViewModel vm in added) + { + _project.Classrooms.Add(vm.Classroom); + } + } + } + + #endregion + } +} diff --git a/TimetableDesigner/ViewModels/Models/TeacherViewModel.cs b/TimetableDesigner/ViewModels/Models/TeacherViewModel.cs new file mode 100644 index 0000000..679ed7f --- /dev/null +++ b/TimetableDesigner/ViewModels/Models/TeacherViewModel.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TimetableDesigner.Core; +using TimetableDesigner.ViewModels.Base; + +namespace TimetableDesigner.ViewModels.Models +{ + public class TeacherViewModel : BaseViewModel + { + #region FIELDS + + private Teacher _teacher; + + #endregion + + + + #region PROPERTIES + + public Teacher Teacher => _teacher; + + public string Name + { + get => _teacher.Name; + set + { + if (_teacher.Name != value) + { + _teacher.Name = value; + NotifyPropertyChanged(nameof(Name)); + } + } + } + public string Description + { + get => _teacher.Description; + set + { + if (_teacher.Description != value) + { + _teacher.Description = value; + NotifyPropertyChanged(nameof(Description)); + } + } + } + + #endregion + + + + #region CONSTRUCTORS + + public TeacherViewModel(Teacher teacher) + { + _teacher = teacher; + } + + #endregion + } +} diff --git a/TimetableDesigner/ViewModels/Models/TimetableTemplateViewModel.cs b/TimetableDesigner/ViewModels/Models/TimetableTemplateViewModel.cs new file mode 100644 index 0000000..d434c83 --- /dev/null +++ b/TimetableDesigner/ViewModels/Models/TimetableTemplateViewModel.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TimetableDesigner.Core; +using TimetableDesigner.ViewModels.Base; + +namespace TimetableDesigner.ViewModels.Models +{ + public class TimetableTemplateViewModel : BaseViewModel + { + #region FIELDS + + private TimetableTemplate _timetableTemplate; + + #endregion + + + + #region PROPERTIES + + public TimetableTemplate TimetableTemplate => _timetableTemplate; + + public ObservableCollection Days => new ObservableCollection(_timetableTemplate.Days); + public ObservableCollection Slots => new ObservableCollection(_timetableTemplate.Slots); + + #endregion + + + + #region CONSTRUCTORS + + public TimetableTemplateViewModel(TimetableTemplate timetableTemplate) + { + _timetableTemplate = timetableTemplate; + } + + #endregion + + + + #region PUBLIC METHODS + + public void AddDay(TimetableDay day) + { + _timetableTemplate.AddDay(day); + NotifyPropertyChanged(nameof(Days)); + } + + public void RemoveDay(TimetableDay day) + { + _timetableTemplate.RemoveDay(day); + NotifyPropertyChanged(nameof(Days)); + } + + public void AddSlot(TimetableSlot slot) + { + _timetableTemplate.AddSlot(slot); + NotifyPropertyChanged(nameof(Slots)); + } + + public void RemoveSlot(TimetableSlot slot) + { + _timetableTemplate.RemoveSlot(slot); + NotifyPropertyChanged(nameof(Slots)); + } + + #endregion + } +} diff --git a/TimetableDesigner/ViewModels/ProjectSettingsTabViewModel.cs b/TimetableDesigner/ViewModels/ProjectSettingsTabViewModel.cs new file mode 100644 index 0000000..9de6f09 --- /dev/null +++ b/TimetableDesigner/ViewModels/ProjectSettingsTabViewModel.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Input; +using TimetableDesigner.Commands; +using TimetableDesigner.Core; +using TimetableDesigner.MessageBox; +using TimetableDesigner.Properties; +using TimetableDesigner.ViewModels.Base; +using TimetableDesigner.ViewModels.Models; + +namespace TimetableDesigner.ViewModels +{ + public class ProjectSettingsTabViewModel : BaseTabViewModel + { + #region FIELDS + + private string _newDayName; + private DateTime? _newSlotFrom; + private DateTime? _newSlotTo; + + #endregion + + + + #region PROPERTIES + + public ICommand AddDayCommand { get; set; } + public ICommand AddSlotCommand { get; set; } + public ICommand RemoveDayCommand { get; set; } + public ICommand RemoveSlotCommand { get; set; } + + public ProjectViewModel? Project { get; set; } + + public string NewDayName + { + get => _newDayName; + set + { + _newDayName = value; + NotifyPropertyChanged(nameof(NewDayName)); + } + } + + public DateTime? NewSlotFrom + { + get => _newSlotFrom; + set + { + _newSlotFrom = value; + NotifyPropertyChanged(nameof(NewSlotFrom)); + } + } + public DateTime? NewSlotTo + { + get => _newSlotTo; + set + { + _newSlotTo = value; + NotifyPropertyChanged(nameof(NewSlotTo)); + } + } + + #endregion + + + + #region CONSTRUCTORS + + public ProjectSettingsTabViewModel() + { + Project = new ProjectViewModel(new Project()); + + AddDayCommand = new RelayCommand(param => AddDay()); + AddSlotCommand = new RelayCommand(param => AddSlot()); + RemoveDayCommand = new RelayCommand(RemoveDay); + RemoveSlotCommand = new RelayCommand(RemoveSlot); + + _newDayName = string.Empty; + _newSlotFrom = new DateTime(1, 1, 1, 8, 0, 0); + _newSlotTo = new DateTime(1, 1, 1, 9, 0, 0); + } + + #endregion + + + + #region PRIVATE METHODS + + private void AddDay() + { + if (!string.IsNullOrWhiteSpace(NewDayName)) + { + Project.TimetableTemplate.AddDay(new TimetableDay(NewDayName)); + NewDayName = string.Empty; + } + } + + private void RemoveDay(TimetableDay day) => Project.TimetableTemplate.RemoveDay(day); + + private void AddSlot() + { + if (NewSlotFrom.HasValue && NewSlotTo.HasValue) + { + TimeOnly from = new TimeOnly(NewSlotFrom.Value.Hour, NewSlotFrom.Value.Minute); + TimeOnly to = new TimeOnly(NewSlotTo.Value.Hour, NewSlotTo.Value.Minute); + if (from >= to) + { + MessageBoxService.ShowError(Resources.ProjectSettings_Message_FromHigherThanTo); + return; + } + + try + { + Project.TimetableTemplate.AddSlot(new TimetableSlot(from, to)); + + double delta = (to - from).TotalMinutes; + DateTime newFrom = NewSlotTo.Value; + DateTime newTo = NewSlotTo.Value.AddMinutes(delta); + NewSlotFrom = newFrom; + NewSlotTo = newTo; + } + catch (ArgumentException) + { + MessageBoxService.ShowError(Resources.ProjectSettings_Message_SlotCollision); + } + } + } + + private void RemoveSlot(TimetableSlot slot) => Project.TimetableTemplate.RemoveSlot(slot); + + #endregion + } +} diff --git a/TimetableDesigner/ViewModels/TeacherEditTabViewModel.cs b/TimetableDesigner/ViewModels/TeacherEditTabViewModel.cs new file mode 100644 index 0000000..eadf0dd --- /dev/null +++ b/TimetableDesigner/ViewModels/TeacherEditTabViewModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TimetableDesigner.ViewModels.Base; + +namespace TimetableDesigner.ViewModels +{ + public class TeacherEditTabViewModel : BaseViewModel + { + } +} diff --git a/TimetableDesigner/ViewModels/WelcomeTabViewModel.cs b/TimetableDesigner/ViewModels/WelcomeTabViewModel.cs new file mode 100644 index 0000000..0c833ca --- /dev/null +++ b/TimetableDesigner/ViewModels/WelcomeTabViewModel.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TimetableDesigner.ViewModels.Base; + +namespace TimetableDesigner.ViewModels +{ + public class WelcomeTabViewModel : BaseTabViewModel + { + #region CONSTRUCTORS + + public WelcomeTabViewModel() + { } + + #endregion + } +} diff --git a/TimetableDesigner/Views/ClassroomEditTabView.xaml b/TimetableDesigner/Views/ClassroomEditTabView.xaml new file mode 100644 index 0000000..fdf5937 --- /dev/null +++ b/TimetableDesigner/Views/ClassroomEditTabView.xaml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + diff --git a/TimetableDesigner/Views/ClassroomEditTabView.xaml.cs b/TimetableDesigner/Views/ClassroomEditTabView.xaml.cs new file mode 100644 index 0000000..539f58b --- /dev/null +++ b/TimetableDesigner/Views/ClassroomEditTabView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace TimetableDesigner.Views +{ + /// + /// Interaction logic for ClassroomEditTabView.xaml + /// + public partial class ClassroomEditTabView : UserControl + { + public ClassroomEditTabView() + { + InitializeComponent(); + } + } +} diff --git a/TimetableDesigner/Views/MainWindow.xaml b/TimetableDesigner/Views/MainWindow.xaml new file mode 100644 index 0000000..9e9613d --- /dev/null +++ b/TimetableDesigner/Views/MainWindow.xaml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TimetableDesigner/Views/MainWindow.xaml.cs b/TimetableDesigner/Views/MainWindow.xaml.cs new file mode 100644 index 0000000..034ff1d --- /dev/null +++ b/TimetableDesigner/Views/MainWindow.xaml.cs @@ -0,0 +1,26 @@ +using Fluent; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace TimetableDesigner.Views +{ + public partial class MainWindow : RibbonWindow + { + public MainWindow() + { + InitializeComponent(); + } + } +} diff --git a/TimetableDesigner/Views/ProjectSettingsTabView.xaml b/TimetableDesigner/Views/ProjectSettingsTabView.xaml new file mode 100644 index 0000000..d20a100 --- /dev/null +++ b/TimetableDesigner/Views/ProjectSettingsTabView.xaml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TimetableDesigner/Views/ProjectSettingsTabView.xaml.cs b/TimetableDesigner/Views/ProjectSettingsTabView.xaml.cs new file mode 100644 index 0000000..cbdd6f8 --- /dev/null +++ b/TimetableDesigner/Views/ProjectSettingsTabView.xaml.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace TimetableDesigner.Views +{ + public partial class ProjectSettingsTabView : UserControl + { + public ProjectSettingsTabView() + { + InitializeComponent(); + } + } +} diff --git a/TimetableDesigner/Views/TeacherEditTabView.xaml b/TimetableDesigner/Views/TeacherEditTabView.xaml new file mode 100644 index 0000000..e29592f --- /dev/null +++ b/TimetableDesigner/Views/TeacherEditTabView.xaml @@ -0,0 +1,12 @@ + + + + + diff --git a/TimetableDesigner/Views/TeacherEditTabView.xaml.cs b/TimetableDesigner/Views/TeacherEditTabView.xaml.cs new file mode 100644 index 0000000..4836e41 --- /dev/null +++ b/TimetableDesigner/Views/TeacherEditTabView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace TimetableDesigner.Views +{ + /// + /// Interaction logic for TeacherEditTabView.xaml + /// + public partial class TeacherEditTabView : UserControl + { + public TeacherEditTabView() + { + InitializeComponent(); + } + } +} diff --git a/TimetableDesigner/Views/WelcomeTabView.xaml b/TimetableDesigner/Views/WelcomeTabView.xaml new file mode 100644 index 0000000..118f515 --- /dev/null +++ b/TimetableDesigner/Views/WelcomeTabView.xaml @@ -0,0 +1,14 @@ + + + + + + + diff --git a/TimetableDesigner/Views/WelcomeTabView.xaml.cs b/TimetableDesigner/Views/WelcomeTabView.xaml.cs new file mode 100644 index 0000000..3d87246 --- /dev/null +++ b/TimetableDesigner/Views/WelcomeTabView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace TimetableDesigner.Views +{ + /// + /// Interaction logic for WelcomeTabView.xaml + /// + public partial class WelcomeTabView : UserControl + { + public WelcomeTabView() + { + InitializeComponent(); + } + } +}