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