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