tmis 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/COPYING +674 -0
- data/README.md +44 -0
- data/Rakefile +64 -0
- data/bin/tmis +4 -0
- data/lib/tmis/engine/database.rb +58 -0
- data/lib/tmis/engine/export/timetable_exporter.rb +366 -0
- data/lib/tmis/engine/import/abstract_spreadsheet.rb +53 -0
- data/lib/tmis/engine/import/spreadsheet_roo.rb +136 -0
- data/lib/tmis/engine/import/timetable_manager.rb +110 -0
- data/lib/tmis/engine/import/timetable_reader.rb +79 -0
- data/lib/tmis/engine/mailer/mailer.rb +51 -0
- data/lib/tmis/engine/migrations/10_create_speciality_subjects.rb +17 -0
- data/lib/tmis/engine/migrations/11_create_emails.rb +10 -0
- data/lib/tmis/engine/migrations/12_add_indexes.rb +32 -0
- data/lib/tmis/engine/migrations/1_create_groups.rb +11 -0
- data/lib/tmis/engine/migrations/2_create_subgroups.rb +10 -0
- data/lib/tmis/engine/migrations/3_create_subjects.rb +11 -0
- data/lib/tmis/engine/migrations/4_create_cabinets.rb +12 -0
- data/lib/tmis/engine/migrations/5_create_lecturers.rb +14 -0
- data/lib/tmis/engine/migrations/6_create_studies.rb +15 -0
- data/lib/tmis/engine/migrations/7_create_courses.rb +9 -0
- data/lib/tmis/engine/migrations/8_create_specialities.rb +9 -0
- data/lib/tmis/engine/migrations/9_create_semesters.rb +10 -0
- data/lib/tmis/engine/models/cabinet.rb +18 -0
- data/lib/tmis/engine/models/course.rb +11 -0
- data/lib/tmis/engine/models/email.rb +19 -0
- data/lib/tmis/engine/models/group.rb +31 -0
- data/lib/tmis/engine/models/lecturer.rb +45 -0
- data/lib/tmis/engine/models/semester.rb +4 -0
- data/lib/tmis/engine/models/speciality.rb +3 -0
- data/lib/tmis/engine/models/speciality_subject.rb +6 -0
- data/lib/tmis/engine/models/study.rb +56 -0
- data/lib/tmis/engine/models/subgroup.rb +21 -0
- data/lib/tmis/engine/models/subject.rb +19 -0
- data/lib/tmis/engine/verificator.rb +96 -0
- data/lib/tmis/interface/forms/about.rb +24 -0
- data/lib/tmis/interface/forms/console.rb +28 -0
- data/lib/tmis/interface/forms/debug_console.rb +32 -0
- data/lib/tmis/interface/forms/edit_study.rb +110 -0
- data/lib/tmis/interface/forms/expand_changes.rb +128 -0
- data/lib/tmis/interface/forms/export_general_timetable.rb +68 -0
- data/lib/tmis/interface/forms/export_group_timetable.rb +158 -0
- data/lib/tmis/interface/forms/export_lecturer_timetable.rb +171 -0
- data/lib/tmis/interface/forms/find.rb +71 -0
- data/lib/tmis/interface/forms/import.rb +36 -0
- data/lib/tmis/interface/forms/settings.rb +125 -0
- data/lib/tmis/interface/forms/ui_about.rb +88 -0
- data/lib/tmis/interface/forms/ui_console.rb +68 -0
- data/lib/tmis/interface/forms/ui_debug_console.rb +82 -0
- data/lib/tmis/interface/forms/ui_edit_study.rb +202 -0
- data/lib/tmis/interface/forms/ui_expand_changes.rb +134 -0
- data/lib/tmis/interface/forms/ui_export_general_timetable.rb +142 -0
- data/lib/tmis/interface/forms/ui_export_group_timetable.rb +160 -0
- data/lib/tmis/interface/forms/ui_export_lecturer_timetable.rb +160 -0
- data/lib/tmis/interface/forms/ui_find.rb +77 -0
- data/lib/tmis/interface/forms/ui_import.rb +134 -0
- data/lib/tmis/interface/forms/ui_settings.rb +417 -0
- data/lib/tmis/interface/mainwindow.rb +933 -0
- data/lib/tmis/interface/models/cabinet_table_model.rb +133 -0
- data/lib/tmis/interface/models/course_table_model.rb +87 -0
- data/lib/tmis/interface/models/group_table_model.rb +190 -0
- data/lib/tmis/interface/models/lecturer_table_model.rb +111 -0
- data/lib/tmis/interface/models/semester_table_model.rb +137 -0
- data/lib/tmis/interface/models/speciality_subject_table_model.rb +288 -0
- data/lib/tmis/interface/models/speciality_table_model.rb +87 -0
- data/lib/tmis/interface/models/study_table_model.rb +323 -0
- data/lib/tmis/interface/models/subgroup_table_model.rb +136 -0
- data/lib/tmis/interface/models/subject_table_model.rb +90 -0
- data/lib/tmis/interface/ui_mainwindow.rb +928 -0
- data/lib/tmis.rb +45 -0
- data/spec/config.rb +49 -0
- data/spec/database_spec.rb +18 -0
- data/spec/export/timetable_exporter_mocks.rb +20 -0
- data/spec/export/timetable_exporter_spec.rb +34 -0
- data/spec/factories/factories.rb +65 -0
- data/spec/import/test_data/raspisanie_2013.csv +104 -0
- data/spec/import/timetable_importer_mocks.rb +6 -0
- data/spec/import/timetable_manager_spec.rb +16 -0
- data/spec/import/timetable_reader_spec.rb +111 -0
- data/spec/import/timetable_roo_spec.rb +48 -0
- data/spec/mailer/mailer_spec.rb +37 -0
- data/spec/mainwindow_spec.rb +18 -0
- data/spec/models/cabinet_spec.rb +33 -0
- data/spec/models/course_spec.rb +26 -0
- data/spec/models/group_spec.rb +33 -0
- data/spec/models/lecturer_spec.rb +38 -0
- data/spec/models/semester_spec.rb +26 -0
- data/spec/models/speciality_spec.rb +26 -0
- data/spec/models/speciality_subject_spec.rb +9 -0
- data/spec/models/study_spec.rb +9 -0
- data/spec/models/subgroup_spec.rb +26 -0
- data/spec/models/subject_spec.rb +39 -0
- metadata +290 -0
@@ -0,0 +1,133 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~
|
3
|
+
require_relative '../../engine/models/cabinet'
|
4
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~
|
5
|
+
class CabinetTableModel < Qt::AbstractTableModel
|
6
|
+
|
7
|
+
def initialize(cabinets, parent)
|
8
|
+
super()
|
9
|
+
@cabinets = cabinets
|
10
|
+
@view = parent
|
11
|
+
@view.setItemDelegateForColumn(1, RadioButtonDelegate.new(self))
|
12
|
+
end
|
13
|
+
|
14
|
+
def refresh
|
15
|
+
@cabinets = Cabinet.all
|
16
|
+
emit layoutChanged()
|
17
|
+
end
|
18
|
+
|
19
|
+
def rowCount(parent)
|
20
|
+
@cabinets.size
|
21
|
+
end
|
22
|
+
|
23
|
+
def columnCount(parent)
|
24
|
+
2
|
25
|
+
end
|
26
|
+
|
27
|
+
def data(index, role = Qt::DisplayRole)
|
28
|
+
cabinet = @cabinets[index.row]
|
29
|
+
default = Qt::Variant.new
|
30
|
+
case role
|
31
|
+
when Qt::DisplayRole
|
32
|
+
case index.column
|
33
|
+
when 0
|
34
|
+
cabinet.title.to_v
|
35
|
+
when 1
|
36
|
+
cabinet.with_computers.to_s.to_v
|
37
|
+
else
|
38
|
+
raise "invalid column #{index.column}"
|
39
|
+
end
|
40
|
+
when Qt::EditRole
|
41
|
+
case index.column
|
42
|
+
when 0
|
43
|
+
cabinet.title.to_v
|
44
|
+
when 1
|
45
|
+
cabinet.with_computers.to_v
|
46
|
+
else
|
47
|
+
raise "invalid column #{index.column}"
|
48
|
+
end
|
49
|
+
else
|
50
|
+
default
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def headerData(section, orientation, role = Qt::DisplayRole)
|
55
|
+
invalid = Qt::Variant.new
|
56
|
+
return invalid unless role == Qt::DisplayRole
|
57
|
+
v = case orientation
|
58
|
+
when Qt::Horizontal
|
59
|
+
%w(Название Компьютерный)[section]
|
60
|
+
else
|
61
|
+
''
|
62
|
+
end
|
63
|
+
Qt::Variant.new(v)
|
64
|
+
end
|
65
|
+
|
66
|
+
def flags(index)
|
67
|
+
Qt::ItemIsEditable | super(index)
|
68
|
+
end
|
69
|
+
|
70
|
+
def setData(index, variant, role = Qt::EditRole)
|
71
|
+
if index.valid? and role == Qt::EditRole
|
72
|
+
cabinet = @cabinets[index.row]
|
73
|
+
case index.column
|
74
|
+
when 0
|
75
|
+
cabinet.title = variant.toString.force_encoding('UTF-8')
|
76
|
+
when 1
|
77
|
+
cabinet.with_computers = variant.toBool
|
78
|
+
else
|
79
|
+
raise "invalid column #{index.column}"
|
80
|
+
end
|
81
|
+
cabinet.save
|
82
|
+
emit dataChanged(index, index)
|
83
|
+
true
|
84
|
+
else
|
85
|
+
false
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def insert_new
|
90
|
+
@cabinets.prepend(Cabinet.new)
|
91
|
+
emit layoutChanged()
|
92
|
+
end
|
93
|
+
|
94
|
+
def remove_current
|
95
|
+
if @view.currentIndex.valid?
|
96
|
+
cabinet = @cabinets[@view.currentIndex.row]
|
97
|
+
unless cabinet.stub
|
98
|
+
cabinet.try(:destroy)
|
99
|
+
@cabinets.delete_at(@view.currentIndex.row)
|
100
|
+
emit layoutChanged()
|
101
|
+
@view.currentIndex = createIndex(-1, -1)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
class RadioButtonDelegate < Qt::ItemDelegate
|
109
|
+
|
110
|
+
def initialize(parent)
|
111
|
+
super
|
112
|
+
end
|
113
|
+
|
114
|
+
def createEditor(parent, option, index)
|
115
|
+
Qt::CheckBox.new(parent)
|
116
|
+
end
|
117
|
+
|
118
|
+
def setEditorData(editor, index)
|
119
|
+
value = index.data.toBool #index.model.data(index, Qt::EditRole)
|
120
|
+
button = editor
|
121
|
+
button.checked = value # button.setValue(value)
|
122
|
+
end
|
123
|
+
|
124
|
+
def setModelData(editor, model, index)
|
125
|
+
button = editor
|
126
|
+
value = button.isChecked # button.value
|
127
|
+
model.setData(index, value.to_v, Qt::EditRole)
|
128
|
+
end
|
129
|
+
|
130
|
+
def updateEditorGeometry(editor, option, index)
|
131
|
+
editor.setGeometry(option.rect)
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~
|
3
|
+
require_relative '../../engine/models/course'
|
4
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~
|
5
|
+
class CourseTableModel < Qt::AbstractTableModel
|
6
|
+
|
7
|
+
def initialize(courses, parent)
|
8
|
+
super()
|
9
|
+
@courses = courses
|
10
|
+
@view = parent
|
11
|
+
end
|
12
|
+
|
13
|
+
def refresh
|
14
|
+
@courses = Course.all
|
15
|
+
emit layoutChanged()
|
16
|
+
end
|
17
|
+
|
18
|
+
def rowCount(parent)
|
19
|
+
@courses.size
|
20
|
+
end
|
21
|
+
|
22
|
+
def columnCount(parent)
|
23
|
+
1
|
24
|
+
end
|
25
|
+
|
26
|
+
def data(index, role = Qt::DisplayRole)
|
27
|
+
invalid = Qt::Variant.new
|
28
|
+
return invalid unless role == Qt::DisplayRole or role == Qt::EditRole
|
29
|
+
course = @courses[index.row]
|
30
|
+
return invalid if course.nil?
|
31
|
+
v = case index.column
|
32
|
+
when 0
|
33
|
+
course.number
|
34
|
+
else
|
35
|
+
raise "invalid column #{index.column}"
|
36
|
+
end || ''
|
37
|
+
Qt::Variant.new(v)
|
38
|
+
end
|
39
|
+
|
40
|
+
def headerData(section, orientation, role = Qt::DisplayRole)
|
41
|
+
invalid = Qt::Variant.new
|
42
|
+
return invalid unless role == Qt::DisplayRole
|
43
|
+
v = case orientation
|
44
|
+
when Qt::Horizontal
|
45
|
+
%w(Номер)[section]
|
46
|
+
else
|
47
|
+
''
|
48
|
+
end
|
49
|
+
Qt::Variant.new(v)
|
50
|
+
end
|
51
|
+
|
52
|
+
def flags(index)
|
53
|
+
Qt::ItemIsEditable | super(index)
|
54
|
+
end
|
55
|
+
|
56
|
+
def setData(index, variant, role = Qt::EditRole)
|
57
|
+
if index.valid? and role == Qt::EditRole
|
58
|
+
course = @courses[index.row]
|
59
|
+
case index.column
|
60
|
+
when 0
|
61
|
+
course.number = variant.toInt
|
62
|
+
else
|
63
|
+
raise "invalid column #{index.column}"
|
64
|
+
end
|
65
|
+
course.save
|
66
|
+
emit dataChanged(index, index)
|
67
|
+
true
|
68
|
+
else
|
69
|
+
false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def insert_new
|
74
|
+
@courses.prepend(Course.new)
|
75
|
+
emit layoutChanged()
|
76
|
+
end
|
77
|
+
|
78
|
+
def remove_current
|
79
|
+
if @view.currentIndex.valid?
|
80
|
+
@courses[@view.currentIndex.row].try(:destroy)
|
81
|
+
@courses.delete_at(@view.currentIndex.row)
|
82
|
+
emit layoutChanged()
|
83
|
+
@view.currentIndex = createIndex(-1, -1)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~
|
3
|
+
require_relative '../../engine/models/group'
|
4
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~
|
5
|
+
class GroupTableModel < Qt::AbstractTableModel
|
6
|
+
|
7
|
+
def initialize(groups, parent)
|
8
|
+
super()
|
9
|
+
@groups = groups
|
10
|
+
@groups.size
|
11
|
+
@view = parent
|
12
|
+
@SpecialityComboBoxDelegate = SpecialityComboBoxDelegate.new(self)
|
13
|
+
@CourseComboBoxDelegate = CourseComboBoxDelegate.new(self)
|
14
|
+
@view.setItemDelegateForColumn(1, @SpecialityComboBoxDelegate)
|
15
|
+
@view.setItemDelegateForColumn(2, @CourseComboBoxDelegate)
|
16
|
+
end
|
17
|
+
|
18
|
+
def refresh
|
19
|
+
@groups = Group.all
|
20
|
+
@SpecialityComboBoxDelegate.setup
|
21
|
+
@CourseComboBoxDelegate.setup
|
22
|
+
emit layoutChanged()
|
23
|
+
end
|
24
|
+
|
25
|
+
def rowCount(parent)
|
26
|
+
@groups.size
|
27
|
+
end
|
28
|
+
|
29
|
+
def columnCount(parent)
|
30
|
+
4
|
31
|
+
end
|
32
|
+
|
33
|
+
def data(index, role = Qt::DisplayRole)
|
34
|
+
group = @groups[index.row]
|
35
|
+
default = Qt::Variant.new
|
36
|
+
case role
|
37
|
+
when Qt::DisplayRole
|
38
|
+
case index.column
|
39
|
+
when 0
|
40
|
+
group.title
|
41
|
+
when 1
|
42
|
+
group.speciality.try(:title)
|
43
|
+
when 2
|
44
|
+
group.course.try(:number)
|
45
|
+
when 3
|
46
|
+
group.emails.map(&:email).join(', ')
|
47
|
+
else
|
48
|
+
raise "invalid column #{index.column}"
|
49
|
+
end.try(:to_v) || default
|
50
|
+
when Qt::EditRole
|
51
|
+
case index.column
|
52
|
+
when 0
|
53
|
+
group.title
|
54
|
+
when 1
|
55
|
+
group.speciality_id
|
56
|
+
when 2
|
57
|
+
group.course_id
|
58
|
+
when 3
|
59
|
+
group.emails.map(&:email).join(', ')
|
60
|
+
else
|
61
|
+
raise "invalid column #{index.column}"
|
62
|
+
end.try(:to_v) || default
|
63
|
+
else
|
64
|
+
default
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def headerData(section, orientation, role = Qt::DisplayRole)
|
69
|
+
invalid = Qt::Variant.new
|
70
|
+
return invalid unless role == Qt::DisplayRole
|
71
|
+
v = case orientation
|
72
|
+
when Qt::Horizontal
|
73
|
+
%w(Название Специальность Курс Email)[section]
|
74
|
+
else
|
75
|
+
''
|
76
|
+
end
|
77
|
+
Qt::Variant.new(v)
|
78
|
+
end
|
79
|
+
|
80
|
+
def flags(index)
|
81
|
+
Qt::ItemIsEditable | super(index)
|
82
|
+
end
|
83
|
+
|
84
|
+
def setData(index, variant, role = Qt::EditRole)
|
85
|
+
if index.valid? and role == Qt::EditRole
|
86
|
+
group = @groups[index.row]
|
87
|
+
case index.column
|
88
|
+
when 0
|
89
|
+
group.title = variant.toString.force_encoding('UTF-8')
|
90
|
+
when 1
|
91
|
+
group.speciality_id = variant.toInt
|
92
|
+
when 2
|
93
|
+
group.course_id = variant.toInt
|
94
|
+
when 3
|
95
|
+
emails = variant.toString.force_encoding('UTF-8').split(/,\s*/)
|
96
|
+
group.emails.destroy_all
|
97
|
+
emails.each do |email|
|
98
|
+
group.emails.create(email: email)
|
99
|
+
end
|
100
|
+
else
|
101
|
+
raise "invalid column #{index.column}"
|
102
|
+
end
|
103
|
+
group.save
|
104
|
+
p group
|
105
|
+
emit dataChanged(index, index)
|
106
|
+
true
|
107
|
+
else
|
108
|
+
false
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def insert_new
|
113
|
+
new_group = Group.new
|
114
|
+
@groups.prepend(new_group)
|
115
|
+
(1..2).map{ |i| Subgroup.create(group: new_group, number: i) }
|
116
|
+
emit layoutChanged()
|
117
|
+
end
|
118
|
+
|
119
|
+
def remove_current
|
120
|
+
if @view.currentIndex.valid?
|
121
|
+
@groups[@view.currentIndex.row].try(:destroy)
|
122
|
+
@groups.delete_at(@view.currentIndex.row)
|
123
|
+
emit layoutChanged()
|
124
|
+
@view.currentIndex = createIndex(-1, -1)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
class SpecialityComboBoxDelegate < Qt::ItemDelegate
|
131
|
+
def initialize(parent)
|
132
|
+
super
|
133
|
+
setup
|
134
|
+
end
|
135
|
+
|
136
|
+
def setup
|
137
|
+
@specialities = Speciality.all.sort_by(&:title)
|
138
|
+
end
|
139
|
+
|
140
|
+
def createEditor(parent, option, index)
|
141
|
+
editor = Qt::ComboBox.new(parent)
|
142
|
+
@specialities.each{ |x| editor.addItem(x.title.to_s, x.id.to_v) }
|
143
|
+
editor
|
144
|
+
end
|
145
|
+
|
146
|
+
def setEditorData(editor, index)
|
147
|
+
value = index.data
|
148
|
+
editor.setCurrentIndex(editor.findData(value))
|
149
|
+
end
|
150
|
+
|
151
|
+
def setModelData(editor, model, index)
|
152
|
+
value = editor.itemData(editor.currentIndex)
|
153
|
+
model.setData(index, value, Qt::EditRole)
|
154
|
+
end
|
155
|
+
|
156
|
+
def updateEditorGeometry(editor, option, index)
|
157
|
+
editor.setGeometry(option.rect)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class CourseComboBoxDelegate < Qt::ItemDelegate
|
162
|
+
def initialize(parent)
|
163
|
+
super
|
164
|
+
setup
|
165
|
+
end
|
166
|
+
|
167
|
+
def setup
|
168
|
+
@courses = Course.all.sort_by(&:number)
|
169
|
+
end
|
170
|
+
|
171
|
+
def createEditor(parent, option, index)
|
172
|
+
editor = Qt::ComboBox.new(parent)
|
173
|
+
@courses.each{ |x| editor.addItem(x.number.to_s, x.id.to_v) }
|
174
|
+
editor
|
175
|
+
end
|
176
|
+
|
177
|
+
def setEditorData(editor, index)
|
178
|
+
value = index.data
|
179
|
+
editor.setCurrentIndex(editor.findData(value))
|
180
|
+
end
|
181
|
+
|
182
|
+
def setModelData(editor, model, index)
|
183
|
+
value = editor.itemData(editor.currentIndex)
|
184
|
+
model.setData(index, value, Qt::EditRole)
|
185
|
+
end
|
186
|
+
|
187
|
+
def updateEditorGeometry(editor, option, index)
|
188
|
+
editor.setGeometry(option.rect)
|
189
|
+
end
|
190
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~
|
3
|
+
require_relative '../../engine/models/lecturer'
|
4
|
+
require_relative '../../engine/models/email'
|
5
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~
|
6
|
+
class LecturerTableModel < Qt::AbstractTableModel
|
7
|
+
|
8
|
+
def initialize(lecturers, parent)
|
9
|
+
super()
|
10
|
+
@lecturers = lecturers
|
11
|
+
@view = parent
|
12
|
+
end
|
13
|
+
|
14
|
+
def refresh
|
15
|
+
@lecturers = Lecturer.all
|
16
|
+
emit layoutChanged()
|
17
|
+
end
|
18
|
+
|
19
|
+
def rowCount(parent)
|
20
|
+
@lecturers.size
|
21
|
+
end
|
22
|
+
|
23
|
+
def columnCount(parent)
|
24
|
+
5
|
25
|
+
end
|
26
|
+
|
27
|
+
def data(index, role = Qt::DisplayRole)
|
28
|
+
invalid = Qt::Variant.new
|
29
|
+
return invalid unless role == Qt::DisplayRole or role == Qt::EditRole
|
30
|
+
lecturer = @lecturers[index.row]
|
31
|
+
return invalid if lecturer.nil?
|
32
|
+
v = case index.column
|
33
|
+
when 0
|
34
|
+
lecturer.surname
|
35
|
+
when 1
|
36
|
+
lecturer.name
|
37
|
+
when 2
|
38
|
+
lecturer.patronymic
|
39
|
+
when 3
|
40
|
+
lecturer.emails.map(&:email).join(', ')
|
41
|
+
when 4
|
42
|
+
lecturer.preferred_days
|
43
|
+
else
|
44
|
+
raise "invalid column #{index.column}"
|
45
|
+
end || ''
|
46
|
+
Qt::Variant.new(v)
|
47
|
+
end
|
48
|
+
|
49
|
+
def headerData(section, orientation, role = Qt::DisplayRole)
|
50
|
+
invalid = Qt::Variant.new
|
51
|
+
return invalid unless role == Qt::DisplayRole
|
52
|
+
v = case orientation
|
53
|
+
when Qt::Horizontal
|
54
|
+
['Фамилия', 'Имя', 'Отчество', 'Email', 'Предпочитаемые дни'][section]
|
55
|
+
else
|
56
|
+
''
|
57
|
+
end
|
58
|
+
Qt::Variant.new(v)
|
59
|
+
end
|
60
|
+
|
61
|
+
def flags(index)
|
62
|
+
Qt::ItemIsEditable | super(index)
|
63
|
+
end
|
64
|
+
|
65
|
+
def setData(index, variant, role = Qt::EditRole)
|
66
|
+
if index.valid? and role == Qt::EditRole
|
67
|
+
lecturer = @lecturers[index.row]
|
68
|
+
case index.column
|
69
|
+
when 0
|
70
|
+
lecturer.surname = variant.toString.force_encoding('UTF-8')
|
71
|
+
when 1
|
72
|
+
lecturer.name = variant.toString.force_encoding('UTF-8')
|
73
|
+
when 2
|
74
|
+
lecturer.patronymic = variant.toString.force_encoding('UTF-8')
|
75
|
+
when 3
|
76
|
+
emails = variant.toString.force_encoding('UTF-8').split(/,\s*/)
|
77
|
+
lecturer.emails.destroy_all
|
78
|
+
emails.each do |email|
|
79
|
+
lecturer.emails.create(email: email)
|
80
|
+
end
|
81
|
+
when 4
|
82
|
+
lecturer.preferred_days = variant.toString.force_encoding('UTF-8').split(/,\s*/).select{|x| x[/^[1-7]$/]}.uniq.join(', ')
|
83
|
+
else
|
84
|
+
raise "invalid column #{index.column}"
|
85
|
+
end
|
86
|
+
lecturer.save
|
87
|
+
emit dataChanged(index, index)
|
88
|
+
true
|
89
|
+
else
|
90
|
+
false
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def insert_new
|
95
|
+
@lecturers.prepend(Lecturer.new)
|
96
|
+
emit layoutChanged()
|
97
|
+
end
|
98
|
+
|
99
|
+
def remove_current
|
100
|
+
if @view.currentIndex.valid?
|
101
|
+
lecturer = @lecturers[@view.currentIndex.row]
|
102
|
+
unless lecturer.stub
|
103
|
+
lecturer.try(:destroy)
|
104
|
+
@lecturers.delete_at(@view.currentIndex.row)
|
105
|
+
emit layoutChanged()
|
106
|
+
@view.currentIndex = createIndex(-1, -1)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~
|
3
|
+
require_relative '../../engine/models/semester'
|
4
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~
|
5
|
+
class SemesterTableModel < Qt::AbstractTableModel
|
6
|
+
|
7
|
+
def initialize(semesters, parent)
|
8
|
+
super()
|
9
|
+
@semesters = semesters
|
10
|
+
@view = parent
|
11
|
+
@CourseComboBoxDelegate = CourseComboBoxDelegate.new(self)
|
12
|
+
@view.setItemDelegateForColumn(1, @CourseComboBoxDelegate)
|
13
|
+
end
|
14
|
+
|
15
|
+
def refresh
|
16
|
+
@semesters = Semester.all
|
17
|
+
@CourseComboBoxDelegate.setup
|
18
|
+
emit layoutChanged()
|
19
|
+
end
|
20
|
+
|
21
|
+
def rowCount(parent)
|
22
|
+
@semesters.size
|
23
|
+
end
|
24
|
+
|
25
|
+
def columnCount(parent)
|
26
|
+
2
|
27
|
+
end
|
28
|
+
|
29
|
+
def data(index, role = Qt::DisplayRole)
|
30
|
+
semester = @semesters[index.row]
|
31
|
+
default = Qt::Variant.new
|
32
|
+
case role
|
33
|
+
when Qt::DisplayRole
|
34
|
+
case index.column
|
35
|
+
when 0
|
36
|
+
semester.title
|
37
|
+
when 1
|
38
|
+
semester.course.try(:number)
|
39
|
+
else
|
40
|
+
raise "invalid column #{index.column}"
|
41
|
+
end.try(:to_v) || default
|
42
|
+
when Qt::EditRole
|
43
|
+
case index.column
|
44
|
+
when 0
|
45
|
+
semester.title
|
46
|
+
when 1
|
47
|
+
semester.course_id
|
48
|
+
else
|
49
|
+
raise "invalid column #{index.column}"
|
50
|
+
end.try(:to_v) || default
|
51
|
+
else
|
52
|
+
default
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def headerData(section, orientation, role = Qt::DisplayRole)
|
57
|
+
invalid = Qt::Variant.new
|
58
|
+
return invalid unless role == Qt::DisplayRole
|
59
|
+
v = case orientation
|
60
|
+
when Qt::Horizontal
|
61
|
+
%w(Название Курс)[section]
|
62
|
+
else
|
63
|
+
''
|
64
|
+
end
|
65
|
+
Qt::Variant.new(v)
|
66
|
+
end
|
67
|
+
|
68
|
+
def flags(index)
|
69
|
+
Qt::ItemIsEditable | super(index)
|
70
|
+
end
|
71
|
+
|
72
|
+
def setData(index, variant, role = Qt::EditRole)
|
73
|
+
if index.valid? and role == Qt::EditRole
|
74
|
+
semester = @semesters[index.row]
|
75
|
+
case index.column
|
76
|
+
when 0
|
77
|
+
semester.title = variant.toString.force_encoding('UTF-8')
|
78
|
+
when 1
|
79
|
+
semester.course_id = variant.toInt
|
80
|
+
else
|
81
|
+
raise "invalid column #{index.column}"
|
82
|
+
end
|
83
|
+
semester.save
|
84
|
+
p semester
|
85
|
+
emit dataChanged(index, index)
|
86
|
+
true
|
87
|
+
else
|
88
|
+
false
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def insert_new
|
93
|
+
@semesters.prepend(Semester.new)
|
94
|
+
emit layoutChanged()
|
95
|
+
end
|
96
|
+
|
97
|
+
def remove_current
|
98
|
+
if @view.currentIndex.valid?
|
99
|
+
@semesters[@view.currentIndex.row].try(:destroy)
|
100
|
+
@semesters.delete_at(@view.currentIndex.row)
|
101
|
+
emit layoutChanged()
|
102
|
+
@view.currentIndex = createIndex(-1, -1)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
class CourseComboBoxDelegate < Qt::ItemDelegate
|
109
|
+
def initialize(parent)
|
110
|
+
super
|
111
|
+
setup
|
112
|
+
end
|
113
|
+
|
114
|
+
def setup
|
115
|
+
@courses = Course.all.sort_by(&:number)
|
116
|
+
end
|
117
|
+
|
118
|
+
def createEditor(parent, option, index)
|
119
|
+
editor = Qt::ComboBox.new(parent)
|
120
|
+
@courses.each{ |x| editor.addItem(x.number.to_s, x.id.to_v) }
|
121
|
+
editor
|
122
|
+
end
|
123
|
+
|
124
|
+
def setEditorData(editor, index)
|
125
|
+
value = index.data
|
126
|
+
editor.setCurrentIndex(editor.findData(value))
|
127
|
+
end
|
128
|
+
|
129
|
+
def setModelData(editor, model, index)
|
130
|
+
value = editor.itemData(editor.currentIndex)
|
131
|
+
model.setData(index, value, Qt::EditRole)
|
132
|
+
end
|
133
|
+
|
134
|
+
def updateEditorGeometry(editor, option, index)
|
135
|
+
editor.setGeometry(option.rect)
|
136
|
+
end
|
137
|
+
end
|