tmis 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,288 @@
1
+ # encoding: UTF-8
2
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~
3
+ require_relative '../../engine/models/speciality_subject'
4
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~
5
+ class SpecialitySubjectTableModel < Qt::AbstractTableModel
6
+
7
+ def initialize(speciality_subjects, parent)
8
+ super()
9
+ @speciality_subjects = speciality_subjects
10
+ @view = parent
11
+ @lecturerComboBoxDelegate = LecturerComboBoxDelegate.new(self)
12
+ @subjectComboBoxDelegate = SubjectComboBoxDelegate.new(self)
13
+ @semesterComboBoxDelegate = SemesterComboBoxDelegate.new(self)
14
+ @specialityComboBoxDelegate = SpecialityComboBoxDelegate.new(self)
15
+ @facultativeRadioButtonDelegate = RadioButtonDelegate.new(self)
16
+ @view.setItemDelegateForColumn(0, @lecturerComboBoxDelegate)
17
+ @view.setItemDelegateForColumn(1, @subjectComboBoxDelegate)
18
+ @view.setItemDelegateForColumn(2, @semesterComboBoxDelegate)
19
+ @view.setItemDelegateForColumn(3, @specialityComboBoxDelegate)
20
+ @view.setItemDelegateForColumn(9, @facultativeRadioButtonDelegate)
21
+ end
22
+
23
+ def refresh
24
+ @speciality_subjects = SpecialitySubject.all
25
+ @lecturerComboBoxDelegate.setup
26
+ @subjectComboBoxDelegate.setup
27
+ @semesterComboBoxDelegate.setup
28
+ @specialityComboBoxDelegate.setup
29
+ emit layoutChanged()
30
+ end
31
+
32
+ def rowCount(parent)
33
+ @speciality_subjects.size
34
+ end
35
+
36
+ def columnCount(parent)
37
+ 10
38
+ end
39
+
40
+ def data(index, role = Qt::DisplayRole)
41
+ speciality_subject = @speciality_subjects[index.row]
42
+ default = Qt::Variant.new
43
+ case role
44
+ when Qt::DisplayRole
45
+ case index.column
46
+ when 0
47
+ speciality_subject.lecturer.try(:to_s)
48
+ when 1
49
+ speciality_subject.subject.try(:title)
50
+ when 2
51
+ speciality_subject.semester.try(:title)
52
+ when 3
53
+ speciality_subject.speciality.try(:title)
54
+ when 4
55
+ speciality_subject.lecture_hours
56
+ when 5
57
+ speciality_subject.practical_hours
58
+ when 6
59
+ speciality_subject.consultations_hours
60
+ when 7
61
+ speciality_subject.lecture_hours.try(:+, speciality_subject.practical_hours || 0)
62
+ when 8
63
+ speciality_subject.preffered_days
64
+ when 9
65
+ speciality_subject.facultative
66
+ else
67
+ raise "invalid column #{index.column}"
68
+ end.try(:to_v) || default
69
+ when Qt::EditRole
70
+ case index.column
71
+ when 0
72
+ speciality_subject.lecturer_id
73
+ when 1
74
+ speciality_subject.subject_id
75
+ when 2
76
+ speciality_subject.semester_id
77
+ when 3
78
+ speciality_subject.speciality_id
79
+ when 4
80
+ speciality_subject.lecture_hours
81
+ when 5
82
+ speciality_subject.practical_hours
83
+ when 6
84
+ speciality_subject.consultations_hours
85
+ when 7
86
+ speciality_subject.lecture_hours.try(:+, speciality_subject.practical_hours || 0)
87
+ when 8
88
+ speciality_subject.preffered_days
89
+ when 9
90
+ speciality_subject.facultative
91
+ else
92
+ raise "invalid column #{index.column}"
93
+ end.try(:to_v) || default
94
+ else
95
+ default
96
+ end
97
+ end
98
+
99
+ def headerData(section, orientation, role = Qt::DisplayRole)
100
+ invalid = Qt::Variant.new
101
+ return invalid unless role == Qt::DisplayRole
102
+ v = case orientation
103
+ when Qt::Horizontal
104
+ ['Преподаватель', 'Предмет', 'Семестр', 'Специальность', 'Лекционные часы', 'Практические часы', 'Консультации', 'Всего', 'Рекомендуемые дни', 'Факультатив'][section]
105
+ else
106
+ ''
107
+ end
108
+ Qt::Variant.new(v)
109
+ end
110
+
111
+ def flags(index)
112
+ Qt::ItemIsEditable | super(index)
113
+ end
114
+
115
+ def setData(index, variant, role = Qt::EditRole)
116
+ if index.valid? and role == Qt::EditRole
117
+ speciality_subject = @speciality_subjects[index.row]
118
+ case index.column
119
+ when 0
120
+ speciality_subject.lecturer_id = variant.toInt
121
+ when 1
122
+ speciality_subject.subject_id = variant.toInt
123
+ when 2
124
+ speciality_subject.semester_id = variant.toInt
125
+ when 3
126
+ speciality_subject.speciality_id = variant.toInt
127
+ when 4
128
+ speciality_subject.lecture_hours = variant.toInt
129
+ when 5
130
+ speciality_subject.practical_hours = variant.toInt
131
+ when 6
132
+ speciality_subject.consultations_hours = variant.toInt
133
+ when 7
134
+ true
135
+ when 8
136
+ speciality_subject.preffered_days = variant.toString.force_encoding('UTF-8').split(/,\s*/).select{|x| x[/^[1-7]$/]}.uniq.join(', ')
137
+ when 9
138
+ speciality_subject.facultative = variant.toBool
139
+ else
140
+ raise "invalid column #{index.column}"
141
+ end
142
+ speciality_subject.save
143
+ emit dataChanged(index, index)
144
+ true
145
+ else
146
+ false
147
+ end
148
+ end
149
+
150
+ def insert_new
151
+ @speciality_subjects.prepend(SpecialitySubject.new)
152
+ emit layoutChanged()
153
+ end
154
+
155
+ def remove_current
156
+ if @view.currentIndex.valid?
157
+ @speciality_subjects[@view.currentIndex.row].try(:destroy)
158
+ @speciality_subjects.delete_at(@view.currentIndex.row)
159
+ emit layoutChanged()
160
+ @view.currentIndex = createIndex(-1, -1)
161
+ end
162
+ end
163
+
164
+ end
165
+
166
+ class LecturerComboBoxDelegate < Qt::ItemDelegate
167
+ def initialize(parent)
168
+ super
169
+ setup
170
+ end
171
+
172
+ def setup
173
+ @lecturers = Lecturer.all.sort_by(&:surname)
174
+ end
175
+
176
+ def createEditor(parent, option, index)
177
+ editor = Qt::ComboBox.new(parent)
178
+ @lecturers.each{ |x| editor.addItem(x.surname.to_s, x.id.to_v) }
179
+ editor
180
+ end
181
+
182
+ def setEditorData(editor, index)
183
+ value = index.data
184
+ editor.setCurrentIndex(editor.findData(value))
185
+ end
186
+
187
+ def setModelData(editor, model, index)
188
+ value = editor.itemData(editor.currentIndex)
189
+ model.setData(index, value, Qt::EditRole)
190
+ end
191
+
192
+ def updateEditorGeometry(editor, option, index)
193
+ editor.setGeometry(option.rect)
194
+ end
195
+ end
196
+
197
+ class SubjectComboBoxDelegate < Qt::ItemDelegate
198
+ def initialize(parent)
199
+ super
200
+ setup
201
+ end
202
+
203
+ def setup
204
+ @subjects = Subject.all.sort_by(&:title)
205
+ end
206
+
207
+ def createEditor(parent, option, index)
208
+ editor = Qt::ComboBox.new(parent)
209
+ @subjects.each{ |x| editor.addItem(x.title.to_s, x.id.to_v) }
210
+ editor
211
+ end
212
+
213
+ def setEditorData(editor, index)
214
+ value = index.data
215
+ editor.setCurrentIndex(editor.findData(value))
216
+ end
217
+
218
+ def setModelData(editor, model, index)
219
+ value = editor.itemData(editor.currentIndex)
220
+ model.setData(index, value, Qt::EditRole)
221
+ end
222
+
223
+ def updateEditorGeometry(editor, option, index)
224
+ editor.setGeometry(option.rect)
225
+ end
226
+ end
227
+
228
+ class SemesterComboBoxDelegate < Qt::ItemDelegate
229
+ def initialize(parent)
230
+ super
231
+ setup
232
+ end
233
+
234
+ def setup
235
+ @semesters = Semester.all.sort_by(&:title)
236
+ end
237
+
238
+ def createEditor(parent, option, index)
239
+ editor = Qt::ComboBox.new(parent)
240
+ @semesters.each{ |x| editor.addItem(x.title.to_s, x.id.to_v) }
241
+ editor
242
+ end
243
+
244
+ def setEditorData(editor, index)
245
+ value = index.data
246
+ editor.setCurrentIndex(editor.findData(value))
247
+ end
248
+
249
+ def setModelData(editor, model, index)
250
+ value = editor.itemData(editor.currentIndex)
251
+ model.setData(index, value, Qt::EditRole)
252
+ end
253
+
254
+ def updateEditorGeometry(editor, option, index)
255
+ editor.setGeometry(option.rect)
256
+ end
257
+ end
258
+
259
+ class SpecialityComboBoxDelegate < Qt::ItemDelegate
260
+ def initialize(parent)
261
+ super
262
+ setup
263
+ end
264
+
265
+ def setup
266
+ @specialities = Speciality.all.sort_by(&:title)
267
+ end
268
+
269
+ def createEditor(parent, option, index)
270
+ editor = Qt::ComboBox.new(parent)
271
+ @specialities.each{ |x| editor.addItem(x.title.to_s, x.id.to_v) }
272
+ editor
273
+ end
274
+
275
+ def setEditorData(editor, index)
276
+ value = index.data
277
+ editor.setCurrentIndex(editor.findData(value))
278
+ end
279
+
280
+ def setModelData(editor, model, index)
281
+ value = editor.itemData(editor.currentIndex)
282
+ model.setData(index, value, Qt::EditRole)
283
+ end
284
+
285
+ def updateEditorGeometry(editor, option, index)
286
+ editor.setGeometry(option.rect)
287
+ end
288
+ end
@@ -0,0 +1,87 @@
1
+ # encoding: UTF-8
2
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~
3
+ require_relative '../../engine/models/speciality'
4
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~
5
+ class SpecialityTableModel < Qt::AbstractTableModel
6
+
7
+ def initialize(specialities, parent)
8
+ super()
9
+ @specialities = specialities
10
+ @view = parent
11
+ end
12
+
13
+ def refresh
14
+ @specialities = Speciality.all
15
+ emit layoutChanged()
16
+ end
17
+
18
+ def rowCount(parent)
19
+ @specialities.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
+ speciality = @specialities[index.row]
30
+ return invalid if speciality.nil?
31
+ v = case index.column
32
+ when 0
33
+ speciality.title
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
+ speciality = @specialities[index.row]
59
+ case index.column
60
+ when 0
61
+ speciality.title = variant.toString.force_encoding('UTF-8')
62
+ else
63
+ raise "invalid column #{index.column}"
64
+ end
65
+ speciality.save
66
+ emit dataChanged(index, index)
67
+ true
68
+ else
69
+ false
70
+ end
71
+ end
72
+
73
+ def insert_new
74
+ @specialities.prepend(Speciality.new)
75
+ emit layoutChanged()
76
+ end
77
+
78
+ def remove_current
79
+ if @view.currentIndex.valid?
80
+ @specialities[@view.currentIndex.row].try(:destroy)
81
+ @specialities.delete_at(@view.currentIndex.row)
82
+ emit layoutChanged()
83
+ @view.currentIndex = createIndex(-1, -1)
84
+ end
85
+ end
86
+
87
+ end
@@ -0,0 +1,323 @@
1
+ # encoding: UTF-8
2
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~
3
+ require_relative '../../engine/models/study'
4
+ require_relative '../forms/edit_study'
5
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~
6
+ class StudyTableModel < Qt::AbstractTableModel
7
+
8
+ signals 'studySaved(QVariant)'
9
+ signals 'refreshTarification(QModelIndex)'
10
+ slots 'editStudy(QModelIndex)'
11
+ slots 'removeData()'
12
+ slots 'displayMenu(QPoint)'
13
+ slots 'cancelColoring()'
14
+
15
+ def initialize(date, parent = nil)
16
+ super()
17
+ @view = parent
18
+ @date = date
19
+ @studies = setup
20
+ @colors_for_studies = {}
21
+ @colors_for_cabinets = {}
22
+ end
23
+
24
+ def setup
25
+ @groups = Group.all.sort_by(&:title_for_sort)
26
+ @titles = @groups.map(&:title)
27
+ Hash[ Group.all.map{|g| [g, []]} ].
28
+ merge(Study.of_groups_and_its_subgroups(Group.scoped).
29
+ where(date: @date).
30
+ group_by(&:get_group)).
31
+ sort_by{|k, v| k.title_for_sort}.
32
+ map do |k, v|
33
+ [k, Hash[ v.sort_by(&:number).
34
+ group_by(&:number).
35
+ map{|n, ss| [n, ss.sort_by{|s| s.groupable.number}]}
36
+ ] ]
37
+ end
38
+ end
39
+
40
+ def refresh
41
+ @studies = setup
42
+ emit layoutChanged()
43
+ end
44
+
45
+ def rowCount(parent = self)
46
+ 12
47
+ end
48
+
49
+ def columnCount(parent = self)
50
+ @titles.size * 2
51
+ end
52
+
53
+ def data(index, role = Qt::DisplayRole, data = nil)
54
+ default = Qt::Variant.new
55
+ return default unless index.valid?
56
+ case role
57
+ when Qt::DisplayRole || Qt::EditRole
58
+ begin
59
+ if index.column.even?
60
+ @studies[index.column / 2][1][(index.row / 2) + 1][index.row % 2].to_s.to_v
61
+ else
62
+ @studies[index.column / 2][1][(index.row / 2) + 1][index.row % 2].cabinet.title.to_v
63
+ end
64
+ rescue NoMethodError
65
+ default
66
+ end
67
+ #if index.column.even?
68
+ # @studies[index.column / 2].try(:at, 1).try(:fetch, (index.row / 2) + 1, nil).try(:at, index.row % 2).try(:to_s)
69
+ #else
70
+ # @studies[index.column / 2].try(:at, 1).try(:fetch, (index.row / 2) + 1, nil).try(:at, index.row % 2).try(:cabinet).try(:title)
71
+ #end.try(:to_v) || default
72
+ when Qt::UserRole
73
+ begin
74
+ if (st = @studies[index.column / 2])
75
+ if (st = st[1])
76
+ if (st = st[(index.row / 2) + 1])
77
+ if (study = st[index.row % 2])
78
+ Base64.encode64(Marshal.dump(study)).to_v
79
+ else
80
+ group = @groups[index.column / 2]
81
+ Base64.encode64(Marshal.dump(group)).to_v
82
+ end
83
+ else
84
+ group = @groups[index.column / 2]
85
+ Base64.encode64(Marshal.dump(group)).to_v
86
+ end
87
+ else
88
+ group = @groups[index.column / 2]
89
+ Base64.encode64(Marshal.dump(group)).to_v
90
+ end
91
+ elsif (group = @groups[index.column / 2])
92
+ Base64.encode64(Marshal.dump(group)).to_v
93
+ else
94
+ default
95
+ end
96
+ rescue NoMethodError
97
+ default
98
+ end
99
+ when Qt::BackgroundRole #Qt::TextColorRole
100
+ begin
101
+ if index.column.even?
102
+ study = @studies[index.column / 2][1][(index.row / 2) + 1][index.row % 2]
103
+ if @colors_for_studies[study.id]
104
+ @colors_for_studies[study.id].to_v
105
+ elsif study.color
106
+ Qt::Variant.fromValue(Qt::Color.new(study.color))
107
+ else
108
+ default
109
+ end
110
+ else
111
+ study = @studies[index.column / 2][1][(index.row / 2) + 1][index.row % 2]
112
+ if @colors_for_cabinets[study.id]
113
+ @colors_for_cabinets[study.id].to_v
114
+ elsif study.color
115
+ Qt::Variant.fromValue(Qt::Color.new(study.color))
116
+ else
117
+ default
118
+ end
119
+ end
120
+ rescue NoMethodError
121
+ default
122
+ end
123
+ else
124
+ default
125
+ end
126
+ end
127
+
128
+ def headerData(section, orientation, role = Qt::DisplayRole)
129
+ invalid = Qt::Variant.new
130
+ return invalid unless role == Qt::DisplayRole
131
+ v = case orientation
132
+ when Qt::Vertical
133
+ (1..6).zip(Array.new(6, '')).flatten[section]
134
+ when Qt::Horizontal
135
+ @titles.zip(Array.new(@titles.size, 'Кабинет')).flatten[section]
136
+ else
137
+ ''
138
+ end
139
+ Qt::Variant.new(v)
140
+ end
141
+
142
+ def flags(index)
143
+ Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | super(index) if index.valid?
144
+ end
145
+
146
+ def setData(index, variant, role = Qt::EditRole)
147
+ if index.valid? and role == Qt::EditRole
148
+ if (studies = @studies[index.column / 2][1][(index.row / 2) + 1]) && (studies[index.row % 2])
149
+ study = studies[index.row % 2]
150
+ EditStudyDialog.new().setupData(study).exec
151
+ refresh
152
+ emit studySaved(study.date.to_v) unless study.date == @date
153
+ else
154
+ study = Study.new
155
+ study.groupable_type = 'Group'
156
+ study.groupable_id = @groups[index.column / 2].id
157
+ study.number = (1..6).to_a[index.row / 2]
158
+ study.date = @date
159
+ EditStudyDialog.new().setupData(study).exec
160
+ unless study.new_record?
161
+ refresh
162
+ emit studySaved(study.date.to_v) unless study.date == @date
163
+ end
164
+ end
165
+ emit dataChanged(index, index)
166
+ true
167
+ else
168
+ false
169
+ end
170
+ end
171
+
172
+ def removeData
173
+ if @view.hasFocus && (index = @view.currentIndex).valid?
174
+ if (studies = @studies[index.column / 2][1][(index.row / 2) + 1])
175
+ if (study = studies[index.row % 2])
176
+ study.delete
177
+ refresh
178
+ emit refreshTarification(index) if $TARIFICATION_MODE
179
+ emit dataChanged(index, createIndex(index.row, index.column + 1))
180
+ end
181
+ end
182
+ end
183
+ end
184
+
185
+ #def dropEvent(event)
186
+ #if event.mimeData().hasFormat("text/plain")
187
+ # event.accept()
188
+ #else
189
+ # event.ignore()
190
+ #end
191
+ #end
192
+
193
+ def mimeData(indexes)
194
+ index = indexes.first
195
+ mime_data = super indexes # для обхода ошибки сегментации Qt::MimeData создаётся с помощью родительского метода
196
+ if (studies = @studies[index.column / 2][1][(index.row / 2) + 1]) && (studies[index.row % 2])
197
+ study = studies[index.row % 2]
198
+ study_dump = Base64.encode64(Marshal.dump(study))
199
+ byte_study = Qt::ByteArray.new study_dump
200
+ table_model_ref = Qt::ByteArray.new self.object_id.to_s
201
+ mime_data.setData('application/study', byte_study)
202
+ mime_data.setData('application/model', table_model_ref)
203
+ else
204
+ mime_data.setData('application/empty', Qt::ByteArray.new(''))
205
+ end
206
+ mime_data
207
+ end
208
+
209
+ def dropMimeData(data, action, row, column, index)
210
+ table_model = ObjectSpace._id2ref(data.data('application/model').data.to_i)
211
+ subject_id = data.data('application/subject').data if data.hasFormat('application/subject')
212
+ lecturer_id = data.data('application/lecturer').data if data.hasFormat('application/lecturer')
213
+ cabinet_id = data.data('application/cabinet').data if data.hasFormat('application/cabinet')
214
+ # date почему-то содержит "application/subject" с каким-то мусором, если drag осуществляется из табицы
215
+ return false if !index.valid? || data.hasFormat('application/empty')
216
+ if data.hasFormat('application/study')
217
+ study = Marshal.load(Base64.decode64(data.data('application/study').data))
218
+ study.number = (1..6).to_a[index.row / 2]
219
+ study.date = @date
220
+ if study.groupable.group?
221
+ study.groupable_id = @groups[index.column / 2].id
222
+ else
223
+ number = study.groupable.number
224
+ study.groupable = @groups[index.column / 2].subgroups.where(number: number).first
225
+ end
226
+ if (studies = @studies[index.column / 2][1][(index.row / 2) + 1]) && (studies[index.row % 2])
227
+ exist_study = studies[index.row % 2]
228
+ exist_study.delete unless exist_study == study
229
+ @studies[index.column / 2][1][(index.row / 2) + 1][index.row % 2] = study
230
+ else
231
+ if @studies[index.column / 2][1][(index.row / 2) + 1]
232
+ @studies[index.column / 2][1][(index.row / 2) + 1][index.row % 2] = study
233
+ else
234
+ array = []
235
+ array[index.row % 2] = study
236
+ @studies[index.column / 2][1][(index.row / 2) + 1] = array
237
+ end
238
+ end
239
+ else
240
+ if (studies = @studies[index.column / 2][1][(index.row / 2) + 1]) && (studies[index.row % 2])
241
+ study = studies[index.row % 2]
242
+ study.subject_id = subject_id if subject_id
243
+ study.lecturer_id = lecturer_id if lecturer_id
244
+ study.cabinet_id = cabinet_id if cabinet_id
245
+ elsif subject_id || lecturer_id || cabinet_id
246
+ study = Study.new
247
+ if (studies = @studies[index.column / 2][1][(index.row / 2) + 1]) && (studies[(index.row % 2) - 1])
248
+ another_study = studies[(index.row % 2) - 1]
249
+ if another_study.groupable.subgroup?
250
+ if another_study.groupable.number == 1
251
+ study.groupable = another_study.groupable.get_group.subgroups.where(number: 2).first
252
+ else
253
+ study.groupable = another_study.groupable.get_group.subgroups.where(number: 1).first
254
+ end
255
+ else
256
+ another_study.groupable = another_study.groupable.get_group.subgroups.where(number: 1).first
257
+ study.groupable = another_study.groupable.get_group.subgroups.where(number: 2).first
258
+ end
259
+ else
260
+ study.groupable_type = 'Group'
261
+ study.groupable_id = @groups[index.column / 2].id
262
+ end
263
+ study.number = (1..6).to_a[index.row / 2]
264
+ study.date = @date
265
+ study.subject_id = subject_id || Subject.where(stub: true).first.id
266
+ study.lecturer_id = lecturer_id || Lecturer.where(stub: true).first.id
267
+ study.cabinet_id = cabinet_id || Cabinet.where(stub: true).first.id
268
+ end
269
+ end
270
+ study.save
271
+ refresh
272
+ table_model.refresh if table_model && table_model != self
273
+ emit refreshTarification(index) if $TARIFICATION_MODE
274
+ emit dataChanged(index, index)
275
+ true
276
+ end
277
+
278
+ def setItemData(index, roles)
279
+ false
280
+ end
281
+
282
+ def supportedDropActions
283
+ Qt::CopyAction
284
+ end
285
+
286
+ def insertRows(row, count, parent )
287
+ false
288
+ end
289
+
290
+ def insertColumns(column, count, parent )
291
+ false
292
+ end
293
+
294
+ def mimeTypes
295
+ ['application/subject', 'application/lecturer', 'application/cabinet', 'application/study']
296
+ end
297
+
298
+ def displayMenu(pos)
299
+ menu = Qt::Menu.new()
300
+ remove = Qt::Action.new('Удалить', menu)
301
+ connect(remove, SIGNAL('triggered()'), self, SLOT('removeData()'))
302
+ menu.addAction(remove)
303
+ menu.exec(@view.viewport.mapToGlobal(pos))
304
+ end
305
+
306
+ def setColor(id, color)
307
+ @colors_for_studies[id] = color
308
+ end
309
+
310
+ def setColorCabinet(id, color)
311
+ @colors_for_cabinets[id] = color
312
+ end
313
+
314
+ def cancelColoring()
315
+ @colors_for_studies.clear
316
+ @colors_for_cabinets.clear
317
+ refresh
318
+ end
319
+
320
+ def editStudy(index)
321
+ setData(index, nil, Qt::EditRole)
322
+ end
323
+ end