From 8d6675349892a0603748c5e3dae7e248b290e78a Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Wed, 14 Aug 2013 10:18:29 +0700 Subject: [PATCH 01/18] Create ChoiceScreen class --- StudentManager/Main.cs | 60 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/StudentManager/Main.cs b/StudentManager/Main.cs index 917cf93..a4c9672 100755 --- a/StudentManager/Main.cs +++ b/StudentManager/Main.cs @@ -1,13 +1,71 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Collections.Specialized; +using System.Collections; namespace StudentManager { - class MainClass + abstract class ChoiceScreen { + protected OrderedDictionary commands; + protected bool running = false; + public String Message { get; set; } + + public ChoiceScreen() + { + commands = new OrderedDictionary(); + } + + public void AddChoice(String key, String label, Action action) + { + commands.Add(key, new Tuple(label, action)); + } + + public void Start() + { + this.running = true; + while (this.running) + { + foreach (DictionaryEntry de in commands) + { + Console.WriteLine( + String.Format("{0} - {1}", + de.Key, + (de.Value as Tuple).Item1)); + } + + String choice = System.Console.ReadLine(); + if (commands.Contains(choice)) + { + (commands[choice] as Tuple).Item2.Invoke(); + } + } + } + + public void Stop() + { + this.running = false; + } + } + + class MainClass : ChoiceScreen + { + + public MainClass() + { + AddChoice("1", "Create new class", CreateNewClass); + + AddChoice("0", "Quit", Stop); + } + + public void CreateNewClass() + { + } + public static void Main(string[] args) { + new MainClass().Start(); } } } From c4a0051dde272efc5a2d671ed29a97f874181890 Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Wed, 14 Aug 2013 10:42:37 +0700 Subject: [PATCH 02/18] Refactoring - Move ChoiceScreen and MainClass to TextInterface.cs, inside TextUi namespace - Rename MainClass to MainScreen - Minimal implementation in Main.cs --- StudentManager/Main.cs | 62 ++--------------------- StudentManager/TextInterface.cs | 89 +++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 59 deletions(-) create mode 100644 StudentManager/TextInterface.cs diff --git a/StudentManager/Main.cs b/StudentManager/Main.cs index a4c9672..7951757 100755 --- a/StudentManager/Main.cs +++ b/StudentManager/Main.cs @@ -1,71 +1,15 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Collections.Specialized; -using System.Collections; +using StudentManager.TextUi; namespace StudentManager { - abstract class ChoiceScreen + class MainClass { - protected OrderedDictionary commands; - protected bool running = false; - public String Message { get; set; } - - public ChoiceScreen() - { - commands = new OrderedDictionary(); - } - - public void AddChoice(String key, String label, Action action) - { - commands.Add(key, new Tuple(label, action)); - } - - public void Start() - { - this.running = true; - while (this.running) - { - foreach (DictionaryEntry de in commands) - { - Console.WriteLine( - String.Format("{0} - {1}", - de.Key, - (de.Value as Tuple).Item1)); - } - - String choice = System.Console.ReadLine(); - if (commands.Contains(choice)) - { - (commands[choice] as Tuple).Item2.Invoke(); - } - } - } - - public void Stop() - { - this.running = false; - } - } - - class MainClass : ChoiceScreen - { - - public MainClass() - { - AddChoice("1", "Create new class", CreateNewClass); - - AddChoice("0", "Quit", Stop); - } - - public void CreateNewClass() - { - } - public static void Main(string[] args) { - new MainClass().Start(); + new MainScreen().Start(); } } } diff --git a/StudentManager/TextInterface.cs b/StudentManager/TextInterface.cs new file mode 100644 index 0000000..c2294b6 --- /dev/null +++ b/StudentManager/TextInterface.cs @@ -0,0 +1,89 @@ +// +// TextInterface.cs +// +// Author: +// chin <${AuthorEmail}> +// +// Copyright (c) 2013 chin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +using System; +using System.Collections.Specialized; +using System.Collections; + +namespace StudentManager.TextUi +{ + abstract class ChoiceScreen + { + protected OrderedDictionary commands; + protected bool running = false; + + public String Message { get; set; } + + public ChoiceScreen() + { + commands = new OrderedDictionary(); + } + + public void AddChoice(String key, String label, Action action) + { + commands.Add(key, new Tuple(label, action)); + } + + public void Start() + { + this.running = true; + while (this.running) + { + foreach (DictionaryEntry de in commands) + { + Console.WriteLine( + String.Format("{0} - {1}", + de.Key, + (de.Value as Tuple).Item1)); + } + + String choice = System.Console.ReadLine(); + if (commands.Contains(choice)) + { + (commands[choice] as Tuple).Item2.Invoke(); + } else + { + Console.WriteLine("No such choice!"); + } + } + } + + public void Stop() + { + this.running = false; + } + } + + class MainScreen : ChoiceScreen + { + public MainScreen() + { + AddChoice("1", "Create new class", CreateNewClass); + + AddChoice("q", "Quit", Stop); + } + + public void CreateNewClass() + { + } + } +} + From 25e837d1585eb42d5506a80d5c188b75e18a1e74 Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Wed, 14 Aug 2013 12:44:12 +0700 Subject: [PATCH 03/18] Partially implement class screen --- StudentManager/TextInterface.cs | 55 ++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/StudentManager/TextInterface.cs b/StudentManager/TextInterface.cs index c2294b6..303eada 100644 --- a/StudentManager/TextInterface.cs +++ b/StudentManager/TextInterface.cs @@ -66,7 +66,7 @@ public void Start() } } - public void Stop() + public virtual void Stop() { this.running = false; } @@ -74,15 +74,60 @@ public void Stop() class MainScreen : ChoiceScreen { - public MainScreen() + Manager manager; + + public MainScreen(Manager manager) { - AddChoice("1", "Create new class", CreateNewClass); + this.manager = manager; + + AddChoice("1", "Manage classes", ManageClasses); AddChoice("q", "Quit", Stop); } - - public void CreateNewClass() + + public void ManageClasses() + { + new ClassScreen(this.manager).Start(); + } + + public override void Stop() + { + base.Stop(); + } + } + + class ClassScreen : ChoiceScreen + { + Manager manager; + + public ClassScreen(Manager manager) { + this.manager = manager; + + AddChoice("1", "List classes", ListClasses); + AddChoice("2", "Manage timetable", ManageTimetable); + AddChoice("b", "Back", Stop); + } + + public void ListClasses() + { + foreach (var cl in manager.Classes) + { + Console.WriteLine(String.Format("{0} {1} {2}", cl.ID, cl.Name, cl.Teacher)); + } + + Class c = null; + do + { + Console.Write("Please select a class ID: "); + String id = System.Console.ReadLine(); + c = manager.GetClassById(id); + } while (c == null); + } + + public void ManageTimetable() + { + } } } From 7c27b0d87366f51dcff4f1b0368eb1cb29a7e383 Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Wed, 14 Aug 2013 12:44:40 +0700 Subject: [PATCH 04/18] Introduce IPersistenceService and refactor XMLDatabase --- StudentManager/XMLDatabase.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/StudentManager/XMLDatabase.cs b/StudentManager/XMLDatabase.cs index b68eab4..f66de86 100644 --- a/StudentManager/XMLDatabase.cs +++ b/StudentManager/XMLDatabase.cs @@ -25,21 +25,27 @@ namespace StudentManager { - public class XMLDatabase + public interface IPersistenceService { - public void save(String path, T data) + void save(String uri, T data); + T load(String uri); + } + + public class XMLDatabase : IPersistenceService + { + public void save(String uri, T data) { var serializer = new XmlSerializer(typeof(T)); - using (var textWriter = new StreamWriter(path)) { + using (var textWriter = new StreamWriter(uri)) { serializer.Serialize(textWriter, data); } } - public T load(String path) + public T load(String uri) { T data; var serializer = new XmlSerializer(typeof(T)); - using (var textReader = new StreamReader(path)) { + using (var textReader = new StreamReader(uri)) { data = (T) serializer.Deserialize(textReader); } return data; From e21552de5cc3ba36789dd466a39fd2d20094fd33 Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Wed, 14 Aug 2013 13:19:50 +0700 Subject: [PATCH 05/18] Implement hooks in ChoiceScreen --- StudentManager/TextInterface.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/StudentManager/TextInterface.cs b/StudentManager/TextInterface.cs index 303eada..552d771 100644 --- a/StudentManager/TextInterface.cs +++ b/StudentManager/TextInterface.cs @@ -29,6 +29,8 @@ abstract class ChoiceScreen { protected OrderedDictionary commands; protected bool running = false; + protected event Action PreHook; + protected event Action PostHook; public String Message { get; set; } @@ -47,6 +49,8 @@ public void Start() this.running = true; while (this.running) { + if (PreHook != null) + PreHook(); foreach (DictionaryEntry de in commands) { Console.WriteLine( @@ -59,6 +63,8 @@ public void Start() if (commands.Contains(choice)) { (commands[choice] as Tuple).Item2.Invoke(); + if (PostHook != null) + PostHook(); } else { Console.WriteLine("No such choice!"); From 5c079b8df79dd5ac3cd4c5d7ba6d8782c49ba676 Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Wed, 14 Aug 2013 13:20:41 +0700 Subject: [PATCH 06/18] Clearscreen in ChoiceScreen --- StudentManager/TextInterface.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/StudentManager/TextInterface.cs b/StudentManager/TextInterface.cs index 552d771..5d9cb91 100644 --- a/StudentManager/TextInterface.cs +++ b/StudentManager/TextInterface.cs @@ -29,6 +29,7 @@ abstract class ChoiceScreen { protected OrderedDictionary commands; protected bool running = false; + protected bool ClearScreen = false; protected event Action PreHook; protected event Action PostHook; @@ -62,6 +63,8 @@ public void Start() String choice = System.Console.ReadLine(); if (commands.Contains(choice)) { + if (this.ClearScreen) + System.Console.Clear(); (commands[choice] as Tuple).Item2.Invoke(); if (PostHook != null) PostHook(); From 2b40fe3f2b56092995fe5d49acfea79ff8d551de Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Wed, 14 Aug 2013 13:21:15 +0700 Subject: [PATCH 07/18] Remove Message in ChoiceScreen, favoring hooks --- StudentManager/TextInterface.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/StudentManager/TextInterface.cs b/StudentManager/TextInterface.cs index 5d9cb91..09cccba 100644 --- a/StudentManager/TextInterface.cs +++ b/StudentManager/TextInterface.cs @@ -33,8 +33,6 @@ abstract class ChoiceScreen protected event Action PreHook; protected event Action PostHook; - public String Message { get; set; } - public ChoiceScreen() { commands = new OrderedDictionary(); From 6152ab03ef403e2f8f2ad12f6dd84f95295521b7 Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Wed, 14 Aug 2013 13:23:34 +0700 Subject: [PATCH 08/18] Minor refactoring --- StudentManager/TextInterface.cs | 38 +++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/StudentManager/TextInterface.cs b/StudentManager/TextInterface.cs index 09cccba..c947420 100644 --- a/StudentManager/TextInterface.cs +++ b/StudentManager/TextInterface.cs @@ -27,8 +27,9 @@ namespace StudentManager.TextUi { abstract class ChoiceScreen { - protected OrderedDictionary commands; - protected bool running = false; + private OrderedDictionary commands; + private bool running = false; + protected bool ClearScreen = false; protected event Action PreHook; protected event Action PostHook; @@ -43,7 +44,7 @@ public void AddChoice(String key, String label, Action action) commands.Add(key, new Tuple(label, action)); } - public void Start() + public virtual void Start() { this.running = true; while (this.running) @@ -59,6 +60,9 @@ public void Start() } String choice = System.Console.ReadLine(); + // FIXME This implementation does not allow key aliases + // i.e. using both "b"(ack) and "q"(uit) for the + // quit action on the main screen. if (commands.Contains(choice)) { if (this.ClearScreen) @@ -88,7 +92,7 @@ public MainScreen(Manager manager) this.manager = manager; AddChoice("1", "Manage classes", ManageClasses); - + AddChoice("2", "Manage timetable", ManageTimetable); AddChoice("q", "Quit", Stop); } @@ -97,6 +101,11 @@ public void ManageClasses() new ClassScreen(this.manager).Start(); } + public void ManageTimetable() + { + + } + public override void Stop() { base.Stop(); @@ -111,8 +120,8 @@ public ClassScreen(Manager manager) { this.manager = manager; - AddChoice("1", "List classes", ListClasses); - AddChoice("2", "Manage timetable", ManageTimetable); + AddChoice("1", "Add a class", AddClass); + AddChoice("2", "Select a class to edit", SelectClass); AddChoice("b", "Back", Stop); } @@ -122,19 +131,20 @@ public void ListClasses() { Console.WriteLine(String.Format("{0} {1} {2}", cl.ID, cl.Name, cl.Teacher)); } + } - Class c = null; - do - { - Console.Write("Please select a class ID: "); - String id = System.Console.ReadLine(); - c = manager.GetClassById(id); - } while (c == null); + public void AddClass() + { } - public void ManageTimetable() + public void SelectClass() { + } + public override void Start() + { + ListClasses(); + base.Start(); } } } From 4f2ba0e3eead26989dd7f2499c3acbb8dcb9c31a Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Wed, 14 Aug 2013 13:27:17 +0700 Subject: [PATCH 09/18] More hooks --- StudentManager/TextInterface.cs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/StudentManager/TextInterface.cs b/StudentManager/TextInterface.cs index c947420..1b0aba4 100644 --- a/StudentManager/TextInterface.cs +++ b/StudentManager/TextInterface.cs @@ -30,9 +30,9 @@ abstract class ChoiceScreen private OrderedDictionary commands; private bool running = false; - protected bool ClearScreen = false; - protected event Action PreHook; - protected event Action PostHook; + protected event Action PreMenuHook; + protected event Action PreActionHook; + protected event Action PostActionHook; public ChoiceScreen() { @@ -49,8 +49,8 @@ public virtual void Start() this.running = true; while (this.running) { - if (PreHook != null) - PreHook(); + if (PreMenuHook != null) + PreMenuHook(); foreach (DictionaryEntry de in commands) { Console.WriteLine( @@ -65,11 +65,13 @@ public virtual void Start() // quit action on the main screen. if (commands.Contains(choice)) { - if (this.ClearScreen) - System.Console.Clear(); + if (PreActionHook != null) + PreActionHook(); + (commands[choice] as Tuple).Item2.Invoke(); - if (PostHook != null) - PostHook(); + + if (PostActionHook != null) + PostActionHook(); } else { Console.WriteLine("No such choice!"); From aeaed160cf1722a8f63a68a7d5f9d468301d3297 Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Wed, 14 Aug 2013 14:16:43 +0700 Subject: [PATCH 10/18] Make Class not inherited from Identity --- StudentManager/Class.cs | 2 +- StudentManager/Manager.cs | 15 ++++++++---- StudentManager/Tests/TestIdentity.cs | 32 ++++++++++++------------- StudentManager/Tests/TestManager.cs | 6 +---- StudentManager/Tests/TestPersistence.cs | 2 -- 5 files changed, 29 insertions(+), 28 deletions(-) diff --git a/StudentManager/Class.cs b/StudentManager/Class.cs index 55efc8b..20fb46c 100755 --- a/StudentManager/Class.cs +++ b/StudentManager/Class.cs @@ -15,7 +15,7 @@ public struct TimeSlot public DateTime EndTime { get; set; } } - public class Class: Identity + public class Class { public string Name { get; set; } diff --git a/StudentManager/Manager.cs b/StudentManager/Manager.cs index 2f0a0af..a09a3c3 100644 --- a/StudentManager/Manager.cs +++ b/StudentManager/Manager.cs @@ -8,7 +8,7 @@ class Manager { // Mutable collections, expected to be edited by // users. - public SortedSet Classes { get; private set; } + public HashSet Classes { get; private set; } public SortedSet Students { get; private set; } @@ -31,7 +31,7 @@ public IEnumerable> Allocation public Manager() { - Classes = new SortedSet(); + Classes = new HashSet(); Students = new SortedSet(); Rooms = new HashSet(); TimeSlots = new HashSet(); @@ -46,10 +46,17 @@ public Student GetStudentById(int id) select student).SingleOrDefault(); } - public Class GetClassById(int id) +// public Class GetClassById(int id) +// { +// return (from cl in this.Classes +// where cl.ID == id +// select cl).SingleOrDefault(); +// } + + public Class GetClassByName(String name) { return (from cl in this.Classes - where cl.ID == id + where cl.Name == name select cl).SingleOrDefault(); } diff --git a/StudentManager/Tests/TestIdentity.cs b/StudentManager/Tests/TestIdentity.cs index abe5245..e6373e4 100755 --- a/StudentManager/Tests/TestIdentity.cs +++ b/StudentManager/Tests/TestIdentity.cs @@ -26,21 +26,21 @@ public void TestStudent() Assert.False(a.Equals(b)); } - [Test] - public void TestClass() - { - var a = new Class() - { - ID = 10 - }; - - var b = new Class() - { - ID = 5 - }; - - Assert.That(a.CompareTo(b) > 0); - Assert.False(a.Equals(b)); - } +// [Test] +// public void TestClass() +// { +// var a = new Class() +// { +// ID = 10 +// }; +// +// var b = new Class() +// { +// ID = 5 +// }; +// +// Assert.That(a.CompareTo(b) > 0); +// Assert.False(a.Equals(b)); +// } } } diff --git a/StudentManager/Tests/TestManager.cs b/StudentManager/Tests/TestManager.cs index b53427d..470c5c8 100755 --- a/StudentManager/Tests/TestManager.cs +++ b/StudentManager/Tests/TestManager.cs @@ -17,7 +17,6 @@ class TestStudentManagement }; private Class c1203l = new Class() { - ID = 3, Name = "C1203L", Teacher = "NhatNK" }; @@ -53,8 +52,7 @@ public void TestRegisterStudent() { [Test] public void TestChangeClassOfStudent() { var bogusClass = new Class() - { - ID = 40, + { Name = "Bogus" }; m.Classes.Add(c1203l); @@ -75,12 +73,10 @@ class TestClassAllocation private Manager m; private Class c1203l = new Class() { - ID = 3, Name = "C1203L" }; private Class bogus = new Class() { - ID = 4, Name = "Bogus" }; diff --git a/StudentManager/Tests/TestPersistence.cs b/StudentManager/Tests/TestPersistence.cs index 65baf13..b958c1b 100644 --- a/StudentManager/Tests/TestPersistence.cs +++ b/StudentManager/Tests/TestPersistence.cs @@ -56,7 +56,6 @@ public void SaveSortedSet() { var s = new SortedSet(); s.Add(new Class() { - ID = 1, Name = "C1203L", Teacher = "NhatNK" }); @@ -82,7 +81,6 @@ public void LoadCollection() { var expected = new SortedSet(); expected.Add(new Class() { - ID = 1, Name = "C1203L", Teacher = "NhatNK" }); From 961df028763b9a18e07d6f25042cf5adcea88ccc Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Wed, 14 Aug 2013 23:31:22 +0700 Subject: [PATCH 11/18] Various changes in TextInterface.cs --- StudentManager/TextInterface.cs | 104 ++++++++++++++++++++++++++------ 1 file changed, 87 insertions(+), 17 deletions(-) diff --git a/StudentManager/TextInterface.cs b/StudentManager/TextInterface.cs index 1b0aba4..6609464 100644 --- a/StudentManager/TextInterface.cs +++ b/StudentManager/TextInterface.cs @@ -20,6 +20,7 @@ // along with this program. If not, see . // using System; +using System.Linq; using System.Collections.Specialized; using System.Collections; @@ -34,8 +35,11 @@ abstract class ChoiceScreen protected event Action PreActionHook; protected event Action PostActionHook; - public ChoiceScreen() + protected ChoiceScreen Parent; + + public ChoiceScreen(ChoiceScreen parent) { + this.Parent = parent; commands = new OrderedDictionary(); } @@ -78,29 +82,42 @@ public virtual void Start() } } } - + + /// + /// Stop this instance and return to parent screen. + /// public virtual void Stop() { this.running = false; } + + /// + /// Stop this instance and chain all parents' Quit method. + /// + public void Quit() + { + this.Stop(); + if (Parent != null) + Parent.Quit(); + } } class MainScreen : ChoiceScreen { Manager manager; - public MainScreen(Manager manager) + public MainScreen(Manager manager): base(null) { this.manager = manager; AddChoice("1", "Manage classes", ManageClasses); AddChoice("2", "Manage timetable", ManageTimetable); - AddChoice("q", "Quit", Stop); + AddChoice("q", "Quit", Quit); } public void ManageClasses() { - new ClassScreen(this.manager).Start(); + new ClassScreen(this.manager, this).Start(); } public void ManageTimetable() @@ -118,35 +135,88 @@ class ClassScreen : ChoiceScreen { Manager manager; - public ClassScreen(Manager manager) + public ClassScreen(Manager manager, ChoiceScreen parent): + base(parent) { this.manager = manager; AddChoice("1", "Add a class", AddClass); AddChoice("2", "Select a class to edit", SelectClass); AddChoice("b", "Back", Stop); - } + AddChoice("q", "Quit", Quit); - public void ListClasses() - { - foreach (var cl in manager.Classes) - { - Console.WriteLine(String.Format("{0} {1} {2}", cl.ID, cl.Name, cl.Teacher)); - } + this.PreMenuHook += () => { + foreach (var cl in manager.Classes) + { + Console.WriteLine(String.Format("{0} {1}", cl.Name, cl.Teacher)); + } + }; } public void AddClass() { + Console.Write("Class name: "); + String name = Console.ReadLine(); + + Console.Write("Teacher: "); + String teacher = Console.ReadLine(); + + var c = new Class() + { + Name = name, + Teacher = teacher + }; + + manager.Classes.Add(c); } - public void SelectClass() + class EachClassScreen : ChoiceScreen { + Class c; + ClassScreen parent; + + public EachClassScreen(Class c, ClassScreen parent): + base(parent) + { + this.c = c; + this.parent = parent; + + AddChoice("1", "Select student ID", SelectStudent); + AddChoice("2", "Remove class", RemoveClass); + AddChoice("3", "Change class info", ChangeClassInfo); + AddChoice("b", "Back", Stop); + AddChoice("q", "Quit", Quit); + + this.PreMenuHook += () => { + var studentList = + (from tuple in this.parent.manager.ClassStudents + where tuple.Item1.Equals(this.c) + select tuple.Item2); + + foreach (Student student in studentList) + { + Console.WriteLine(String.Format("{0} {1}", student.ID, student.Name)); + } + }; + } + + void SelectStudent() + { + } + + void RemoveClass() + { + } + + void ChangeClassInfo() {} } - public override void Start() + public void SelectClass() { - ListClasses(); - base.Start(); + Console.Write("Select a class ID: "); + String name = Console.ReadLine(); + Class c = manager.GetClassByName(name); + new EachClassScreen(c, this).Start(); } } } From 796de4bcef8ad27ff59c6fc4c3177b8ce0214f20 Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Wed, 14 Aug 2013 23:33:28 +0700 Subject: [PATCH 12/18] Project settings --- StudentManager.sln | 12 +++------ StudentManager.userprefs | 39 ++++++++++++++++------------ StudentManager/StudentManager.csproj | 1 + 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/StudentManager.sln b/StudentManager.sln index e4e24fb..71df75a 100644 --- a/StudentManager.sln +++ b/StudentManager.sln @@ -18,6 +18,7 @@ Global StartupItem = StudentManager\StudentManager.csproj Policies = $0 $0.TextStylePolicy = $1 + $1.RemoveTrailingWhitespace = True $1.inheritsSet = VisualStudio $1.inheritsScope = text/plain $1.scope = text/x-csharp @@ -31,12 +32,6 @@ Global $2.EventAddBraceStyle = NextLine $2.EventRemoveBraceStyle = NextLine $2.StatementBraceStyle = NextLine - $2.ElseNewLinePlacement = NewLine - $2.CatchNewLinePlacement = NewLine - $2.FinallyNewLinePlacement = NewLine - $2.WhileNewLinePlacement = DoNotCare - $2.ArrayInitializerWrapping = DoNotChange - $2.ArrayInitializerBraceStyle = NextLine $2.BeforeMethodDeclarationParentheses = False $2.BeforeMethodCallParentheses = False $2.BeforeConstructorDeclarationParentheses = False @@ -48,8 +43,9 @@ Global $2.scope = text/x-csharp $0.TextStylePolicy = $3 $3.FileWidth = 120 - $3.TabsToSpaces = False - $3.inheritsSet = VisualStudio + $3.TabWidth = 4 + $3.EolMarker = Unix + $3.inheritsSet = Mono $3.inheritsScope = text/plain $3.scope = text/plain $0.StandardHeader = $4 diff --git a/StudentManager.userprefs b/StudentManager.userprefs index 00b9ae3..18bdbc2 100644 --- a/StudentManager.userprefs +++ b/StudentManager.userprefs @@ -1,19 +1,32 @@  - + - - - - + + + + + + + + + + + + + + + + + + - - - + + @@ -24,15 +37,7 @@ - - - - - - - - - + diff --git a/StudentManager/StudentManager.csproj b/StudentManager/StudentManager.csproj index 3ccaa59..23841e8 100644 --- a/StudentManager/StudentManager.csproj +++ b/StudentManager/StudentManager.csproj @@ -53,6 +53,7 @@ + \ No newline at end of file From 7b656c16068fcde9a32e00dcf2e38557d58cc3a4 Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Wed, 14 Aug 2013 23:34:51 +0700 Subject: [PATCH 13/18] New constructor for Manager for persistence --- StudentManager/Manager.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/StudentManager/Manager.cs b/StudentManager/Manager.cs index a09a3c3..3060c05 100644 --- a/StudentManager/Manager.cs +++ b/StudentManager/Manager.cs @@ -29,6 +29,10 @@ public IEnumerable> ClassStudents public IEnumerable> Allocation { get { return this.allocation; } } + /// + /// In memory constructor. All data is created fresh. Mostly for testing + /// purposes. + /// public Manager() { Classes = new HashSet(); @@ -39,6 +43,22 @@ public Manager() allocation = new HashSet>(); } + /// + /// Initializes with external data sources. + /// + /// + /// A database accessing object. + /// + /// + /// A mapping between resources' name and their URI. The list of resources that + /// we need is: classes, students, rooms, timeslots, classstudents, allocation. + /// + public Manager(IPersistenceService database, Dictionary UriMapping) + { + Classes = new HashSet(database.load>(UriMapping["classes"])); + Students = new SortedSet(database.load>(UriMapping["students"])); + } + public Student GetStudentById(int id) { return (from student in this.Students From be12c5357ed8ff9e1003d254bf61608f39143444 Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Thu, 15 Aug 2013 01:59:53 +0700 Subject: [PATCH 14/18] New Identity implementation based on attributes and reflection --- StudentManager/Identity.cs | 66 +++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/StudentManager/Identity.cs b/StudentManager/Identity.cs index 92671c8..e293530 100644 --- a/StudentManager/Identity.cs +++ b/StudentManager/Identity.cs @@ -20,30 +20,64 @@ // along with this program. If not, see . // using System; +using System.Linq; +using System.Reflection; namespace StudentManager { - public abstract class Identity: IComparable + public abstract class Identity : IEquatable { - public int ID { get; set; } - - - public int CompareTo(Identity other) + [AttributeUsage(System.AttributeTargets.Property)] + public class IDAttribute : System.Attribute { - return this.ID - other.ID; } - - public override bool Equals(Object other) + + MethodInfo IdGetMethod; + + public Identity() + { + var idProperty = (from prop in this.GetType().GetProperties() + from attr in prop.GetCustomAttributes(false) + where attr is IDAttribute + select prop).SingleOrDefault(); + + // Not null, readable and not an indexer + if (idProperty != null && + idProperty.CanRead && + idProperty.GetIndexParameters().Length == 0) + { + IdGetMethod = idProperty.GetGetMethod(); + } + } + + #region IEquatable[Identity] implementation + public bool Equals(Identity other) + { + if (this.IdGetMethod != null) + { + object otherId = other.IdGetMethod.Invoke(other, null); + object thisId = this.IdGetMethod.Invoke(this, null); + return thisId.Equals(otherId); + } else + { + return base.Equals(other); + } + } + + public override bool Equals(object obj) + { + var other = obj as Identity; + return other != null && this.Equals(other); + } + + public override int GetHashCode() { - if (other == null) - return false; - - Identity _other = other as Identity; - if (_other == null) - return false; - - return this.ID == _other.ID; + if (this.IdGetMethod != null) + return this.IdGetMethod.Invoke(this, null).GetHashCode(); + else + return base.GetHashCode(); } + #endregion } } From a118a814ae58c0a8ef24f8512de57d928bf8e6e2 Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Thu, 15 Aug 2013 02:01:01 +0700 Subject: [PATCH 15/18] Use the new Identity implementation --- StudentManager/Class.cs | 6 ++++-- StudentManager/Manager.cs | 8 ++++---- StudentManager/Student.cs | 2 ++ StudentManager/Tests/TestIdentity.cs | 5 ++--- StudentManager/Tests/TestManager.cs | 8 ++++---- StudentManager/Tests/TestPersistence.cs | 4 ++-- 6 files changed, 18 insertions(+), 15 deletions(-) diff --git a/StudentManager/Class.cs b/StudentManager/Class.cs index 20fb46c..f688913 100755 --- a/StudentManager/Class.cs +++ b/StudentManager/Class.cs @@ -3,8 +3,9 @@ namespace StudentManager { - public struct Room + public class Room : Identity { + [Identity.ID] public String Name { get; set; } } @@ -15,8 +16,9 @@ public struct TimeSlot public DateTime EndTime { get; set; } } - public class Class + public class Class : Identity { + [Identity.ID] public string Name { get; set; } public string Teacher { get; set; } diff --git a/StudentManager/Manager.cs b/StudentManager/Manager.cs index 3060c05..42af193 100644 --- a/StudentManager/Manager.cs +++ b/StudentManager/Manager.cs @@ -10,7 +10,7 @@ class Manager // users. public HashSet Classes { get; private set; } - public SortedSet Students { get; private set; } + public HashSet Students { get; private set; } public HashSet Rooms { get; private set; } @@ -36,7 +36,7 @@ public IEnumerable> Allocation public Manager() { Classes = new HashSet(); - Students = new SortedSet(); + Students = new HashSet(); Rooms = new HashSet(); TimeSlots = new HashSet(); classStudents = new HashSet>(); @@ -56,10 +56,10 @@ public Manager() public Manager(IPersistenceService database, Dictionary UriMapping) { Classes = new HashSet(database.load>(UriMapping["classes"])); - Students = new SortedSet(database.load>(UriMapping["students"])); + Students = new HashSet(database.load>(UriMapping["students"])); } - public Student GetStudentById(int id) + public Student GetStudentById(String id) { return (from student in this.Students where student.ID == id diff --git a/StudentManager/Student.cs b/StudentManager/Student.cs index 306119e..888ca8f 100644 --- a/StudentManager/Student.cs +++ b/StudentManager/Student.cs @@ -5,6 +5,8 @@ namespace StudentManager { public class Student: Identity { + [Identity.ID] + public string ID { get; set; } public string Name { get; set; } public string Address { get; set; } diff --git a/StudentManager/Tests/TestIdentity.cs b/StudentManager/Tests/TestIdentity.cs index e6373e4..02dc09c 100755 --- a/StudentManager/Tests/TestIdentity.cs +++ b/StudentManager/Tests/TestIdentity.cs @@ -14,15 +14,14 @@ public void TestStudent() { var a = new Student() { - ID = 10 + ID = "aoe" }; var b = new Student() { - ID = 5 + ID = "aoed" }; - Assert.That(a.CompareTo(b) > 0); Assert.False(a.Equals(b)); } diff --git a/StudentManager/Tests/TestManager.cs b/StudentManager/Tests/TestManager.cs index 470c5c8..11b6d81 100755 --- a/StudentManager/Tests/TestManager.cs +++ b/StudentManager/Tests/TestManager.cs @@ -12,7 +12,7 @@ class TestStudentManagement private Manager m; private Student trung = new Student() { - ID = 10, + ID = "B01414", Name = "Trung" }; private Class c1203l = new Class() @@ -28,11 +28,11 @@ public void Init() { [Test] public void TestGetStudentByID() { - Assert.Null(m.GetStudentById(10)); + Assert.Null(m.GetStudentById("B01415")); m.Students.Add(trung); - Assert.AreSame(trung, m.GetStudentById(10)); - Assert.Null(m.GetStudentById(80)); + Assert.AreSame(trung, m.GetStudentById("B01414")); + Assert.Null(m.GetStudentById("")); } [Test] diff --git a/StudentManager/Tests/TestPersistence.cs b/StudentManager/Tests/TestPersistence.cs index b958c1b..12e85ac 100644 --- a/StudentManager/Tests/TestPersistence.cs +++ b/StudentManager/Tests/TestPersistence.cs @@ -34,7 +34,7 @@ public void SaveSingleObject() { var s = new Student() { - ID = 10, + ID = "B01414", Name = "Trung", Address = "Home" }; @@ -66,7 +66,7 @@ public void SaveSortedSet() public void LoadIdentity() { var s = new Student() { - ID = 10, + ID = "B01414", Name = "Trung", Address = "Home" }; From 1b784271bcf26bcf70b77cd054f3192c7081d326 Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Thu, 15 Aug 2013 02:02:17 +0700 Subject: [PATCH 16/18] Fix some test cases --- StudentManager/Tests/TestIdentity.cs | 31 ++++++++++++------------- StudentManager/Tests/TestPersistence.cs | 2 +- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/StudentManager/Tests/TestIdentity.cs b/StudentManager/Tests/TestIdentity.cs index 02dc09c..010e28c 100755 --- a/StudentManager/Tests/TestIdentity.cs +++ b/StudentManager/Tests/TestIdentity.cs @@ -25,21 +25,20 @@ public void TestStudent() Assert.False(a.Equals(b)); } -// [Test] -// public void TestClass() -// { -// var a = new Class() -// { -// ID = 10 -// }; -// -// var b = new Class() -// { -// ID = 5 -// }; -// -// Assert.That(a.CompareTo(b) > 0); -// Assert.False(a.Equals(b)); -// } + [Test] + public void TestClass() + { + var a = new Class() + { + Name = "C1203L" + }; + + var b = new Class() + { + Name = "C1203F" + }; + + Assert.False(a.Equals(b)); + } } } diff --git a/StudentManager/Tests/TestPersistence.cs b/StudentManager/Tests/TestPersistence.cs index 12e85ac..1c4efea 100644 --- a/StudentManager/Tests/TestPersistence.cs +++ b/StudentManager/Tests/TestPersistence.cs @@ -43,7 +43,7 @@ public void SaveSingleObject() Assert.AreEqual( @" - 10 + B01414 Trung
Home
", From 81832fd781df608d2c2b589c80e99380980e9a7c Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Thu, 15 Aug 2013 02:06:06 +0700 Subject: [PATCH 17/18] Doc for the new Identity class --- StudentManager/Identity.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/StudentManager/Identity.cs b/StudentManager/Identity.cs index e293530..7200859 100644 --- a/StudentManager/Identity.cs +++ b/StudentManager/Identity.cs @@ -25,6 +25,17 @@ namespace StudentManager { + /// + /// Base class for identities. + /// + /// + /// The single purpose for this class' existence is to provide + /// simple and uniform ID and equality check. Inheriting classes + /// are expected to have a single public property decorated with + /// the [ID] attribute, which will be used in equality comparisions. + /// If there are multiple properties with ID attribute, only the + /// first one will be used. + /// public abstract class Identity : IEquatable { [AttributeUsage(System.AttributeTargets.Property)] From 388a45f05028d47e49a7eb7a98020f0b420d413b Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Thu, 15 Aug 2013 02:06:54 +0700 Subject: [PATCH 18/18] Update Main --- StudentManager/Main.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/StudentManager/Main.cs b/StudentManager/Main.cs index 7951757..6f1782a 100755 --- a/StudentManager/Main.cs +++ b/StudentManager/Main.cs @@ -9,7 +9,8 @@ class MainClass { public static void Main(string[] args) { - new MainScreen().Start(); + Manager m = new Manager(); + new MainScreen(m).Start(); } } }