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.fxml;
|
||||
|
||||
|
||||
opens org.example.se302 to javafx.fxml;
|
||||
// Export all packages
|
||||
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 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