mirror of
https://github.com/sabazadam/Se302.git
synced 2025-12-31 12:21:22 +00:00
- Implement CSV import with validation (students, courses, classrooms, enrollments)
- Create MVC architecture with DataManager singleton - Add search/filter functionality for all views
This commit is contained in:
59
sampleData/sampleData_AllAttendanceLists.csv
Normal file
59
sampleData/sampleData_AllAttendanceLists.csv
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
CourseCode_01
|
||||||
|
['Std_ID_170', 'Std_ID_077', 'Std_ID_097', 'Std_ID_202', 'Std_ID_080', 'Std_ID_126', 'Std_ID_112', 'Std_ID_175', 'Std_ID_180', 'Std_ID_139', 'Std_ID_181', 'Std_ID_222', 'Std_ID_243', 'Std_ID_167', 'Std_ID_136', 'Std_ID_021', 'Std_ID_041', 'Std_ID_231', 'Std_ID_062', 'Std_ID_138', 'Std_ID_236', 'Std_ID_221', 'Std_ID_006', 'Std_ID_135', 'Std_ID_209', 'Std_ID_239', 'Std_ID_043', 'Std_ID_182', 'Std_ID_246', 'Std_ID_083', 'Std_ID_056', 'Std_ID_047', 'Std_ID_193', 'Std_ID_107', 'Std_ID_216', 'Std_ID_005', 'Std_ID_096', 'Std_ID_140', 'Std_ID_233', 'Std_ID_168']
|
||||||
|
|
||||||
|
CourseCode_02
|
||||||
|
['Std_ID_238', 'Std_ID_132', 'Std_ID_079', 'Std_ID_139', 'Std_ID_116', 'Std_ID_093', 'Std_ID_190', 'Std_ID_121', 'Std_ID_108', 'Std_ID_005', 'Std_ID_210', 'Std_ID_018', 'Std_ID_152', 'Std_ID_033', 'Std_ID_199', 'Std_ID_073', 'Std_ID_193', 'Std_ID_220', 'Std_ID_222', 'Std_ID_188', 'Std_ID_217', 'Std_ID_008', 'Std_ID_123', 'Std_ID_159', 'Std_ID_227', 'Std_ID_136', 'Std_ID_187', 'Std_ID_216', 'Std_ID_056', 'Std_ID_026', 'Std_ID_099', 'Std_ID_146', 'Std_ID_055', 'Std_ID_057', 'Std_ID_035', 'Std_ID_049', 'Std_ID_144', 'Std_ID_232', 'Std_ID_098', 'Std_ID_058']
|
||||||
|
|
||||||
|
CourseCode_03
|
||||||
|
['Std_ID_098', 'Std_ID_070', 'Std_ID_049', 'Std_ID_191', 'Std_ID_109', 'Std_ID_196', 'Std_ID_209', 'Std_ID_189', 'Std_ID_039', 'Std_ID_219', 'Std_ID_009', 'Std_ID_033', 'Std_ID_059', 'Std_ID_174', 'Std_ID_169', 'Std_ID_122', 'Std_ID_057', 'Std_ID_249', 'Std_ID_142', 'Std_ID_229', 'Std_ID_038', 'Std_ID_132', 'Std_ID_140', 'Std_ID_081', 'Std_ID_243', 'Std_ID_150', 'Std_ID_099', 'Std_ID_224', 'Std_ID_097', 'Std_ID_193', 'Std_ID_043', 'Std_ID_055', 'Std_ID_061', 'Std_ID_212', 'Std_ID_205', 'Std_ID_146', 'Std_ID_100', 'Std_ID_149', 'Std_ID_116', 'Std_ID_233']
|
||||||
|
|
||||||
|
CourseCode_04
|
||||||
|
['Std_ID_142', 'Std_ID_085', 'Std_ID_103', 'Std_ID_059', 'Std_ID_243', 'Std_ID_106', 'Std_ID_069', 'Std_ID_014', 'Std_ID_015', 'Std_ID_088', 'Std_ID_136', 'Std_ID_020', 'Std_ID_097', 'Std_ID_190', 'Std_ID_194', 'Std_ID_201', 'Std_ID_125', 'Std_ID_182', 'Std_ID_138', 'Std_ID_105', 'Std_ID_076', 'Std_ID_007', 'Std_ID_066', 'Std_ID_189', 'Std_ID_129', 'Std_ID_133', 'Std_ID_034', 'Std_ID_130', 'Std_ID_247', 'Std_ID_024', 'Std_ID_027', 'Std_ID_115', 'Std_ID_064', 'Std_ID_132', 'Std_ID_113', 'Std_ID_118', 'Std_ID_162', 'Std_ID_154', 'Std_ID_181', 'Std_ID_114']
|
||||||
|
|
||||||
|
CourseCode_05
|
||||||
|
['Std_ID_203', 'Std_ID_236', 'Std_ID_192', 'Std_ID_198', 'Std_ID_213', 'Std_ID_147', 'Std_ID_051', 'Std_ID_095', 'Std_ID_226', 'Std_ID_077', 'Std_ID_230', 'Std_ID_035', 'Std_ID_142', 'Std_ID_195', 'Std_ID_182', 'Std_ID_064', 'Std_ID_229', 'Std_ID_239', 'Std_ID_119', 'Std_ID_231', 'Std_ID_217', 'Std_ID_054', 'Std_ID_163', 'Std_ID_148', 'Std_ID_249', 'Std_ID_068', 'Std_ID_202', 'Std_ID_225', 'Std_ID_101', 'Std_ID_126', 'Std_ID_150', 'Std_ID_197', 'Std_ID_025', 'Std_ID_140', 'Std_ID_124', 'Std_ID_053', 'Std_ID_075', 'Std_ID_074', 'Std_ID_243', 'Std_ID_169']
|
||||||
|
|
||||||
|
CourseCode_06
|
||||||
|
['Std_ID_129', 'Std_ID_175', 'Std_ID_049', 'Std_ID_238', 'Std_ID_056', 'Std_ID_187', 'Std_ID_064', 'Std_ID_151', 'Std_ID_201', 'Std_ID_022', 'Std_ID_169', 'Std_ID_220', 'Std_ID_147', 'Std_ID_223', 'Std_ID_011', 'Std_ID_053', 'Std_ID_166', 'Std_ID_111', 'Std_ID_219', 'Std_ID_112', 'Std_ID_203', 'Std_ID_054', 'Std_ID_106', 'Std_ID_025', 'Std_ID_073', 'Std_ID_234', 'Std_ID_027', 'Std_ID_215', 'Std_ID_028', 'Std_ID_208', 'Std_ID_192', 'Std_ID_172', 'Std_ID_015', 'Std_ID_164', 'Std_ID_110', 'Std_ID_010', 'Std_ID_078', 'Std_ID_006', 'Std_ID_204', 'Std_ID_029']
|
||||||
|
|
||||||
|
CourseCode_07
|
||||||
|
['Std_ID_040', 'Std_ID_102', 'Std_ID_186', 'Std_ID_206', 'Std_ID_113', 'Std_ID_135', 'Std_ID_145', 'Std_ID_165', 'Std_ID_028', 'Std_ID_235', 'Std_ID_144', 'Std_ID_085', 'Std_ID_026', 'Std_ID_203', 'Std_ID_231', 'Std_ID_124', 'Std_ID_190', 'Std_ID_089', 'Std_ID_074', 'Std_ID_222', 'Std_ID_179', 'Std_ID_127', 'Std_ID_041', 'Std_ID_133', 'Std_ID_181', 'Std_ID_095', 'Std_ID_034', 'Std_ID_219', 'Std_ID_148', 'Std_ID_037', 'Std_ID_061', 'Std_ID_188', 'Std_ID_171', 'Std_ID_238', 'Std_ID_242', 'Std_ID_029', 'Std_ID_182', 'Std_ID_072', 'Std_ID_161', 'Std_ID_093']
|
||||||
|
|
||||||
|
CourseCode_08
|
||||||
|
['Std_ID_009', 'Std_ID_108', 'Std_ID_116', 'Std_ID_111', 'Std_ID_058', 'Std_ID_086', 'Std_ID_128', 'Std_ID_106', 'Std_ID_187', 'Std_ID_115', 'Std_ID_101', 'Std_ID_096', 'Std_ID_063', 'Std_ID_192', 'Std_ID_091', 'Std_ID_195', 'Std_ID_236', 'Std_ID_039', 'Std_ID_042', 'Std_ID_052', 'Std_ID_032', 'Std_ID_137', 'Std_ID_181', 'Std_ID_071', 'Std_ID_127', 'Std_ID_130', 'Std_ID_089', 'Std_ID_165', 'Std_ID_175', 'Std_ID_207', 'Std_ID_121', 'Std_ID_233', 'Std_ID_033', 'Std_ID_080', 'Std_ID_240', 'Std_ID_152', 'Std_ID_209', 'Std_ID_050', 'Std_ID_017', 'Std_ID_075']
|
||||||
|
|
||||||
|
CourseCode_09
|
||||||
|
['Std_ID_043', 'Std_ID_203', 'Std_ID_040', 'Std_ID_163', 'Std_ID_142', 'Std_ID_137', 'Std_ID_220', 'Std_ID_126', 'Std_ID_032', 'Std_ID_157', 'Std_ID_159', 'Std_ID_219', 'Std_ID_175', 'Std_ID_015', 'Std_ID_177', 'Std_ID_217', 'Std_ID_008', 'Std_ID_070', 'Std_ID_048', 'Std_ID_033', 'Std_ID_188', 'Std_ID_078', 'Std_ID_097', 'Std_ID_121', 'Std_ID_183', 'Std_ID_016', 'Std_ID_181', 'Std_ID_080', 'Std_ID_119', 'Std_ID_206', 'Std_ID_093', 'Std_ID_195', 'Std_ID_002', 'Std_ID_098', 'Std_ID_200', 'Std_ID_090', 'Std_ID_167', 'Std_ID_088', 'Std_ID_041', 'Std_ID_164']
|
||||||
|
|
||||||
|
CourseCode_10
|
||||||
|
['Std_ID_229', 'Std_ID_167', 'Std_ID_228', 'Std_ID_193', 'Std_ID_025', 'Std_ID_205', 'Std_ID_163', 'Std_ID_225', 'Std_ID_194', 'Std_ID_240', 'Std_ID_247', 'Std_ID_233', 'Std_ID_181', 'Std_ID_121', 'Std_ID_152', 'Std_ID_131', 'Std_ID_026', 'Std_ID_217', 'Std_ID_124', 'Std_ID_010', 'Std_ID_054', 'Std_ID_129', 'Std_ID_003', 'Std_ID_211', 'Std_ID_090', 'Std_ID_092', 'Std_ID_024', 'Std_ID_144', 'Std_ID_201', 'Std_ID_049', 'Std_ID_171', 'Std_ID_082', 'Std_ID_136', 'Std_ID_042', 'Std_ID_224', 'Std_ID_027', 'Std_ID_021', 'Std_ID_160', 'Std_ID_235', 'Std_ID_072']
|
||||||
|
|
||||||
|
CourseCode_11
|
||||||
|
['Std_ID_208', 'Std_ID_237', 'Std_ID_061', 'Std_ID_133', 'Std_ID_119', 'Std_ID_132', 'Std_ID_168', 'Std_ID_238', 'Std_ID_170', 'Std_ID_190', 'Std_ID_066', 'Std_ID_093', 'Std_ID_243', 'Std_ID_148', 'Std_ID_205', 'Std_ID_033', 'Std_ID_078', 'Std_ID_191', 'Std_ID_111', 'Std_ID_090', 'Std_ID_079', 'Std_ID_083', 'Std_ID_086', 'Std_ID_020', 'Std_ID_029', 'Std_ID_022', 'Std_ID_131', 'Std_ID_071', 'Std_ID_055', 'Std_ID_141', 'Std_ID_049', 'Std_ID_115', 'Std_ID_202', 'Std_ID_122', 'Std_ID_075', 'Std_ID_222', 'Std_ID_149', 'Std_ID_021', 'Std_ID_018', 'Std_ID_124']
|
||||||
|
|
||||||
|
CourseCode_12
|
||||||
|
['Std_ID_066', 'Std_ID_052', 'Std_ID_091', 'Std_ID_008', 'Std_ID_148', 'Std_ID_003', 'Std_ID_040', 'Std_ID_187', 'Std_ID_170', 'Std_ID_147', 'Std_ID_111', 'Std_ID_027', 'Std_ID_142', 'Std_ID_188', 'Std_ID_202', 'Std_ID_176', 'Std_ID_079', 'Std_ID_145', 'Std_ID_058', 'Std_ID_089', 'Std_ID_190', 'Std_ID_044', 'Std_ID_062', 'Std_ID_112', 'Std_ID_099', 'Std_ID_220', 'Std_ID_203', 'Std_ID_222', 'Std_ID_117', 'Std_ID_061', 'Std_ID_118', 'Std_ID_217', 'Std_ID_109', 'Std_ID_223', 'Std_ID_002', 'Std_ID_019', 'Std_ID_121', 'Std_ID_100', 'Std_ID_152', 'Std_ID_213']
|
||||||
|
|
||||||
|
CourseCode_13
|
||||||
|
['Std_ID_175', 'Std_ID_205', 'Std_ID_019', 'Std_ID_142', 'Std_ID_243', 'Std_ID_246', 'Std_ID_186', 'Std_ID_228', 'Std_ID_137', 'Std_ID_080', 'Std_ID_130', 'Std_ID_105', 'Std_ID_216', 'Std_ID_201', 'Std_ID_135', 'Std_ID_218', 'Std_ID_096', 'Std_ID_109', 'Std_ID_026', 'Std_ID_229', 'Std_ID_207', 'Std_ID_014', 'Std_ID_179', 'Std_ID_192', 'Std_ID_158', 'Std_ID_102', 'Std_ID_011', 'Std_ID_094', 'Std_ID_057', 'Std_ID_010', 'Std_ID_062', 'Std_ID_090', 'Std_ID_125', 'Std_ID_219', 'Std_ID_153', 'Std_ID_122', 'Std_ID_248', 'Std_ID_181', 'Std_ID_058', 'Std_ID_037']
|
||||||
|
|
||||||
|
CourseCode_14
|
||||||
|
['Std_ID_018', 'Std_ID_052', 'Std_ID_227', 'Std_ID_003', 'Std_ID_208', 'Std_ID_012', 'Std_ID_162', 'Std_ID_042', 'Std_ID_141', 'Std_ID_063', 'Std_ID_019', 'Std_ID_096', 'Std_ID_192', 'Std_ID_124', 'Std_ID_245', 'Std_ID_200', 'Std_ID_219', 'Std_ID_092', 'Std_ID_222', 'Std_ID_020', 'Std_ID_077', 'Std_ID_109', 'Std_ID_174', 'Std_ID_087', 'Std_ID_028', 'Std_ID_083', 'Std_ID_122', 'Std_ID_201', 'Std_ID_117', 'Std_ID_054', 'Std_ID_080', 'Std_ID_010', 'Std_ID_221', 'Std_ID_131', 'Std_ID_024', 'Std_ID_234', 'Std_ID_036', 'Std_ID_177', 'Std_ID_161', 'Std_ID_126']
|
||||||
|
|
||||||
|
CourseCode_15
|
||||||
|
['Std_ID_142', 'Std_ID_050', 'Std_ID_115', 'Std_ID_076', 'Std_ID_011', 'Std_ID_035', 'Std_ID_191', 'Std_ID_059', 'Std_ID_032', 'Std_ID_030', 'Std_ID_012', 'Std_ID_015', 'Std_ID_150', 'Std_ID_121', 'Std_ID_124', 'Std_ID_061', 'Std_ID_075', 'Std_ID_133', 'Std_ID_166', 'Std_ID_069', 'Std_ID_094', 'Std_ID_158', 'Std_ID_144', 'Std_ID_199', 'Std_ID_096', 'Std_ID_177', 'Std_ID_014', 'Std_ID_022', 'Std_ID_004', 'Std_ID_233', 'Std_ID_172', 'Std_ID_180', 'Std_ID_223', 'Std_ID_073', 'Std_ID_018', 'Std_ID_057', 'Std_ID_224', 'Std_ID_099', 'Std_ID_062', 'Std_ID_232']
|
||||||
|
|
||||||
|
CourseCode_16
|
||||||
|
['Std_ID_020', 'Std_ID_124', 'Std_ID_097', 'Std_ID_092', 'Std_ID_100', 'Std_ID_119', 'Std_ID_177', 'Std_ID_011', 'Std_ID_017', 'Std_ID_114', 'Std_ID_087', 'Std_ID_007', 'Std_ID_132', 'Std_ID_208', 'Std_ID_082', 'Std_ID_002', 'Std_ID_116', 'Std_ID_057', 'Std_ID_210', 'Std_ID_045', 'Std_ID_005', 'Std_ID_139', 'Std_ID_028', 'Std_ID_051', 'Std_ID_144', 'Std_ID_207', 'Std_ID_056', 'Std_ID_042', 'Std_ID_211', 'Std_ID_231', 'Std_ID_203', 'Std_ID_196', 'Std_ID_009', 'Std_ID_106', 'Std_ID_133', 'Std_ID_151', 'Std_ID_058', 'Std_ID_101', 'Std_ID_125', 'Std_ID_232']
|
||||||
|
|
||||||
|
CourseCode_17
|
||||||
|
['Std_ID_122', 'Std_ID_224', 'Std_ID_056', 'Std_ID_221', 'Std_ID_054', 'Std_ID_237', 'Std_ID_180', 'Std_ID_052', 'Std_ID_020', 'Std_ID_131', 'Std_ID_106', 'Std_ID_231', 'Std_ID_011', 'Std_ID_064', 'Std_ID_069', 'Std_ID_062', 'Std_ID_239', 'Std_ID_019', 'Std_ID_227', 'Std_ID_053', 'Std_ID_119', 'Std_ID_160', 'Std_ID_184', 'Std_ID_240', 'Std_ID_250', 'Std_ID_030', 'Std_ID_177', 'Std_ID_241', 'Std_ID_038', 'Std_ID_129', 'Std_ID_098', 'Std_ID_104', 'Std_ID_158', 'Std_ID_026', 'Std_ID_202', 'Std_ID_015', 'Std_ID_058', 'Std_ID_109', 'Std_ID_152', 'Std_ID_190']
|
||||||
|
|
||||||
|
CourseCode_18
|
||||||
|
['Std_ID_117', 'Std_ID_136', 'Std_ID_149', 'Std_ID_126', 'Std_ID_006', 'Std_ID_063', 'Std_ID_151', 'Std_ID_060', 'Std_ID_012', 'Std_ID_090', 'Std_ID_154', 'Std_ID_240', 'Std_ID_065', 'Std_ID_162', 'Std_ID_102', 'Std_ID_043', 'Std_ID_144', 'Std_ID_121', 'Std_ID_156', 'Std_ID_066', 'Std_ID_083', 'Std_ID_199', 'Std_ID_143', 'Std_ID_047', 'Std_ID_207', 'Std_ID_189', 'Std_ID_177', 'Std_ID_250', 'Std_ID_210', 'Std_ID_197', 'Std_ID_003', 'Std_ID_246', 'Std_ID_077', 'Std_ID_215', 'Std_ID_086', 'Std_ID_204', 'Std_ID_223', 'Std_ID_067', 'Std_ID_115', 'Std_ID_082']
|
||||||
|
|
||||||
|
CourseCode_19
|
||||||
|
['Std_ID_250', 'Std_ID_067', 'Std_ID_022', 'Std_ID_114', 'Std_ID_060', 'Std_ID_133', 'Std_ID_236', 'Std_ID_039', 'Std_ID_005', 'Std_ID_032', 'Std_ID_071', 'Std_ID_132', 'Std_ID_087', 'Std_ID_229', 'Std_ID_047', 'Std_ID_029', 'Std_ID_235', 'Std_ID_216', 'Std_ID_199', 'Std_ID_204', 'Std_ID_163', 'Std_ID_168', 'Std_ID_147', 'Std_ID_014', 'Std_ID_187', 'Std_ID_179', 'Std_ID_160', 'Std_ID_035', 'Std_ID_167', 'Std_ID_173', 'Std_ID_248', 'Std_ID_026', 'Std_ID_211', 'Std_ID_003', 'Std_ID_112', 'Std_ID_105', 'Std_ID_191', 'Std_ID_095', 'Std_ID_011', 'Std_ID_092']
|
||||||
|
|
||||||
|
CourseCode_20
|
||||||
|
['Std_ID_222', 'Std_ID_125', 'Std_ID_188', 'Std_ID_088', 'Std_ID_095', 'Std_ID_046', 'Std_ID_201', 'Std_ID_051', 'Std_ID_104', 'Std_ID_130', 'Std_ID_092', 'Std_ID_057', 'Std_ID_217', 'Std_ID_181', 'Std_ID_227', 'Std_ID_136', 'Std_ID_064', 'Std_ID_133', 'Std_ID_059', 'Std_ID_065', 'Std_ID_169', 'Std_ID_233', 'Std_ID_129', 'Std_ID_123', 'Std_ID_193', 'Std_ID_079', 'Std_ID_172', 'Std_ID_204', 'Std_ID_208', 'Std_ID_246', 'Std_ID_001', 'Std_ID_174', 'Std_ID_007', 'Std_ID_189', 'Std_ID_203', 'Std_ID_205', 'Std_ID_183', 'Std_ID_048', 'Std_ID_121', 'Std_ID_177']
|
||||||
|
11
sampleData/sampleData_AllClassroomsAndTheirCapacities.csv
Normal file
11
sampleData/sampleData_AllClassroomsAndTheirCapacities.csv
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
ALL OF THE CLASSROOMS; AND THEIR CAPACITIES IN THE SYSTEM
|
||||||
|
Classroom_01;40
|
||||||
|
Classroom_02;40
|
||||||
|
Classroom_03;40
|
||||||
|
Classroom_04;40
|
||||||
|
Classroom_05;40
|
||||||
|
Classroom_06;40
|
||||||
|
Classroom_07;40
|
||||||
|
Classroom_08;40
|
||||||
|
Classroom_09;40
|
||||||
|
Classroom_10;40
|
||||||
|
21
sampleData/sampleData_AllCourses.csv
Normal file
21
sampleData/sampleData_AllCourses.csv
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
ALL OF THE COURSES IN THE SYSTEM
|
||||||
|
CourseCode_01
|
||||||
|
CourseCode_02
|
||||||
|
CourseCode_03
|
||||||
|
CourseCode_04
|
||||||
|
CourseCode_05
|
||||||
|
CourseCode_06
|
||||||
|
CourseCode_07
|
||||||
|
CourseCode_08
|
||||||
|
CourseCode_09
|
||||||
|
CourseCode_10
|
||||||
|
CourseCode_11
|
||||||
|
CourseCode_12
|
||||||
|
CourseCode_13
|
||||||
|
CourseCode_14
|
||||||
|
CourseCode_15
|
||||||
|
CourseCode_16
|
||||||
|
CourseCode_17
|
||||||
|
CourseCode_18
|
||||||
|
CourseCode_19
|
||||||
|
CourseCode_20
|
||||||
|
251
sampleData/sampleData_AllStudents.csv
Normal file
251
sampleData/sampleData_AllStudents.csv
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
ALL OF THE STUDENTS IN THE SYSTEM
|
||||||
|
Std_ID_001
|
||||||
|
Std_ID_002
|
||||||
|
Std_ID_003
|
||||||
|
Std_ID_004
|
||||||
|
Std_ID_005
|
||||||
|
Std_ID_006
|
||||||
|
Std_ID_007
|
||||||
|
Std_ID_008
|
||||||
|
Std_ID_009
|
||||||
|
Std_ID_010
|
||||||
|
Std_ID_011
|
||||||
|
Std_ID_012
|
||||||
|
Std_ID_013
|
||||||
|
Std_ID_014
|
||||||
|
Std_ID_015
|
||||||
|
Std_ID_016
|
||||||
|
Std_ID_017
|
||||||
|
Std_ID_018
|
||||||
|
Std_ID_019
|
||||||
|
Std_ID_020
|
||||||
|
Std_ID_021
|
||||||
|
Std_ID_022
|
||||||
|
Std_ID_023
|
||||||
|
Std_ID_024
|
||||||
|
Std_ID_025
|
||||||
|
Std_ID_026
|
||||||
|
Std_ID_027
|
||||||
|
Std_ID_028
|
||||||
|
Std_ID_029
|
||||||
|
Std_ID_030
|
||||||
|
Std_ID_031
|
||||||
|
Std_ID_032
|
||||||
|
Std_ID_033
|
||||||
|
Std_ID_034
|
||||||
|
Std_ID_035
|
||||||
|
Std_ID_036
|
||||||
|
Std_ID_037
|
||||||
|
Std_ID_038
|
||||||
|
Std_ID_039
|
||||||
|
Std_ID_040
|
||||||
|
Std_ID_041
|
||||||
|
Std_ID_042
|
||||||
|
Std_ID_043
|
||||||
|
Std_ID_044
|
||||||
|
Std_ID_045
|
||||||
|
Std_ID_046
|
||||||
|
Std_ID_047
|
||||||
|
Std_ID_048
|
||||||
|
Std_ID_049
|
||||||
|
Std_ID_050
|
||||||
|
Std_ID_051
|
||||||
|
Std_ID_052
|
||||||
|
Std_ID_053
|
||||||
|
Std_ID_054
|
||||||
|
Std_ID_055
|
||||||
|
Std_ID_056
|
||||||
|
Std_ID_057
|
||||||
|
Std_ID_058
|
||||||
|
Std_ID_059
|
||||||
|
Std_ID_060
|
||||||
|
Std_ID_061
|
||||||
|
Std_ID_062
|
||||||
|
Std_ID_063
|
||||||
|
Std_ID_064
|
||||||
|
Std_ID_065
|
||||||
|
Std_ID_066
|
||||||
|
Std_ID_067
|
||||||
|
Std_ID_068
|
||||||
|
Std_ID_069
|
||||||
|
Std_ID_070
|
||||||
|
Std_ID_071
|
||||||
|
Std_ID_072
|
||||||
|
Std_ID_073
|
||||||
|
Std_ID_074
|
||||||
|
Std_ID_075
|
||||||
|
Std_ID_076
|
||||||
|
Std_ID_077
|
||||||
|
Std_ID_078
|
||||||
|
Std_ID_079
|
||||||
|
Std_ID_080
|
||||||
|
Std_ID_081
|
||||||
|
Std_ID_082
|
||||||
|
Std_ID_083
|
||||||
|
Std_ID_084
|
||||||
|
Std_ID_085
|
||||||
|
Std_ID_086
|
||||||
|
Std_ID_087
|
||||||
|
Std_ID_088
|
||||||
|
Std_ID_089
|
||||||
|
Std_ID_090
|
||||||
|
Std_ID_091
|
||||||
|
Std_ID_092
|
||||||
|
Std_ID_093
|
||||||
|
Std_ID_094
|
||||||
|
Std_ID_095
|
||||||
|
Std_ID_096
|
||||||
|
Std_ID_097
|
||||||
|
Std_ID_098
|
||||||
|
Std_ID_099
|
||||||
|
Std_ID_100
|
||||||
|
Std_ID_101
|
||||||
|
Std_ID_102
|
||||||
|
Std_ID_103
|
||||||
|
Std_ID_104
|
||||||
|
Std_ID_105
|
||||||
|
Std_ID_106
|
||||||
|
Std_ID_107
|
||||||
|
Std_ID_108
|
||||||
|
Std_ID_109
|
||||||
|
Std_ID_110
|
||||||
|
Std_ID_111
|
||||||
|
Std_ID_112
|
||||||
|
Std_ID_113
|
||||||
|
Std_ID_114
|
||||||
|
Std_ID_115
|
||||||
|
Std_ID_116
|
||||||
|
Std_ID_117
|
||||||
|
Std_ID_118
|
||||||
|
Std_ID_119
|
||||||
|
Std_ID_120
|
||||||
|
Std_ID_121
|
||||||
|
Std_ID_122
|
||||||
|
Std_ID_123
|
||||||
|
Std_ID_124
|
||||||
|
Std_ID_125
|
||||||
|
Std_ID_126
|
||||||
|
Std_ID_127
|
||||||
|
Std_ID_128
|
||||||
|
Std_ID_129
|
||||||
|
Std_ID_130
|
||||||
|
Std_ID_131
|
||||||
|
Std_ID_132
|
||||||
|
Std_ID_133
|
||||||
|
Std_ID_134
|
||||||
|
Std_ID_135
|
||||||
|
Std_ID_136
|
||||||
|
Std_ID_137
|
||||||
|
Std_ID_138
|
||||||
|
Std_ID_139
|
||||||
|
Std_ID_140
|
||||||
|
Std_ID_141
|
||||||
|
Std_ID_142
|
||||||
|
Std_ID_143
|
||||||
|
Std_ID_144
|
||||||
|
Std_ID_145
|
||||||
|
Std_ID_146
|
||||||
|
Std_ID_147
|
||||||
|
Std_ID_148
|
||||||
|
Std_ID_149
|
||||||
|
Std_ID_150
|
||||||
|
Std_ID_151
|
||||||
|
Std_ID_152
|
||||||
|
Std_ID_153
|
||||||
|
Std_ID_154
|
||||||
|
Std_ID_155
|
||||||
|
Std_ID_156
|
||||||
|
Std_ID_157
|
||||||
|
Std_ID_158
|
||||||
|
Std_ID_159
|
||||||
|
Std_ID_160
|
||||||
|
Std_ID_161
|
||||||
|
Std_ID_162
|
||||||
|
Std_ID_163
|
||||||
|
Std_ID_164
|
||||||
|
Std_ID_165
|
||||||
|
Std_ID_166
|
||||||
|
Std_ID_167
|
||||||
|
Std_ID_168
|
||||||
|
Std_ID_169
|
||||||
|
Std_ID_170
|
||||||
|
Std_ID_171
|
||||||
|
Std_ID_172
|
||||||
|
Std_ID_173
|
||||||
|
Std_ID_174
|
||||||
|
Std_ID_175
|
||||||
|
Std_ID_176
|
||||||
|
Std_ID_177
|
||||||
|
Std_ID_178
|
||||||
|
Std_ID_179
|
||||||
|
Std_ID_180
|
||||||
|
Std_ID_181
|
||||||
|
Std_ID_182
|
||||||
|
Std_ID_183
|
||||||
|
Std_ID_184
|
||||||
|
Std_ID_185
|
||||||
|
Std_ID_186
|
||||||
|
Std_ID_187
|
||||||
|
Std_ID_188
|
||||||
|
Std_ID_189
|
||||||
|
Std_ID_190
|
||||||
|
Std_ID_191
|
||||||
|
Std_ID_192
|
||||||
|
Std_ID_193
|
||||||
|
Std_ID_194
|
||||||
|
Std_ID_195
|
||||||
|
Std_ID_196
|
||||||
|
Std_ID_197
|
||||||
|
Std_ID_198
|
||||||
|
Std_ID_199
|
||||||
|
Std_ID_200
|
||||||
|
Std_ID_201
|
||||||
|
Std_ID_202
|
||||||
|
Std_ID_203
|
||||||
|
Std_ID_204
|
||||||
|
Std_ID_205
|
||||||
|
Std_ID_206
|
||||||
|
Std_ID_207
|
||||||
|
Std_ID_208
|
||||||
|
Std_ID_209
|
||||||
|
Std_ID_210
|
||||||
|
Std_ID_211
|
||||||
|
Std_ID_212
|
||||||
|
Std_ID_213
|
||||||
|
Std_ID_214
|
||||||
|
Std_ID_215
|
||||||
|
Std_ID_216
|
||||||
|
Std_ID_217
|
||||||
|
Std_ID_218
|
||||||
|
Std_ID_219
|
||||||
|
Std_ID_220
|
||||||
|
Std_ID_221
|
||||||
|
Std_ID_222
|
||||||
|
Std_ID_223
|
||||||
|
Std_ID_224
|
||||||
|
Std_ID_225
|
||||||
|
Std_ID_226
|
||||||
|
Std_ID_227
|
||||||
|
Std_ID_228
|
||||||
|
Std_ID_229
|
||||||
|
Std_ID_230
|
||||||
|
Std_ID_231
|
||||||
|
Std_ID_232
|
||||||
|
Std_ID_233
|
||||||
|
Std_ID_234
|
||||||
|
Std_ID_235
|
||||||
|
Std_ID_236
|
||||||
|
Std_ID_237
|
||||||
|
Std_ID_238
|
||||||
|
Std_ID_239
|
||||||
|
Std_ID_240
|
||||||
|
Std_ID_241
|
||||||
|
Std_ID_242
|
||||||
|
Std_ID_243
|
||||||
|
Std_ID_244
|
||||||
|
Std_ID_245
|
||||||
|
Std_ID_246
|
||||||
|
Std_ID_247
|
||||||
|
Std_ID_248
|
||||||
|
Std_ID_249
|
||||||
|
Std_ID_250
|
||||||
|
@@ -2,7 +2,14 @@ module org.example.se302 {
|
|||||||
requires javafx.controls;
|
requires javafx.controls;
|
||||||
requires javafx.fxml;
|
requires javafx.fxml;
|
||||||
|
|
||||||
|
// Export all packages
|
||||||
opens org.example.se302 to javafx.fxml;
|
|
||||||
exports org.example.se302;
|
exports org.example.se302;
|
||||||
|
exports org.example.se302.controller;
|
||||||
|
exports org.example.se302.model;
|
||||||
|
exports org.example.se302.service;
|
||||||
|
|
||||||
|
// Open packages for reflection (FXML loading)
|
||||||
|
opens org.example.se302 to javafx.fxml;
|
||||||
|
opens org.example.se302.controller to javafx.fxml;
|
||||||
|
opens org.example.se302.model to javafx.base;
|
||||||
}
|
}
|
||||||
36
src/main/java/org/example/se302/ExamSchedulerApp.java
Normal file
36
src/main/java/org/example/se302/ExamSchedulerApp.java
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package org.example.se302;
|
||||||
|
|
||||||
|
import javafx.application.Application;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main JavaFX Application for Exam Scheduling System.
|
||||||
|
*/
|
||||||
|
public class ExamSchedulerApp extends Application {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(Stage stage) throws IOException {
|
||||||
|
FXMLLoader fxmlLoader = new FXMLLoader(
|
||||||
|
ExamSchedulerApp.class.getResource("view/main-view.fxml")
|
||||||
|
);
|
||||||
|
Scene scene = new Scene(fxmlLoader.load(), 1200, 800);
|
||||||
|
|
||||||
|
// Load CSS stylesheet
|
||||||
|
String css = ExamSchedulerApp.class.getResource("css/application.css").toExternalForm();
|
||||||
|
scene.getStylesheets().add(css);
|
||||||
|
|
||||||
|
stage.setTitle("Exam Scheduling System v1.0");
|
||||||
|
stage.setMinWidth(900);
|
||||||
|
stage.setMinHeight(600);
|
||||||
|
stage.setScene(scene);
|
||||||
|
stage.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
launch();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,6 @@ import javafx.application.Application;
|
|||||||
|
|
||||||
public class Launcher {
|
public class Launcher {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
Application.launch(HelloApplication.class, args);
|
Application.launch(ExamSchedulerApp.class, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package org.example.se302.controller;
|
||||||
|
|
||||||
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.TableColumn;
|
||||||
|
import javafx.scene.control.TableView;
|
||||||
|
import org.example.se302.model.Classroom;
|
||||||
|
import org.example.se302.service.DataManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for the Classrooms view.
|
||||||
|
*/
|
||||||
|
public class ClassroomsController {
|
||||||
|
|
||||||
|
@FXML private TableView<Classroom> classroomsTable;
|
||||||
|
@FXML private TableColumn<Classroom, String> classroomIdColumn;
|
||||||
|
@FXML private TableColumn<Classroom, Number> capacityColumn;
|
||||||
|
@FXML private TableColumn<Classroom, String> statusColumn;
|
||||||
|
@FXML private TableColumn<Classroom, String> utilizationColumn;
|
||||||
|
|
||||||
|
@FXML private Label totalClassroomsLabel;
|
||||||
|
@FXML private Label totalCapacityLabel;
|
||||||
|
@FXML private Label averageCapacityLabel;
|
||||||
|
|
||||||
|
private DataManager dataManager;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
dataManager = DataManager.getInstance();
|
||||||
|
|
||||||
|
// Set up table columns
|
||||||
|
classroomIdColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleStringProperty(cellData.getValue().getClassroomId()));
|
||||||
|
|
||||||
|
capacityColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleIntegerProperty(cellData.getValue().getCapacity()));
|
||||||
|
|
||||||
|
statusColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleStringProperty("Available")); // For demo phase
|
||||||
|
|
||||||
|
utilizationColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleStringProperty("Not Scheduled")); // For demo phase
|
||||||
|
|
||||||
|
// Bind table to data
|
||||||
|
classroomsTable.setItems(dataManager.getClassrooms());
|
||||||
|
|
||||||
|
// Update summary statistics
|
||||||
|
updateSummaryStatistics();
|
||||||
|
|
||||||
|
// Listen for data changes
|
||||||
|
dataManager.getClassrooms().addListener(
|
||||||
|
(javafx.collections.ListChangeListener<Classroom>) c -> updateSummaryStatistics());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSummaryStatistics() {
|
||||||
|
int totalClassrooms = dataManager.getTotalClassrooms();
|
||||||
|
int totalCapacity = dataManager.getClassrooms().stream()
|
||||||
|
.mapToInt(Classroom::getCapacity)
|
||||||
|
.sum();
|
||||||
|
double averageCapacity = totalClassrooms > 0 ?
|
||||||
|
(double) totalCapacity / totalClassrooms : 0;
|
||||||
|
|
||||||
|
totalClassroomsLabel.setText("Total Classrooms: " + totalClassrooms);
|
||||||
|
totalCapacityLabel.setText("Total Capacity: " + totalCapacity);
|
||||||
|
averageCapacityLabel.setText(String.format("Average Capacity: %.1f", averageCapacity));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
package org.example.se302.controller;
|
||||||
|
|
||||||
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.transformation.FilteredList;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.control.*;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
import org.example.se302.model.Course;
|
||||||
|
import org.example.se302.service.DataManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for the Courses view.
|
||||||
|
*/
|
||||||
|
public class CoursesController {
|
||||||
|
|
||||||
|
@FXML private TextField searchField;
|
||||||
|
@FXML private Label resultCountLabel;
|
||||||
|
@FXML private TableView<Course> coursesTable;
|
||||||
|
@FXML private TableColumn<Course, String> courseCodeColumn;
|
||||||
|
@FXML private TableColumn<Course, Number> studentCountColumn;
|
||||||
|
@FXML private TableColumn<Course, String> classroomColumn;
|
||||||
|
@FXML private TableColumn<Course, String> examDateColumn;
|
||||||
|
@FXML private TableColumn<Course, Void> actionColumn;
|
||||||
|
|
||||||
|
@FXML private VBox studentListPanel;
|
||||||
|
@FXML private Label studentListTitleLabel;
|
||||||
|
@FXML private TableView<String> enrolledStudentsTable;
|
||||||
|
@FXML private TableColumn<String, String> enrolledStudentIdColumn;
|
||||||
|
@FXML private Label enrolledCountLabel;
|
||||||
|
|
||||||
|
private DataManager dataManager;
|
||||||
|
private FilteredList<Course> filteredCourses;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
dataManager = DataManager.getInstance();
|
||||||
|
|
||||||
|
// Set up table columns
|
||||||
|
courseCodeColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleStringProperty(cellData.getValue().getCourseCode()));
|
||||||
|
|
||||||
|
studentCountColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleIntegerProperty(cellData.getValue().getEnrolledStudentsCount()));
|
||||||
|
|
||||||
|
classroomColumn.setCellValueFactory(cellData -> {
|
||||||
|
String classroom = cellData.getValue().getAssignedClassroom();
|
||||||
|
return new SimpleStringProperty(classroom != null ? classroom : "Not Assigned");
|
||||||
|
});
|
||||||
|
|
||||||
|
examDateColumn.setCellValueFactory(cellData -> {
|
||||||
|
String examDate = cellData.getValue().getExamDateTime();
|
||||||
|
return new SimpleStringProperty(examDate != null ? examDate : "Not Scheduled");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add "View Students" button to action column
|
||||||
|
actionColumn.setCellFactory(col -> new TableCell<>() {
|
||||||
|
private final Button viewButton = new Button("View Students");
|
||||||
|
|
||||||
|
{
|
||||||
|
viewButton.setOnAction(event -> {
|
||||||
|
Course course = getTableView().getItems().get(getIndex());
|
||||||
|
showEnrolledStudents(course);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateItem(Void item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
setGraphic(empty ? null : viewButton);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set up enrolled students table column
|
||||||
|
enrolledStudentIdColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleStringProperty(cellData.getValue()));
|
||||||
|
|
||||||
|
// Set up filtered list
|
||||||
|
filteredCourses = new FilteredList<>(dataManager.getCourses(), p -> true);
|
||||||
|
coursesTable.setItems(filteredCourses);
|
||||||
|
|
||||||
|
// Set up search functionality
|
||||||
|
searchField.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
filterCourses(newValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update result count
|
||||||
|
updateResultCount();
|
||||||
|
filteredCourses.addListener((javafx.collections.ListChangeListener<Course>) c -> updateResultCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void onClearSearch() {
|
||||||
|
searchField.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void onCloseStudentList() {
|
||||||
|
studentListPanel.setVisible(false);
|
||||||
|
studentListPanel.setManaged(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void filterCourses(String searchText) {
|
||||||
|
if (searchText == null || searchText.trim().isEmpty()) {
|
||||||
|
filteredCourses.setPredicate(course -> true);
|
||||||
|
} else {
|
||||||
|
String lowerCaseFilter = searchText.toLowerCase().trim();
|
||||||
|
filteredCourses.setPredicate(course ->
|
||||||
|
course.getCourseCode().toLowerCase().contains(lowerCaseFilter)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showEnrolledStudents(Course course) {
|
||||||
|
if (course == null) return;
|
||||||
|
|
||||||
|
studentListTitleLabel.setText("Students Enrolled in " + course.getCourseCode());
|
||||||
|
enrolledStudentsTable.setItems(FXCollections.observableArrayList(course.getEnrolledStudents()));
|
||||||
|
enrolledCountLabel.setText("Total: " + course.getEnrolledStudentsCount() + " students");
|
||||||
|
|
||||||
|
studentListPanel.setVisible(true);
|
||||||
|
studentListPanel.setManaged(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateResultCount() {
|
||||||
|
int total = filteredCourses.size();
|
||||||
|
int overall = dataManager.getTotalCourses();
|
||||||
|
|
||||||
|
if (total == overall) {
|
||||||
|
resultCountLabel.setText("Total: " + total + " courses");
|
||||||
|
} else {
|
||||||
|
resultCountLabel.setText("Showing: " + total + " of " + overall + " courses");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
229
src/main/java/org/example/se302/controller/ImportController.java
Normal file
229
src/main/java/org/example/se302/controller/ImportController.java
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
package org.example.se302.controller;
|
||||||
|
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.TextArea;
|
||||||
|
import javafx.scene.control.TextField;
|
||||||
|
import javafx.stage.FileChooser;
|
||||||
|
import org.example.se302.model.ImportResult;
|
||||||
|
import org.example.se302.service.DataImportService;
|
||||||
|
import org.example.se302.service.DataManager;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for the Import Data view.
|
||||||
|
*/
|
||||||
|
public class ImportController {
|
||||||
|
|
||||||
|
@FXML private TextField studentFileField;
|
||||||
|
@FXML private TextField courseFileField;
|
||||||
|
@FXML private TextField classroomFileField;
|
||||||
|
@FXML private TextField enrollmentFileField;
|
||||||
|
|
||||||
|
@FXML private Label studentStatusLabel;
|
||||||
|
@FXML private Label courseStatusLabel;
|
||||||
|
@FXML private Label classroomStatusLabel;
|
||||||
|
@FXML private Label enrollmentStatusLabel;
|
||||||
|
|
||||||
|
@FXML private TextArea messagesArea;
|
||||||
|
@FXML private Button importAllButton;
|
||||||
|
|
||||||
|
private File studentFile;
|
||||||
|
private File courseFile;
|
||||||
|
private File classroomFile;
|
||||||
|
private File enrollmentFile;
|
||||||
|
|
||||||
|
private DataImportService importService;
|
||||||
|
private DataManager dataManager;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
importService = new DataImportService();
|
||||||
|
dataManager = DataManager.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void onBrowseStudents() {
|
||||||
|
FileChooser fileChooser = createFileChooser("Select Student Data CSV");
|
||||||
|
studentFile = fileChooser.showOpenDialog(studentFileField.getScene().getWindow());
|
||||||
|
|
||||||
|
if (studentFile != null) {
|
||||||
|
studentFileField.setText(studentFile.getAbsolutePath());
|
||||||
|
studentStatusLabel.setText("File selected - Ready to import");
|
||||||
|
studentStatusLabel.setStyle("-fx-text-fill: blue;");
|
||||||
|
checkAllFilesSelected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void onBrowseCourses() {
|
||||||
|
FileChooser fileChooser = createFileChooser("Select Course Data CSV");
|
||||||
|
courseFile = fileChooser.showOpenDialog(courseFileField.getScene().getWindow());
|
||||||
|
|
||||||
|
if (courseFile != null) {
|
||||||
|
courseFileField.setText(courseFile.getAbsolutePath());
|
||||||
|
courseStatusLabel.setText("File selected - Ready to import");
|
||||||
|
courseStatusLabel.setStyle("-fx-text-fill: blue;");
|
||||||
|
checkAllFilesSelected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void onBrowseClassrooms() {
|
||||||
|
FileChooser fileChooser = createFileChooser("Select Classroom Data CSV");
|
||||||
|
classroomFile = fileChooser.showOpenDialog(classroomFileField.getScene().getWindow());
|
||||||
|
|
||||||
|
if (classroomFile != null) {
|
||||||
|
classroomFileField.setText(classroomFile.getAbsolutePath());
|
||||||
|
classroomStatusLabel.setText("File selected - Ready to import");
|
||||||
|
classroomStatusLabel.setStyle("-fx-text-fill: blue;");
|
||||||
|
checkAllFilesSelected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void onBrowseEnrollments() {
|
||||||
|
FileChooser fileChooser = createFileChooser("Select Enrollment Data CSV");
|
||||||
|
enrollmentFile = fileChooser.showOpenDialog(enrollmentFileField.getScene().getWindow());
|
||||||
|
|
||||||
|
if (enrollmentFile != null) {
|
||||||
|
enrollmentFileField.setText(enrollmentFile.getAbsolutePath());
|
||||||
|
enrollmentStatusLabel.setText("File selected - Ready to import");
|
||||||
|
enrollmentStatusLabel.setStyle("-fx-text-fill: blue;");
|
||||||
|
checkAllFilesSelected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void onImportAll() {
|
||||||
|
messagesArea.clear();
|
||||||
|
messagesArea.appendText("Starting import process...\n\n");
|
||||||
|
|
||||||
|
// Clear existing data
|
||||||
|
dataManager.clearAll();
|
||||||
|
|
||||||
|
// Import students
|
||||||
|
messagesArea.appendText("Importing students...\n");
|
||||||
|
ImportResult studentResult = importService.importStudents(studentFile);
|
||||||
|
updateStatus(studentStatusLabel, studentResult);
|
||||||
|
messagesArea.appendText(studentResult.getFormattedMessage() + "\n");
|
||||||
|
|
||||||
|
// Import courses
|
||||||
|
messagesArea.appendText("Importing courses...\n");
|
||||||
|
ImportResult courseResult = importService.importCourses(courseFile);
|
||||||
|
updateStatus(courseStatusLabel, courseResult);
|
||||||
|
messagesArea.appendText(courseResult.getFormattedMessage() + "\n");
|
||||||
|
|
||||||
|
// Import classrooms
|
||||||
|
messagesArea.appendText("Importing classrooms...\n");
|
||||||
|
ImportResult classroomResult = importService.importClassrooms(classroomFile);
|
||||||
|
updateStatus(classroomStatusLabel, classroomResult);
|
||||||
|
messagesArea.appendText(classroomResult.getFormattedMessage() + "\n");
|
||||||
|
|
||||||
|
// Import enrollments (must be after students and courses)
|
||||||
|
messagesArea.appendText("Importing enrollments...\n");
|
||||||
|
ImportResult enrollmentResult = importService.importEnrollments(enrollmentFile);
|
||||||
|
updateStatus(enrollmentStatusLabel, enrollmentResult);
|
||||||
|
messagesArea.appendText(enrollmentResult.getFormattedMessage() + "\n");
|
||||||
|
|
||||||
|
// Check if all imports were successful
|
||||||
|
if (studentResult.isSuccess() && courseResult.isSuccess() &&
|
||||||
|
classroomResult.isSuccess() && enrollmentResult.isSuccess()) {
|
||||||
|
|
||||||
|
messagesArea.appendText("\n========================================\n");
|
||||||
|
messagesArea.appendText("IMPORT SUCCESSFUL!\n");
|
||||||
|
messagesArea.appendText("========================================\n");
|
||||||
|
messagesArea.appendText(String.format("- Loaded %d students\n", dataManager.getTotalStudents()));
|
||||||
|
messagesArea.appendText(String.format("- Loaded %d courses\n", dataManager.getTotalCourses()));
|
||||||
|
messagesArea.appendText(String.format("- Loaded %d classrooms\n", dataManager.getTotalClassrooms()));
|
||||||
|
messagesArea.appendText("- Data is ready for viewing and scheduling\n");
|
||||||
|
messagesArea.appendText("\nYou can now navigate to other tabs to view the data.\n");
|
||||||
|
|
||||||
|
// Enable other tabs
|
||||||
|
enableDataTabs();
|
||||||
|
} else {
|
||||||
|
messagesArea.appendText("\n========================================\n");
|
||||||
|
messagesArea.appendText("IMPORT COMPLETED WITH ERRORS\n");
|
||||||
|
messagesArea.appendText("========================================\n");
|
||||||
|
messagesArea.appendText("Please check the error messages above and fix the CSV files.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void onClearAll() {
|
||||||
|
studentFile = null;
|
||||||
|
courseFile = null;
|
||||||
|
classroomFile = null;
|
||||||
|
enrollmentFile = null;
|
||||||
|
|
||||||
|
studentFileField.clear();
|
||||||
|
courseFileField.clear();
|
||||||
|
classroomFileField.clear();
|
||||||
|
enrollmentFileField.clear();
|
||||||
|
|
||||||
|
studentStatusLabel.setText("Not Loaded");
|
||||||
|
courseStatusLabel.setText("Not Loaded");
|
||||||
|
classroomStatusLabel.setText("Not Loaded");
|
||||||
|
enrollmentStatusLabel.setText("Not Loaded");
|
||||||
|
|
||||||
|
studentStatusLabel.setStyle("");
|
||||||
|
courseStatusLabel.setStyle("");
|
||||||
|
classroomStatusLabel.setStyle("");
|
||||||
|
enrollmentStatusLabel.setStyle("");
|
||||||
|
|
||||||
|
messagesArea.clear();
|
||||||
|
importAllButton.setDisable(true);
|
||||||
|
|
||||||
|
dataManager.clearAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private FileChooser createFileChooser(String title) {
|
||||||
|
FileChooser fileChooser = new FileChooser();
|
||||||
|
fileChooser.setTitle(title);
|
||||||
|
fileChooser.getExtensionFilters().add(
|
||||||
|
new FileChooser.ExtensionFilter("CSV Files", "*.csv")
|
||||||
|
);
|
||||||
|
|
||||||
|
// Set initial directory to sampleData if it exists
|
||||||
|
File sampleDataDir = new File("sampleData");
|
||||||
|
if (sampleDataDir.exists() && sampleDataDir.isDirectory()) {
|
||||||
|
fileChooser.setInitialDirectory(sampleDataDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileChooser;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkAllFilesSelected() {
|
||||||
|
boolean allSelected = studentFile != null && courseFile != null &&
|
||||||
|
classroomFile != null && enrollmentFile != null;
|
||||||
|
importAllButton.setDisable(!allSelected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateStatus(Label statusLabel, ImportResult result) {
|
||||||
|
if (result.isSuccess()) {
|
||||||
|
statusLabel.setText("Loaded: " + result.getRecordCount() + " records");
|
||||||
|
statusLabel.setStyle("-fx-text-fill: green;");
|
||||||
|
} else {
|
||||||
|
statusLabel.setText("Error - See messages below");
|
||||||
|
statusLabel.setStyle("-fx-text-fill: red;");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enableDataTabs() {
|
||||||
|
// The tabs will be enabled via the MainController
|
||||||
|
// For now, we'll use a simple approach by navigating up the scene graph
|
||||||
|
try {
|
||||||
|
// Get the root BorderPane from main-view.fxml
|
||||||
|
javafx.scene.Parent root = studentFileField.getScene().getRoot();
|
||||||
|
|
||||||
|
// Since we can't easily access the MainController from here,
|
||||||
|
// we'll just let the user know they can navigate to other tabs
|
||||||
|
// The tabs are already set to enabled in the success message
|
||||||
|
messagesArea.appendText("Note: You can now switch to the Students, Courses, Classrooms, or Schedule Views tabs.\n");
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Ignore if we can't access the scene graph
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package org.example.se302.controller;
|
||||||
|
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.Tab;
|
||||||
|
import javafx.scene.control.TabPane;
|
||||||
|
import org.example.se302.service.DataManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main controller for the application window.
|
||||||
|
* Manages the TabPane and status bar.
|
||||||
|
*/
|
||||||
|
public class MainController {
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private TabPane mainTabPane;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Tab importTab;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Tab studentsTab;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Tab coursesTab;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Tab classroomsTab;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Tab scheduleTab;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Label statusLabel;
|
||||||
|
|
||||||
|
private DataManager dataManager;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
dataManager = DataManager.getInstance();
|
||||||
|
|
||||||
|
// Initially disable data tabs until import is complete
|
||||||
|
studentsTab.setDisable(true);
|
||||||
|
coursesTab.setDisable(true);
|
||||||
|
classroomsTab.setDisable(true);
|
||||||
|
scheduleTab.setDisable(true);
|
||||||
|
|
||||||
|
updateStatusBar();
|
||||||
|
|
||||||
|
// Listen for data changes to automatically enable tabs
|
||||||
|
dataManager.getStudents().addListener(
|
||||||
|
(javafx.collections.ListChangeListener<org.example.se302.model.Student>) c -> {
|
||||||
|
if (dataManager.hasData()) {
|
||||||
|
enableDataTabs();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable data tabs after successful import.
|
||||||
|
*/
|
||||||
|
public void enableDataTabs() {
|
||||||
|
studentsTab.setDisable(false);
|
||||||
|
coursesTab.setDisable(false);
|
||||||
|
classroomsTab.setDisable(false);
|
||||||
|
scheduleTab.setDisable(false);
|
||||||
|
updateStatusBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the status bar with current data counts.
|
||||||
|
*/
|
||||||
|
public void updateStatusBar() {
|
||||||
|
if (!dataManager.hasData()) {
|
||||||
|
statusLabel.setText("Ready - No data loaded");
|
||||||
|
} else {
|
||||||
|
statusLabel.setText(String.format(
|
||||||
|
"Loaded: %d Students, %d Courses, %d Classrooms",
|
||||||
|
dataManager.getTotalStudents(),
|
||||||
|
dataManager.getTotalCourses(),
|
||||||
|
dataManager.getTotalClassrooms()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package org.example.se302.controller;
|
||||||
|
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.control.Alert;
|
||||||
|
import javafx.scene.control.DatePicker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for the Calendar/Day schedule view.
|
||||||
|
*/
|
||||||
|
public class ScheduleCalendarController {
|
||||||
|
|
||||||
|
@FXML private DatePicker startDatePicker;
|
||||||
|
@FXML private DatePicker endDatePicker;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
// Initialize with default date range if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void onGenerateSchedule() {
|
||||||
|
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
|
alert.setTitle("Coming Soon");
|
||||||
|
alert.setHeaderText("Schedule Generation");
|
||||||
|
alert.setContentText("The CSP-based schedule generation algorithm will be implemented in Phase 2.\n\n" +
|
||||||
|
"It will automatically create an exam schedule that satisfies all constraints:\n" +
|
||||||
|
"- No consecutive exams for students\n" +
|
||||||
|
"- Max 2 exams per day per student\n" +
|
||||||
|
"- Classroom capacity limits\n" +
|
||||||
|
"- No double-booking");
|
||||||
|
alert.showAndWait();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package org.example.se302.controller;
|
||||||
|
|
||||||
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.control.ComboBox;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.TableColumn;
|
||||||
|
import javafx.scene.control.TableView;
|
||||||
|
import org.example.se302.model.Classroom;
|
||||||
|
import org.example.se302.service.DataManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for the Classroom Schedule view.
|
||||||
|
*/
|
||||||
|
public class ScheduleClassroomController {
|
||||||
|
|
||||||
|
@FXML private ComboBox<Classroom> classroomComboBox;
|
||||||
|
@FXML private Label selectedClassroomLabel;
|
||||||
|
@FXML private TableView<ClassroomSlotEntry> scheduleTable;
|
||||||
|
@FXML private TableColumn<ClassroomSlotEntry, String> dateColumn;
|
||||||
|
@FXML private TableColumn<ClassroomSlotEntry, String> timeColumn;
|
||||||
|
@FXML private TableColumn<ClassroomSlotEntry, String> courseColumn;
|
||||||
|
@FXML private TableColumn<ClassroomSlotEntry, Number> studentsColumn;
|
||||||
|
@FXML private TableColumn<ClassroomSlotEntry, String> utilizationColumn;
|
||||||
|
@FXML private Label utilizationLabel;
|
||||||
|
|
||||||
|
private DataManager dataManager;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
dataManager = DataManager.getInstance();
|
||||||
|
|
||||||
|
// Populate classroom combo box
|
||||||
|
classroomComboBox.setItems(dataManager.getClassrooms());
|
||||||
|
|
||||||
|
// Set up table columns
|
||||||
|
dateColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleStringProperty(cellData.getValue().getDate()));
|
||||||
|
timeColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleStringProperty(cellData.getValue().getTime()));
|
||||||
|
courseColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleStringProperty(cellData.getValue().getCourse()));
|
||||||
|
studentsColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleIntegerProperty(cellData.getValue().getStudentCount()));
|
||||||
|
utilizationColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleStringProperty(cellData.getValue().getUtilization()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void onShowSchedule() {
|
||||||
|
Classroom selected = classroomComboBox.getValue();
|
||||||
|
if (selected == null) return;
|
||||||
|
|
||||||
|
selectedClassroomLabel.setText("Schedule for: " + selected.getClassroomId() +
|
||||||
|
" (Capacity: " + selected.getCapacity() + ")");
|
||||||
|
|
||||||
|
// For demo: show empty schedule
|
||||||
|
ObservableList<ClassroomSlotEntry> entries = FXCollections.observableArrayList();
|
||||||
|
scheduleTable.setItems(entries);
|
||||||
|
|
||||||
|
utilizationLabel.setText("Overall Utilization: 0% (No exams scheduled)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper class for table entries
|
||||||
|
public static class ClassroomSlotEntry {
|
||||||
|
private final String date;
|
||||||
|
private final String time;
|
||||||
|
private final String course;
|
||||||
|
private final int studentCount;
|
||||||
|
private final String utilization;
|
||||||
|
|
||||||
|
public ClassroomSlotEntry(String date, String time, String course, int studentCount, String utilization) {
|
||||||
|
this.date = date;
|
||||||
|
this.time = time;
|
||||||
|
this.course = course;
|
||||||
|
this.studentCount = studentCount;
|
||||||
|
this.utilization = utilization;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDate() { return date; }
|
||||||
|
public String getTime() { return time; }
|
||||||
|
public String getCourse() { return course; }
|
||||||
|
public int getStudentCount() { return studentCount; }
|
||||||
|
public String getUtilization() { return utilization; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package org.example.se302.controller;
|
||||||
|
|
||||||
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.control.TableColumn;
|
||||||
|
import javafx.scene.control.TableView;
|
||||||
|
import org.example.se302.model.Course;
|
||||||
|
import org.example.se302.service.DataManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for the Course Schedule view.
|
||||||
|
*/
|
||||||
|
public class ScheduleCourseController {
|
||||||
|
|
||||||
|
@FXML private TableView<CourseScheduleEntry> courseScheduleTable;
|
||||||
|
@FXML private TableColumn<CourseScheduleEntry, String> courseCodeColumn;
|
||||||
|
@FXML private TableColumn<CourseScheduleEntry, Number> enrolledColumn;
|
||||||
|
@FXML private TableColumn<CourseScheduleEntry, String> dateColumn;
|
||||||
|
@FXML private TableColumn<CourseScheduleEntry, String> timeColumn;
|
||||||
|
@FXML private TableColumn<CourseScheduleEntry, String> classroomColumn;
|
||||||
|
|
||||||
|
private DataManager dataManager;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
dataManager = DataManager.getInstance();
|
||||||
|
|
||||||
|
// Set up table columns
|
||||||
|
courseCodeColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleStringProperty(cellData.getValue().getCourseCode()));
|
||||||
|
enrolledColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleIntegerProperty(cellData.getValue().getEnrolledCount()));
|
||||||
|
dateColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleStringProperty(cellData.getValue().getDate()));
|
||||||
|
timeColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleStringProperty(cellData.getValue().getTime()));
|
||||||
|
classroomColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleStringProperty(cellData.getValue().getClassroom()));
|
||||||
|
|
||||||
|
// Load data
|
||||||
|
loadScheduleData();
|
||||||
|
|
||||||
|
// Listen for data changes
|
||||||
|
dataManager.getCourses().addListener(
|
||||||
|
(javafx.collections.ListChangeListener<Course>) c -> loadScheduleData());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadScheduleData() {
|
||||||
|
ObservableList<CourseScheduleEntry> entries = FXCollections.observableArrayList();
|
||||||
|
|
||||||
|
for (Course course : dataManager.getCourses()) {
|
||||||
|
entries.add(new CourseScheduleEntry(
|
||||||
|
course.getCourseCode(),
|
||||||
|
course.getEnrolledStudentsCount(),
|
||||||
|
"Not Scheduled",
|
||||||
|
"-",
|
||||||
|
"-"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
courseScheduleTable.setItems(entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper class for table entries
|
||||||
|
public static class CourseScheduleEntry {
|
||||||
|
private final String courseCode;
|
||||||
|
private final int enrolledCount;
|
||||||
|
private final String date;
|
||||||
|
private final String time;
|
||||||
|
private final String classroom;
|
||||||
|
|
||||||
|
public CourseScheduleEntry(String courseCode, int enrolledCount, String date, String time, String classroom) {
|
||||||
|
this.courseCode = courseCode;
|
||||||
|
this.enrolledCount = enrolledCount;
|
||||||
|
this.date = date;
|
||||||
|
this.time = time;
|
||||||
|
this.classroom = classroom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCourseCode() { return courseCode; }
|
||||||
|
public int getEnrolledCount() { return enrolledCount; }
|
||||||
|
public String getDate() { return date; }
|
||||||
|
public String getTime() { return time; }
|
||||||
|
public String getClassroom() { return classroom; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package org.example.se302.controller;
|
||||||
|
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.control.ComboBox;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.TableColumn;
|
||||||
|
import javafx.scene.control.TableView;
|
||||||
|
import org.example.se302.model.Student;
|
||||||
|
import org.example.se302.service.DataManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for the Student Schedule view.
|
||||||
|
*/
|
||||||
|
public class ScheduleStudentController {
|
||||||
|
|
||||||
|
@FXML private ComboBox<Student> studentComboBox;
|
||||||
|
@FXML private Label selectedStudentLabel;
|
||||||
|
@FXML private TableView<CourseScheduleEntry> scheduleTable;
|
||||||
|
@FXML private TableColumn<CourseScheduleEntry, String> courseColumn;
|
||||||
|
@FXML private TableColumn<CourseScheduleEntry, String> dateColumn;
|
||||||
|
@FXML private TableColumn<CourseScheduleEntry, String> timeColumn;
|
||||||
|
@FXML private TableColumn<CourseScheduleEntry, String> classroomColumn;
|
||||||
|
|
||||||
|
private DataManager dataManager;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
dataManager = DataManager.getInstance();
|
||||||
|
|
||||||
|
// Populate student combo box
|
||||||
|
studentComboBox.setItems(dataManager.getStudents());
|
||||||
|
|
||||||
|
// Set up table columns
|
||||||
|
courseColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleStringProperty(cellData.getValue().getCourseCode()));
|
||||||
|
dateColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleStringProperty(cellData.getValue().getDate()));
|
||||||
|
timeColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleStringProperty(cellData.getValue().getTime()));
|
||||||
|
classroomColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleStringProperty(cellData.getValue().getClassroom()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void onShowSchedule() {
|
||||||
|
Student selected = studentComboBox.getValue();
|
||||||
|
if (selected == null) return;
|
||||||
|
|
||||||
|
selectedStudentLabel.setText("Exam Schedule for: " + selected.getStudentId());
|
||||||
|
|
||||||
|
// For demo: show enrolled courses with "Not Scheduled" status
|
||||||
|
ObservableList<CourseScheduleEntry> entries = FXCollections.observableArrayList();
|
||||||
|
for (String courseCode : selected.getEnrolledCourses()) {
|
||||||
|
entries.add(new CourseScheduleEntry(courseCode, "Not Scheduled", "-", "-"));
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduleTable.setItems(entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper class for table entries
|
||||||
|
public static class CourseScheduleEntry {
|
||||||
|
private final String courseCode;
|
||||||
|
private final String date;
|
||||||
|
private final String time;
|
||||||
|
private final String classroom;
|
||||||
|
|
||||||
|
public CourseScheduleEntry(String courseCode, String date, String time, String classroom) {
|
||||||
|
this.courseCode = courseCode;
|
||||||
|
this.date = date;
|
||||||
|
this.time = time;
|
||||||
|
this.classroom = classroom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCourseCode() { return courseCode; }
|
||||||
|
public String getDate() { return date; }
|
||||||
|
public String getTime() { return time; }
|
||||||
|
public String getClassroom() { return classroom; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package org.example.se302.controller;
|
||||||
|
|
||||||
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.transformation.FilteredList;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.control.*;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
import org.example.se302.model.Student;
|
||||||
|
import org.example.se302.service.DataManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for the Students view.
|
||||||
|
*/
|
||||||
|
public class StudentsController {
|
||||||
|
|
||||||
|
@FXML private TextField searchField;
|
||||||
|
@FXML private Label resultCountLabel;
|
||||||
|
@FXML private TableView<Student> studentsTable;
|
||||||
|
@FXML private TableColumn<Student, String> studentIdColumn;
|
||||||
|
@FXML private TableColumn<Student, Number> courseCountColumn;
|
||||||
|
@FXML private TableColumn<Student, Void> actionColumn;
|
||||||
|
|
||||||
|
@FXML private VBox detailPanel;
|
||||||
|
@FXML private Label detailStudentIdLabel;
|
||||||
|
@FXML private ListView<String> coursesList;
|
||||||
|
@FXML private Label detailCourseCountLabel;
|
||||||
|
|
||||||
|
private DataManager dataManager;
|
||||||
|
private FilteredList<Student> filteredStudents;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
dataManager = DataManager.getInstance();
|
||||||
|
|
||||||
|
// Set up table columns
|
||||||
|
studentIdColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleStringProperty(cellData.getValue().getStudentId()));
|
||||||
|
|
||||||
|
courseCountColumn.setCellValueFactory(cellData ->
|
||||||
|
new SimpleIntegerProperty(cellData.getValue().getEnrolledCoursesCount()));
|
||||||
|
|
||||||
|
// Add "View Details" button to action column
|
||||||
|
actionColumn.setCellFactory(col -> new TableCell<>() {
|
||||||
|
private final Button viewButton = new Button("View Details");
|
||||||
|
|
||||||
|
{
|
||||||
|
viewButton.setOnAction(event -> {
|
||||||
|
Student student = getTableView().getItems().get(getIndex());
|
||||||
|
showStudentDetails(student);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateItem(Void item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
setGraphic(empty ? null : viewButton);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set up filtered list
|
||||||
|
filteredStudents = new FilteredList<>(dataManager.getStudents(), p -> true);
|
||||||
|
studentsTable.setItems(filteredStudents);
|
||||||
|
|
||||||
|
// Set up search functionality
|
||||||
|
searchField.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
filterStudents(newValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update result count
|
||||||
|
updateResultCount();
|
||||||
|
filteredStudents.addListener((javafx.collections.ListChangeListener<Student>) c -> updateResultCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void onClearSearch() {
|
||||||
|
searchField.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void onCloseDetail() {
|
||||||
|
detailPanel.setVisible(false);
|
||||||
|
detailPanel.setManaged(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void filterStudents(String searchText) {
|
||||||
|
if (searchText == null || searchText.trim().isEmpty()) {
|
||||||
|
filteredStudents.setPredicate(student -> true);
|
||||||
|
} else {
|
||||||
|
String lowerCaseFilter = searchText.toLowerCase().trim();
|
||||||
|
filteredStudents.setPredicate(student ->
|
||||||
|
student.getStudentId().toLowerCase().contains(lowerCaseFilter)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showStudentDetails(Student student) {
|
||||||
|
if (student == null) return;
|
||||||
|
|
||||||
|
detailStudentIdLabel.setText("Student ID: " + student.getStudentId());
|
||||||
|
coursesList.setItems(FXCollections.observableArrayList(student.getEnrolledCourses()));
|
||||||
|
detailCourseCountLabel.setText("Total: " + student.getEnrolledCoursesCount() + " courses");
|
||||||
|
|
||||||
|
detailPanel.setVisible(true);
|
||||||
|
detailPanel.setManaged(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateResultCount() {
|
||||||
|
int total = filteredStudents.size();
|
||||||
|
int overall = dataManager.getTotalStudents();
|
||||||
|
|
||||||
|
if (total == overall) {
|
||||||
|
resultCountLabel.setText("Total: " + total + " students");
|
||||||
|
} else {
|
||||||
|
resultCountLabel.setText("Showing: " + total + " of " + overall + " students");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/main/java/org/example/se302/model/Classroom.java
Normal file
35
src/main/java/org/example/se302/model/Classroom.java
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package org.example.se302.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a classroom in the exam scheduling system.
|
||||||
|
*/
|
||||||
|
public class Classroom {
|
||||||
|
private String classroomId;
|
||||||
|
private int capacity;
|
||||||
|
|
||||||
|
public Classroom(String classroomId, int capacity) {
|
||||||
|
this.classroomId = classroomId;
|
||||||
|
this.capacity = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClassroomId() {
|
||||||
|
return classroomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClassroomId(String classroomId) {
|
||||||
|
this.classroomId = classroomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCapacity() {
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCapacity(int capacity) {
|
||||||
|
this.capacity = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return classroomId + " (Capacity: " + capacity + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
68
src/main/java/org/example/se302/model/Course.java
Normal file
68
src/main/java/org/example/se302/model/Course.java
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package org.example.se302.model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a course in the exam scheduling system.
|
||||||
|
*/
|
||||||
|
public class Course {
|
||||||
|
private String courseCode;
|
||||||
|
private List<String> enrolledStudents;
|
||||||
|
private String assignedClassroom; // null if not scheduled
|
||||||
|
private String examDateTime; // null if not scheduled
|
||||||
|
|
||||||
|
public Course(String courseCode) {
|
||||||
|
this.courseCode = courseCode;
|
||||||
|
this.enrolledStudents = new ArrayList<>();
|
||||||
|
this.assignedClassroom = null;
|
||||||
|
this.examDateTime = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCourseCode() {
|
||||||
|
return courseCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCourseCode(String courseCode) {
|
||||||
|
this.courseCode = courseCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getEnrolledStudents() {
|
||||||
|
return enrolledStudents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnrolledStudents(List<String> enrolledStudents) {
|
||||||
|
this.enrolledStudents = enrolledStudents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addStudent(String studentId) {
|
||||||
|
if (!enrolledStudents.contains(studentId)) {
|
||||||
|
enrolledStudents.add(studentId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEnrolledStudentsCount() {
|
||||||
|
return enrolledStudents.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAssignedClassroom() {
|
||||||
|
return assignedClassroom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAssignedClassroom(String assignedClassroom) {
|
||||||
|
this.assignedClassroom = assignedClassroom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExamDateTime() {
|
||||||
|
return examDateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExamDateTime(String examDateTime) {
|
||||||
|
this.examDateTime = examDateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return courseCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
79
src/main/java/org/example/se302/model/ImportResult.java
Normal file
79
src/main/java/org/example/se302/model/ImportResult.java
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
package org.example.se302.model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the result of a CSV import operation.
|
||||||
|
*/
|
||||||
|
public class ImportResult {
|
||||||
|
private boolean success;
|
||||||
|
private int recordCount;
|
||||||
|
private List<String> errors;
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public ImportResult() {
|
||||||
|
this.success = false;
|
||||||
|
this.recordCount = 0;
|
||||||
|
this.errors = new ArrayList<>();
|
||||||
|
this.message = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImportResult(boolean success, int recordCount, String message) {
|
||||||
|
this.success = success;
|
||||||
|
this.recordCount = recordCount;
|
||||||
|
this.message = message;
|
||||||
|
this.errors = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuccess(boolean success) {
|
||||||
|
this.success = success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRecordCount() {
|
||||||
|
return recordCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecordCount(int recordCount) {
|
||||||
|
this.recordCount = recordCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getErrors() {
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addError(String error) {
|
||||||
|
this.errors.add(error);
|
||||||
|
this.success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasErrors() {
|
||||||
|
return !errors.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFormattedMessage() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(message).append("\n");
|
||||||
|
|
||||||
|
if (hasErrors()) {
|
||||||
|
sb.append("\nErrors:\n");
|
||||||
|
for (String error : errors) {
|
||||||
|
sb.append(" - ").append(error).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/main/java/org/example/se302/model/Student.java
Normal file
48
src/main/java/org/example/se302/model/Student.java
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package org.example.se302.model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a student in the exam scheduling system.
|
||||||
|
*/
|
||||||
|
public class Student {
|
||||||
|
private String studentId;
|
||||||
|
private List<String> enrolledCourses;
|
||||||
|
|
||||||
|
public Student(String studentId) {
|
||||||
|
this.studentId = studentId;
|
||||||
|
this.enrolledCourses = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStudentId() {
|
||||||
|
return studentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStudentId(String studentId) {
|
||||||
|
this.studentId = studentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getEnrolledCourses() {
|
||||||
|
return enrolledCourses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnrolledCourses(List<String> enrolledCourses) {
|
||||||
|
this.enrolledCourses = enrolledCourses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCourse(String courseCode) {
|
||||||
|
if (!enrolledCourses.contains(courseCode)) {
|
||||||
|
enrolledCourses.add(courseCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEnrolledCoursesCount() {
|
||||||
|
return enrolledCourses.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return studentId;
|
||||||
|
}
|
||||||
|
}
|
||||||
314
src/main/java/org/example/se302/service/DataImportService.java
Normal file
314
src/main/java/org/example/se302/service/DataImportService.java
Normal file
@@ -0,0 +1,314 @@
|
|||||||
|
package org.example.se302.service;
|
||||||
|
|
||||||
|
import org.example.se302.model.Classroom;
|
||||||
|
import org.example.se302.model.Course;
|
||||||
|
import org.example.se302.model.ImportResult;
|
||||||
|
import org.example.se302.model.Student;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service class for importing data from CSV files.
|
||||||
|
*/
|
||||||
|
public class DataImportService {
|
||||||
|
private static final Pattern STUDENT_ID_PATTERN = Pattern.compile("Std_ID_\\d{3}");
|
||||||
|
private static final Pattern COURSE_CODE_PATTERN = Pattern.compile("CourseCode_\\d{2}");
|
||||||
|
private static final Pattern CLASSROOM_ID_PATTERN = Pattern.compile("Classroom_\\d{2}");
|
||||||
|
|
||||||
|
private final DataManager dataManager;
|
||||||
|
|
||||||
|
public DataImportService() {
|
||||||
|
this.dataManager = DataManager.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import students from CSV file.
|
||||||
|
* Format: One student ID per line (after header)
|
||||||
|
*/
|
||||||
|
public ImportResult importStudents(File file) {
|
||||||
|
ImportResult result = new ImportResult();
|
||||||
|
|
||||||
|
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||||
|
List<String> lines = new ArrayList<>();
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
lines.add(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lines.isEmpty()) {
|
||||||
|
result.addError("File is empty");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip header line
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 1; i < lines.size(); i++) {
|
||||||
|
String studentId = lines.get(i).trim();
|
||||||
|
|
||||||
|
if (studentId.isEmpty()) {
|
||||||
|
continue; // Skip empty lines
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!STUDENT_ID_PATTERN.matcher(studentId).matches()) {
|
||||||
|
result.addError("Line " + (i + 1) + ": Invalid student ID format: " + studentId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Student student = new Student(studentId);
|
||||||
|
dataManager.addStudent(student);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.setRecordCount(count);
|
||||||
|
if (!result.hasErrors()) {
|
||||||
|
result.setSuccess(true);
|
||||||
|
result.setMessage("Successfully imported " + count + " students");
|
||||||
|
} else {
|
||||||
|
result.setMessage("Imported " + count + " students with errors");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
result.addError("Failed to read file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import courses from CSV file.
|
||||||
|
* Format: One course code per line (after header)
|
||||||
|
*/
|
||||||
|
public ImportResult importCourses(File file) {
|
||||||
|
ImportResult result = new ImportResult();
|
||||||
|
|
||||||
|
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||||
|
List<String> lines = new ArrayList<>();
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
lines.add(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lines.isEmpty()) {
|
||||||
|
result.addError("File is empty");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip header line
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 1; i < lines.size(); i++) {
|
||||||
|
String courseCode = lines.get(i).trim();
|
||||||
|
|
||||||
|
if (courseCode.isEmpty()) {
|
||||||
|
continue; // Skip empty lines
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!COURSE_CODE_PATTERN.matcher(courseCode).matches()) {
|
||||||
|
result.addError("Line " + (i + 1) + ": Invalid course code format: " + courseCode);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Course course = new Course(courseCode);
|
||||||
|
dataManager.addCourse(course);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.setRecordCount(count);
|
||||||
|
if (!result.hasErrors()) {
|
||||||
|
result.setSuccess(true);
|
||||||
|
result.setMessage("Successfully imported " + count + " courses");
|
||||||
|
} else {
|
||||||
|
result.setMessage("Imported " + count + " courses with errors");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
result.addError("Failed to read file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import classrooms from CSV file.
|
||||||
|
* Format: ClassroomID;Capacity (semicolon-separated)
|
||||||
|
*/
|
||||||
|
public ImportResult importClassrooms(File file) {
|
||||||
|
ImportResult result = new ImportResult();
|
||||||
|
|
||||||
|
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||||
|
List<String> lines = new ArrayList<>();
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
lines.add(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lines.isEmpty()) {
|
||||||
|
result.addError("File is empty");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip header line
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 1; i < lines.size(); i++) {
|
||||||
|
String classroomLine = lines.get(i).trim();
|
||||||
|
|
||||||
|
if (classroomLine.isEmpty()) {
|
||||||
|
continue; // Skip empty lines
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] parts = classroomLine.split(";");
|
||||||
|
if (parts.length != 2) {
|
||||||
|
result.addError("Line " + (i + 1) + ": Invalid format. Expected 'ClassroomID;Capacity'");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String classroomId = parts[0].trim();
|
||||||
|
String capacityStr = parts[1].trim();
|
||||||
|
|
||||||
|
if (!CLASSROOM_ID_PATTERN.matcher(classroomId).matches()) {
|
||||||
|
result.addError("Line " + (i + 1) + ": Invalid classroom ID format: " + classroomId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int capacity = Integer.parseInt(capacityStr);
|
||||||
|
if (capacity <= 0) {
|
||||||
|
result.addError("Line " + (i + 1) + ": Capacity must be positive");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Classroom classroom = new Classroom(classroomId, capacity);
|
||||||
|
dataManager.addClassroom(classroom);
|
||||||
|
count++;
|
||||||
|
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
result.addError("Line " + (i + 1) + ": Invalid capacity number: " + capacityStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.setRecordCount(count);
|
||||||
|
if (!result.hasErrors()) {
|
||||||
|
result.setSuccess(true);
|
||||||
|
result.setMessage("Successfully imported " + count + " classrooms");
|
||||||
|
} else {
|
||||||
|
result.setMessage("Imported " + count + " classrooms with errors");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
result.addError("Failed to read file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import enrollment data from CSV file.
|
||||||
|
* Format: Alternating lines - course code, then Python list of student IDs
|
||||||
|
*/
|
||||||
|
public ImportResult importEnrollments(File file) {
|
||||||
|
ImportResult result = new ImportResult();
|
||||||
|
|
||||||
|
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||||
|
List<String> lines = new ArrayList<>();
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
lines.add(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lines.isEmpty()) {
|
||||||
|
result.addError("File is empty");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int courseCount = 0;
|
||||||
|
int enrollmentCount = 0;
|
||||||
|
|
||||||
|
// Skip header, then process in pairs (course code, student list)
|
||||||
|
for (int i = 1; i < lines.size(); i++) {
|
||||||
|
String courseCode = lines.get(i).trim();
|
||||||
|
|
||||||
|
if (courseCode.isEmpty()) {
|
||||||
|
continue; // Skip empty lines
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next line should be the student list
|
||||||
|
if (i + 1 >= lines.size()) {
|
||||||
|
result.addError("Line " + (i + 1) + ": Missing student list for course " + courseCode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++; // Move to student list line
|
||||||
|
String studentListStr = lines.get(i).trim();
|
||||||
|
|
||||||
|
// Verify course exists
|
||||||
|
Course course = dataManager.getCourse(courseCode);
|
||||||
|
if (course == null) {
|
||||||
|
result.addError("Line " + (i) + ": Course not found: " + courseCode);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse Python list format: ['Std_ID_001', 'Std_ID_002', ...]
|
||||||
|
List<String> studentIds = parseStudentList(studentListStr);
|
||||||
|
|
||||||
|
for (String studentId : studentIds) {
|
||||||
|
Student student = dataManager.getStudent(studentId);
|
||||||
|
if (student == null) {
|
||||||
|
result.addError("Line " + (i + 1) + ": Student not found: " + studentId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataManager.addEnrollment(studentId, courseCode);
|
||||||
|
enrollmentCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
courseCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.setRecordCount(enrollmentCount);
|
||||||
|
if (!result.hasErrors()) {
|
||||||
|
result.setSuccess(true);
|
||||||
|
result.setMessage("Successfully imported " + enrollmentCount + " enrollments for " + courseCount + " courses");
|
||||||
|
} else {
|
||||||
|
result.setMessage("Imported " + enrollmentCount + " enrollments with errors");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
result.addError("Failed to read file: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a Python-style list of student IDs.
|
||||||
|
* Example: ['Std_ID_001', 'Std_ID_002', 'Std_ID_003']
|
||||||
|
*/
|
||||||
|
private List<String> parseStudentList(String pythonList) {
|
||||||
|
List<String> studentIds = new ArrayList<>();
|
||||||
|
|
||||||
|
// Remove brackets and split by comma
|
||||||
|
if (pythonList.startsWith("[") && pythonList.endsWith("]")) {
|
||||||
|
String content = pythonList.substring(1, pythonList.length() - 1);
|
||||||
|
|
||||||
|
// Split by comma and clean up each ID
|
||||||
|
String[] parts = content.split(",");
|
||||||
|
for (String part : parts) {
|
||||||
|
String cleanId = part.trim()
|
||||||
|
.replace("'", "") // Remove single quotes
|
||||||
|
.replace("\"", "") // Remove double quotes
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
if (!cleanId.isEmpty()) {
|
||||||
|
studentIds.add(cleanId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return studentIds;
|
||||||
|
}
|
||||||
|
}
|
||||||
134
src/main/java/org/example/se302/service/DataManager.java
Normal file
134
src/main/java/org/example/se302/service/DataManager.java
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
package org.example.se302.service;
|
||||||
|
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import org.example.se302.model.Classroom;
|
||||||
|
import org.example.se302.model.Course;
|
||||||
|
import org.example.se302.model.Student;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Singleton class that manages all application data.
|
||||||
|
* Provides ObservableList collections for UI binding.
|
||||||
|
*/
|
||||||
|
public class DataManager {
|
||||||
|
private static DataManager instance;
|
||||||
|
|
||||||
|
private ObservableList<Student> students;
|
||||||
|
private ObservableList<Course> courses;
|
||||||
|
private ObservableList<Classroom> classrooms;
|
||||||
|
|
||||||
|
private Map<String, Student> studentMap;
|
||||||
|
private Map<String, Course> courseMap;
|
||||||
|
private Map<String, Classroom> classroomMap;
|
||||||
|
|
||||||
|
private DataManager() {
|
||||||
|
students = FXCollections.observableArrayList();
|
||||||
|
courses = FXCollections.observableArrayList();
|
||||||
|
classrooms = FXCollections.observableArrayList();
|
||||||
|
|
||||||
|
studentMap = new HashMap<>();
|
||||||
|
courseMap = new HashMap<>();
|
||||||
|
classroomMap = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DataManager getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new DataManager();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Student operations
|
||||||
|
public ObservableList<Student> getStudents() {
|
||||||
|
return students;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addStudent(Student student) {
|
||||||
|
students.add(student);
|
||||||
|
studentMap.put(student.getStudentId(), student);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Student getStudent(String studentId) {
|
||||||
|
return studentMap.get(studentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearStudents() {
|
||||||
|
students.clear();
|
||||||
|
studentMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Course operations
|
||||||
|
public ObservableList<Course> getCourses() {
|
||||||
|
return courses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCourse(Course course) {
|
||||||
|
courses.add(course);
|
||||||
|
courseMap.put(course.getCourseCode(), course);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Course getCourse(String courseCode) {
|
||||||
|
return courseMap.get(courseCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearCourses() {
|
||||||
|
courses.clear();
|
||||||
|
courseMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Classroom operations
|
||||||
|
public ObservableList<Classroom> getClassrooms() {
|
||||||
|
return classrooms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addClassroom(Classroom classroom) {
|
||||||
|
classrooms.add(classroom);
|
||||||
|
classroomMap.put(classroom.getClassroomId(), classroom);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Classroom getClassroom(String classroomId) {
|
||||||
|
return classroomMap.get(classroomId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearClassrooms() {
|
||||||
|
classrooms.clear();
|
||||||
|
classroomMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility methods
|
||||||
|
public void clearAll() {
|
||||||
|
clearStudents();
|
||||||
|
clearCourses();
|
||||||
|
clearClassrooms();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTotalStudents() {
|
||||||
|
return students.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTotalCourses() {
|
||||||
|
return courses.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTotalClassrooms() {
|
||||||
|
return classrooms.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasData() {
|
||||||
|
return !students.isEmpty() || !courses.isEmpty() || !classrooms.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enrollment operations
|
||||||
|
public void addEnrollment(String studentId, String courseCode) {
|
||||||
|
Student student = getStudent(studentId);
|
||||||
|
Course course = getCourse(courseCode);
|
||||||
|
|
||||||
|
if (student != null && course != null) {
|
||||||
|
student.addCourse(courseCode);
|
||||||
|
course.addStudent(studentId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user