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,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