tmis 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +674 -0
  3. data/README.md +44 -0
  4. data/Rakefile +64 -0
  5. data/bin/tmis +4 -0
  6. data/lib/tmis/engine/database.rb +58 -0
  7. data/lib/tmis/engine/export/timetable_exporter.rb +366 -0
  8. data/lib/tmis/engine/import/abstract_spreadsheet.rb +53 -0
  9. data/lib/tmis/engine/import/spreadsheet_roo.rb +136 -0
  10. data/lib/tmis/engine/import/timetable_manager.rb +110 -0
  11. data/lib/tmis/engine/import/timetable_reader.rb +79 -0
  12. data/lib/tmis/engine/mailer/mailer.rb +51 -0
  13. data/lib/tmis/engine/migrations/10_create_speciality_subjects.rb +17 -0
  14. data/lib/tmis/engine/migrations/11_create_emails.rb +10 -0
  15. data/lib/tmis/engine/migrations/12_add_indexes.rb +32 -0
  16. data/lib/tmis/engine/migrations/1_create_groups.rb +11 -0
  17. data/lib/tmis/engine/migrations/2_create_subgroups.rb +10 -0
  18. data/lib/tmis/engine/migrations/3_create_subjects.rb +11 -0
  19. data/lib/tmis/engine/migrations/4_create_cabinets.rb +12 -0
  20. data/lib/tmis/engine/migrations/5_create_lecturers.rb +14 -0
  21. data/lib/tmis/engine/migrations/6_create_studies.rb +15 -0
  22. data/lib/tmis/engine/migrations/7_create_courses.rb +9 -0
  23. data/lib/tmis/engine/migrations/8_create_specialities.rb +9 -0
  24. data/lib/tmis/engine/migrations/9_create_semesters.rb +10 -0
  25. data/lib/tmis/engine/models/cabinet.rb +18 -0
  26. data/lib/tmis/engine/models/course.rb +11 -0
  27. data/lib/tmis/engine/models/email.rb +19 -0
  28. data/lib/tmis/engine/models/group.rb +31 -0
  29. data/lib/tmis/engine/models/lecturer.rb +45 -0
  30. data/lib/tmis/engine/models/semester.rb +4 -0
  31. data/lib/tmis/engine/models/speciality.rb +3 -0
  32. data/lib/tmis/engine/models/speciality_subject.rb +6 -0
  33. data/lib/tmis/engine/models/study.rb +56 -0
  34. data/lib/tmis/engine/models/subgroup.rb +21 -0
  35. data/lib/tmis/engine/models/subject.rb +19 -0
  36. data/lib/tmis/engine/verificator.rb +96 -0
  37. data/lib/tmis/interface/forms/about.rb +24 -0
  38. data/lib/tmis/interface/forms/console.rb +28 -0
  39. data/lib/tmis/interface/forms/debug_console.rb +32 -0
  40. data/lib/tmis/interface/forms/edit_study.rb +110 -0
  41. data/lib/tmis/interface/forms/expand_changes.rb +128 -0
  42. data/lib/tmis/interface/forms/export_general_timetable.rb +68 -0
  43. data/lib/tmis/interface/forms/export_group_timetable.rb +158 -0
  44. data/lib/tmis/interface/forms/export_lecturer_timetable.rb +171 -0
  45. data/lib/tmis/interface/forms/find.rb +71 -0
  46. data/lib/tmis/interface/forms/import.rb +36 -0
  47. data/lib/tmis/interface/forms/settings.rb +125 -0
  48. data/lib/tmis/interface/forms/ui_about.rb +88 -0
  49. data/lib/tmis/interface/forms/ui_console.rb +68 -0
  50. data/lib/tmis/interface/forms/ui_debug_console.rb +82 -0
  51. data/lib/tmis/interface/forms/ui_edit_study.rb +202 -0
  52. data/lib/tmis/interface/forms/ui_expand_changes.rb +134 -0
  53. data/lib/tmis/interface/forms/ui_export_general_timetable.rb +142 -0
  54. data/lib/tmis/interface/forms/ui_export_group_timetable.rb +160 -0
  55. data/lib/tmis/interface/forms/ui_export_lecturer_timetable.rb +160 -0
  56. data/lib/tmis/interface/forms/ui_find.rb +77 -0
  57. data/lib/tmis/interface/forms/ui_import.rb +134 -0
  58. data/lib/tmis/interface/forms/ui_settings.rb +417 -0
  59. data/lib/tmis/interface/mainwindow.rb +933 -0
  60. data/lib/tmis/interface/models/cabinet_table_model.rb +133 -0
  61. data/lib/tmis/interface/models/course_table_model.rb +87 -0
  62. data/lib/tmis/interface/models/group_table_model.rb +190 -0
  63. data/lib/tmis/interface/models/lecturer_table_model.rb +111 -0
  64. data/lib/tmis/interface/models/semester_table_model.rb +137 -0
  65. data/lib/tmis/interface/models/speciality_subject_table_model.rb +288 -0
  66. data/lib/tmis/interface/models/speciality_table_model.rb +87 -0
  67. data/lib/tmis/interface/models/study_table_model.rb +323 -0
  68. data/lib/tmis/interface/models/subgroup_table_model.rb +136 -0
  69. data/lib/tmis/interface/models/subject_table_model.rb +90 -0
  70. data/lib/tmis/interface/ui_mainwindow.rb +928 -0
  71. data/lib/tmis.rb +45 -0
  72. data/spec/config.rb +49 -0
  73. data/spec/database_spec.rb +18 -0
  74. data/spec/export/timetable_exporter_mocks.rb +20 -0
  75. data/spec/export/timetable_exporter_spec.rb +34 -0
  76. data/spec/factories/factories.rb +65 -0
  77. data/spec/import/test_data/raspisanie_2013.csv +104 -0
  78. data/spec/import/timetable_importer_mocks.rb +6 -0
  79. data/spec/import/timetable_manager_spec.rb +16 -0
  80. data/spec/import/timetable_reader_spec.rb +111 -0
  81. data/spec/import/timetable_roo_spec.rb +48 -0
  82. data/spec/mailer/mailer_spec.rb +37 -0
  83. data/spec/mainwindow_spec.rb +18 -0
  84. data/spec/models/cabinet_spec.rb +33 -0
  85. data/spec/models/course_spec.rb +26 -0
  86. data/spec/models/group_spec.rb +33 -0
  87. data/spec/models/lecturer_spec.rb +38 -0
  88. data/spec/models/semester_spec.rb +26 -0
  89. data/spec/models/speciality_spec.rb +26 -0
  90. data/spec/models/speciality_subject_spec.rb +9 -0
  91. data/spec/models/study_spec.rb +9 -0
  92. data/spec/models/subgroup_spec.rb +26 -0
  93. data/spec/models/subject_spec.rb +39 -0
  94. 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