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,6 @@
1
+ class SpecialitySubject < ActiveRecord::Base
2
+ belongs_to :subject
3
+ belongs_to :semester
4
+ belongs_to :speciality
5
+ belongs_to :lecturer
6
+ end
@@ -0,0 +1,56 @@
1
+ # coding: UTF-8
2
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3
+ require 'contracts'
4
+ #include Contracts
5
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6
+ class Study < ActiveRecord::Base
7
+ belongs_to :groupable, :polymorphic => true
8
+ belongs_to :subject
9
+ belongs_to :lecturer
10
+ belongs_to :cabinet
11
+
12
+ # Use Model#scoped instead of Model#all
13
+ #Contract ActiveRecord::Relation => ActiveRecord::Relation::ActiveRecord_Relation_Group
14
+ def self.of_groups_and_its_subgroups(groups)
15
+ where_groups_or_subgroups(groups.select(:id), Subgroup.where(group_id: groups.select(:id)))
16
+ end
17
+
18
+ #Contract Group => ActiveRecord::Relation
19
+ def self.of_group_and_its_subgroups(group)
20
+ where_groups_or_subgroups(group.id, Subgroup.where(group_id: group.id))
21
+ end
22
+
23
+ def validate
24
+ end
25
+
26
+ def get_group
27
+ groupable.get_group
28
+ end
29
+
30
+ def to_group?
31
+ groupable_type == 'Group'
32
+ end
33
+
34
+ def to_subgroup?
35
+ groupable_type == 'Subgroup'
36
+ end
37
+
38
+ def to_s
39
+ begin
40
+ if to_subgroup?
41
+ "#{subject.title}\n#{lecturer}" + " (#{groupable.number}п)"
42
+ else
43
+ "#{subject.title}\n#{lecturer}"
44
+ end
45
+ rescue #FIXME
46
+ 'ERROR'
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def self.where_groups_or_subgroups(ids_of_groups, ids_of_subroups)
53
+ where('(groupable_type = "Group" AND groupable_id in (?)) OR (groupable_type = "Subgroup" AND groupable_id in (?))', ids_of_groups, ids_of_subroups)
54
+ end
55
+ private_class_method :where_groups_or_subgroups
56
+ end
@@ -0,0 +1,21 @@
1
+ # coding: UTF-8
2
+ class Subgroup < ActiveRecord::Base
3
+ belongs_to :group
4
+ has_many :studies, :as => :groupable, :dependent => :destroy
5
+
6
+ def group?
7
+ false
8
+ end
9
+
10
+ def subgroup?
11
+ true
12
+ end
13
+
14
+ def get_group
15
+ self.group
16
+ end
17
+
18
+ def to_s
19
+ "#{group.title} #{number} подгруппа"
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ class Subject < ActiveRecord::Base
2
+ has_many :studies
3
+ has_many :speciality_subjects
4
+
5
+ before_destroy :set_stubs_for_studies
6
+
7
+ def to_s
8
+ title
9
+ end
10
+
11
+ def set_stubs_for_studies
12
+ raise "Stub can't be destroyed!" if self.stub
13
+ stub = Subject.where(stub: true).first
14
+ studies.each do |s|
15
+ s.subject = stub
16
+ s.save
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,96 @@
1
+ # coding: UTF-8
2
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3
+ class Verificator
4
+
5
+ def initialize(dates)
6
+ @dates = dates.to_a
7
+ end
8
+
9
+ def verify(verification)
10
+ case verification
11
+ when :lecturer_studies
12
+ lecturer_studies
13
+ when :cabinet_studies
14
+ cabinet_studies
15
+ when :lecturer_stubs
16
+ lecturer_stubs
17
+ when :cabinet_stubs
18
+ cabinet_stubs
19
+ when :subject_stubs
20
+ subject_stubs
21
+ when :group_and_subgroups
22
+ group_and_subgroups
23
+ when :preferred_days
24
+ preferred_days
25
+ when :computer_cabinets
26
+ computer_cabinet
27
+ else
28
+ raise ArgumentError, 'No such verification'
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def lecturer_studies
35
+ @dates.map do |date|
36
+ Study.select('date, number, lecturer_id, count(*)').where(date: date).group('number, lecturer_id').having('count(*) > 1')
37
+ end.flatten.map{|x| Study.where(date: x.date, number: x.number, lecturer_id: x.lecturer_id )}.flatten.group_by{|x| [x.date, x.lecturer_id, x.number] }
38
+ #@dates.map{ |date| Study.select('id, date, number, lecturer_id, count(*)').where(date: date).group('number, lecturer_id').having('count(*) > 1').to_a }
39
+ end
40
+
41
+ def cabinet_studies
42
+ @dates.map do |date|
43
+ Study.select('date, number, cabinet_id, count(*)').where(date: date).group('number, cabinet_id').having('count(*) > 1')
44
+ end.flatten.map{|x| Study.where(date: x.date, number: x.number, cabinet_id: x.cabinet_id )}.flatten.group_by{|x| [x.date, x.cabinet_id, x.number] }
45
+ end
46
+
47
+ def lecturer_stubs
48
+ @dates.map do |date|
49
+ [date, Study.joins(:lecturer).where('lecturers.stub = ?', true).where(date: date)]
50
+ end
51
+ end
52
+
53
+ def cabinet_stubs
54
+ @dates.map do |date|
55
+ [date, Study.joins(:cabinet).where('cabinets.stub = ?', true).where(date: date)]
56
+ end
57
+ end
58
+
59
+ def subject_stubs
60
+ @dates.map do |date|
61
+ [date, Study.joins(:subject).where('subjects.stub = ?', true).where(date: date)]
62
+ end
63
+ end
64
+
65
+ def computer_cabinet
66
+ @dates.map do |date|
67
+ [date, Study.joins(:cabinet).where(groupable_type: 'Subgroup').where("cabinets.with_computers = ?", false).where(date: date)]
68
+ end
69
+ end
70
+
71
+ def preferred_days
72
+ @dates.map do |date|
73
+ #[date, Study.joins(:lecturer).where(date: date).where("NOT instr(preferred_days, strftime('%w', date))")] # doesn't work on windows
74
+ #[date, Study.joins(:lecturer).where(date: date).where("NOT preferred_days like strftime('%w', date)")]
75
+ [date, Lecturer.all.map do |l|
76
+ if l.preferred_days
77
+ l.studies.where(date: date).where("NOT strftime('%w', date) in (#{l.preferred_days.split(/,\s*/).map{|s| '\'' << s << '\'' }.join(',')})", ).to_a
78
+ end
79
+ end.flatten.compact]
80
+ end
81
+ end
82
+
83
+ #- занятия для группы и подгруппы на одной паре
84
+ #def group_and_subgroup
85
+ # @dates.map do |date|
86
+ # Study.select('date, number, groupable_type, count(*)').where(date: date).group('number, groupable_type').having('count(*) > 1')
87
+ # end.flatten.map{|x| Study.where(date: x.date, number: x.number, cabinet_id: x.cabinet_id )}.flatten.group_by{|x| [x.date, x.cabinet_id, x.number] }
88
+ #end
89
+ end
90
+
91
+ # SELECT surname, count(surname)
92
+ # FROM "lecturers"
93
+ # group by surname
94
+ # having count(surname) > 1
95
+ # Lecturer.select('surname, count(surname)').group(:surname).having('count(surname) > 1')
96
+ # select lecturer_id, number, count(*) from studies where date = '2013-06-03' group by number, lecturer_id having count(*) > 1
@@ -0,0 +1,24 @@
1
+ # coding: UTF-8
2
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3
+ require 'Qt'
4
+ require_relative 'ui_about'
5
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6
+ require 'contracts'
7
+ #include Contracts
8
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9
+ class AboutDialog < Qt::Dialog
10
+
11
+ def initialize(parent = nil)
12
+ super parent
13
+ @ui = Ui::AboutDialog.new
14
+ @ui.setup_ui self
15
+ @ui.textBrowser.html += <<-HEREDOC.gsub(/^ {4}/, '')
16
+ <p>Timetable Management Information System</p>
17
+ Версия: 0.1
18
+ <p>Информационная система управления расписанием, предназначенная для учебных заведений среднего профессионального образования.</p>
19
+ <p>Copyright © 2012 Милешкин Владислав noein93@gmail.com</p>
20
+ <p>TMIS является свободным программным обеспечением и распространяется на условиях GNU GPLv3. Текст лицензии можно найти в файле COPYING, а также по ссылке: www.gnu.org/licenses/gpl.</p>
21
+ HEREDOC
22
+ end
23
+
24
+ end
@@ -0,0 +1,28 @@
1
+ # coding: UTF-8
2
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3
+ require 'Qt'
4
+ require 'date'
5
+ require_relative 'ui_console'
6
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7
+ require 'contracts'
8
+ #include Contracts
9
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10
+ class ConsoleDialog < Qt::Dialog
11
+
12
+ signals 'dialogClosed()'
13
+
14
+ attr_accessor :browser
15
+
16
+ def initialize(parent = nil)
17
+ super parent
18
+ @ui = Ui::ConsoleDialog.new
19
+ @ui.setup_ui self
20
+ @browser = @ui.textBrowser
21
+ end
22
+
23
+ def closeEvent(event)
24
+ emit dialogClosed
25
+ event.accept
26
+ end
27
+
28
+ end
@@ -0,0 +1,32 @@
1
+ # coding: UTF-8
2
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3
+ require 'Qt'
4
+ require 'date'
5
+ require_relative 'ui_debug_console'
6
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7
+ require 'contracts'
8
+ #include Contracts
9
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10
+ class DebugConsoleDialog < Qt::Dialog
11
+
12
+ slots 'on_enterPushButton_pressed()'
13
+
14
+ attr_accessor :browser
15
+
16
+ def initialize(parent = nil)
17
+ super parent
18
+ @ui = Ui::DebugConsoleDialog.new
19
+ @ui.setup_ui self
20
+ end
21
+
22
+ def on_enterPushButton_pressed
23
+ res = '$'
24
+ begin
25
+ res = "#{Database.instance.instance_eval(@ui.lineEdit.text)}"
26
+ rescue Exception => detail
27
+ @ui.textEdit.setText("Error on #{@ui.lineEdit.text}")
28
+ end
29
+ @ui.textEdit.setText(res)
30
+ end
31
+
32
+ end
@@ -0,0 +1,110 @@
1
+ # coding: UTF-8
2
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3
+ require 'Qt'
4
+ require 'date'
5
+ require_relative 'ui_edit_study'
6
+ require_relative '../../engine/database'
7
+ require_relative '../../engine/models/lecturer'
8
+ #require_relative '../../engine/models/group'
9
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10
+ require 'contracts'
11
+ #include Contracts
12
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13
+ class EditStudyDialog < Qt::Dialog
14
+
15
+ slots 'on_groupComboBox_currentIndexChanged(int)'
16
+ slots 'on_selectColorPushButton_clicked()'
17
+ slots 'on_defaultColorPushButton_clicked()'
18
+ slots 'reset()'
19
+ slots 'save()'
20
+
21
+ def initialize(parent = nil)
22
+ super parent
23
+ @ui = Ui::EditStudyDialog.new
24
+ @ui.setup_ui self
25
+ end
26
+
27
+ #Contract Study => EditStudyDialog
28
+ def setupData(study)
29
+ @study = study
30
+ setWindowTitle 'Новое занятие' if @study.new_record?
31
+ @color = Qt::Color.new(study.color || "#ffffff")
32
+ @ui.selectColorPushButton.setPalette(Qt::Palette.new(@color))
33
+ # set group
34
+ Group.all.sort_by(&:title_for_sort).each{|x| @ui.groupComboBox.addItem(x.title, x.id.to_v)}
35
+ @ui.groupComboBox.setCurrentIndex(@ui.groupComboBox.findData(@study.groupable.get_group.id.to_v))
36
+ # set subject
37
+ Subject.all.sort_by(&:title).each{|x| @ui.subjectComboBox.addItem(x.title, x.id.to_v)}
38
+ @ui.subjectComboBox.setCurrentIndex(@ui.subjectComboBox.findData(@study.subject.id.to_v)) unless @study.new_record?
39
+ # set lecturer
40
+ Lecturer.all.sort_by(&:surname).each{|x| @ui.lecturerComboBox.addItem(x.to_s, x.id.to_v)}
41
+ @ui.lecturerComboBox.setCurrentIndex(@ui.lecturerComboBox.findData(@study.lecturer.id.to_v)) unless @study.new_record?
42
+ # set cabinet
43
+ Cabinet.all.sort_by(&:title).each{|x| @ui.cabinetComboBox.addItem(x.title.to_s, x.id.to_v)}
44
+ @ui.cabinetComboBox.setCurrentIndex(@ui.cabinetComboBox.findData(@study.cabinet.id.to_v)) unless @study.new_record?
45
+ # set number
46
+ (1..6).each{|x| @ui.numberComboBox.addItem(x.to_s, x.to_v)}
47
+ @ui.numberComboBox.setCurrentIndex(@ui.numberComboBox.findData(@study.number.to_v))
48
+ @ui.dateDateEdit.setDate(Qt::Date.fromString(@study.date.to_s, Qt::ISODate))
49
+ connect(@ui.buttonBox.button(Qt::DialogButtonBox::Reset), SIGNAL('clicked()'), self, SLOT('reset()'))
50
+ connect(@ui.buttonBox.button(Qt::DialogButtonBox::Save), SIGNAL('clicked()'), self, SLOT('save()'))
51
+ connect(@ui.buttonBox.button(Qt::DialogButtonBox::Cancel), SIGNAL('clicked()')){ close }
52
+ self
53
+ end
54
+
55
+ def on_groupComboBox_currentIndexChanged(index)
56
+ @ui.subgroupComboBox.clear
57
+ @ui.subgroupComboBox.addItem('Вся группа', 0.to_v)
58
+ Subgroup.where(group_id: @study.groupable.get_group).each{|x| @ui.subgroupComboBox.addItem(x.number.to_s, x.id.to_v)}
59
+ if @study.groupable.subgroup? && !@study.new_record?
60
+ @ui.subgroupComboBox.setCurrentIndex(@ui.subgroupComboBox.findData(@study.groupable.id.to_v))
61
+ else
62
+ @ui.subgroupComboBox.setCurrentIndex(0)
63
+ end
64
+ end
65
+
66
+ def reset
67
+ [@ui.groupComboBox, @ui.subgroupComboBox, @ui.subjectComboBox, @ui.lecturerComboBox, @ui.cabinetComboBox,
68
+ @ui.numberComboBox].each(&:clear)
69
+ setupData(@study)
70
+ end
71
+
72
+ def save
73
+ if @ui.subgroupComboBox.currentIndex == 0
74
+ group = Group.where(id: @ui.groupComboBox.itemData(@ui.groupComboBox.currentIndex).to_i).first
75
+ @study.groupable_id = group.id
76
+ @study.groupable_type = 'Group'
77
+ else
78
+ subgroup = Subgroup.where(id: @ui.subgroupComboBox.itemData(@ui.subgroupComboBox.currentIndex).to_i).first
79
+ @study.groupable_id = subgroup.id
80
+ @study.groupable_type = 'Subgroup'
81
+ end
82
+ @study.subject = Subject.where(id: @ui.subjectComboBox.itemData(@ui.subjectComboBox.currentIndex).to_i).first
83
+ @study.lecturer = Lecturer.where(id: @ui.lecturerComboBox.itemData(@ui.lecturerComboBox.currentIndex).to_i).first
84
+ @study.cabinet = Cabinet.where(id: @ui.cabinetComboBox.itemData(@ui.cabinetComboBox.currentIndex).to_i).first
85
+ @study.number = @ui.numberComboBox.currentIndex + 1
86
+ @study.date = Date.parse(@ui.dateDateEdit.date.toString(Qt::ISODate))
87
+ @study.color = @color.name
88
+ @study.save
89
+ close
90
+ end
91
+
92
+ def on_defaultColorPushButton_clicked
93
+ @color = Qt::Color.new("#ffffff")
94
+ @ui.selectColorPushButton.setPalette(Qt::Palette.new(@color))
95
+ end
96
+
97
+ def on_selectColorPushButton_clicked
98
+ color = Qt::ColorDialog.getColor(@color, self)
99
+ if color.valid?
100
+ @ui.selectColorPushButton.setPalette(Qt::Palette.new(color))
101
+ @color = color
102
+ end
103
+ end
104
+
105
+ def show_message(text)
106
+ box = Qt::MessageBox.new
107
+ box.setText text
108
+ box.exec
109
+ end
110
+ end
@@ -0,0 +1,128 @@
1
+ # coding: UTF-8
2
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3
+ require 'Qt'
4
+ require 'date'
5
+ require_relative 'ui_expand_changes'
6
+ require_relative '../../engine/database'
7
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8
+ require 'contracts'
9
+ #include Contracts
10
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11
+ class ExpandChangesDialog < Qt::Dialog
12
+
13
+ slots 'on_buttonBox_accepted()'
14
+ slots 'on_buttonBox_rejected()'
15
+
16
+ def initialize(parent = nil)
17
+ super(parent)
18
+ @ui = Ui::ExpandChangesDialog.new
19
+ @ui.setup_ui self
20
+ @date = Date.parse(parent.ui.dateDateEdit.date.toString(Qt::ISODate))
21
+ monday = Qt::Date.fromString(@date.monday.to_s, Qt::ISODate)
22
+ @ui.fromDateDateEdit.setDate monday
23
+ @ui.toDateDateEdit.setDate monday
24
+ end
25
+
26
+ def on_buttonBox_accepted
27
+ from_monday = Date.parse(@ui.fromDateDateEdit.date.toString(Qt::ISODate)).monday
28
+ to_date = Date.parse(@ui.toDateDateEdit.date.toString(Qt::ISODate))
29
+ week_studies = Study.where(date: from_monday..(from_monday + 6))
30
+
31
+ Database.instance.transaction do
32
+ case @ui.evennessComboBox.currentIndex
33
+ when 0
34
+ if from_monday == to_date
35
+ elsif to_date > from_monday
36
+ dates = (from_monday + 7).upto(to_date).select{|date| (1..6).include? date.cwday }.to_a
37
+ Study.where(date: (from_monday + 7)..to_date).each{|study| study.destroy }
38
+ week_studies.each do |study|
39
+ dates.each do |date|
40
+ if study.date.cwday == date.cwday
41
+ study = study.dup
42
+ study.date = date
43
+ study.save
44
+ end
45
+ end
46
+ end
47
+ elsif to_date < from_monday
48
+ dates = (from_monday - 1).downto(to_date).select{|date| (1..6).include? date.cwday }.to_a
49
+ Study.where(date: to_date...from_monday).each{|study| study.destroy }
50
+ week_studies.each do |study|
51
+ dates.each do |date|
52
+ if study.date.cwday == date.cwday
53
+ study = study.dup
54
+ study.date = date
55
+ study.save
56
+ end
57
+ end
58
+ end
59
+ end
60
+ when 1
61
+ if from_monday == to_date
62
+ elsif to_date > from_monday
63
+ dates = (from_monday + 7).upto(to_date).select{|date| date.cweek.even? && ((1..6).include? date.cwday) }.to_a
64
+ Study.where(date: (from_monday + 7)..to_date).each{|study| study.destroy }
65
+ week_studies.each do |study|
66
+ dates.each do |date|
67
+ if study.date.cwday == date.cwday
68
+ study = study.dup
69
+ study.date = date
70
+ study.save
71
+ end
72
+ end
73
+ end
74
+ elsif to_date < from_monday
75
+ dates = (from_monday - 1).downto(to_date).select{|date| date.cweek.even? && ((1..6).include? date.cwday) }.to_a
76
+ Study.where(date: to_date...from_monday).each{|study| study.destroy }
77
+ week_studies.each do |study|
78
+ dates.each do |date|
79
+ if study.date.cwday == date.cwday
80
+ study = study.dup
81
+ study.date = date
82
+ study.save
83
+ end
84
+ end
85
+ end
86
+ end
87
+ when 2
88
+ if from_monday == to_date
89
+ elsif to_date > from_monday
90
+ dates = (from_monday + 7).upto(to_date).select{|date| date.cweek.odd? && ((1..6).include? date.cwday) }.to_a
91
+ Study.where(date: (from_monday + 7)..to_date).each{|study| study.destroy }
92
+ week_studies.each do |study|
93
+ dates.each do |date|
94
+ if study.date.cwday == date.cwday
95
+ study = study.dup
96
+ study.date = date
97
+ study.save
98
+ end
99
+ end
100
+ end
101
+ elsif to_date < from_monday
102
+ dates = (from_monday - 1).downto(to_date).select{|date| date.cweek.odd? && ((1..6).include? date.cwday) }.to_a
103
+ Study.where(date: to_date...from_monday).each{|study| study.destroy }
104
+ week_studies.each do |study|
105
+ dates.each do |date|
106
+ if study.date.cwday == date.cwday
107
+ study = study.dup
108
+ study.date = date
109
+ study.save
110
+ end
111
+ end
112
+ end
113
+ end
114
+ else
115
+ end
116
+ end
117
+ end
118
+
119
+ def on_buttonBox_rejected
120
+ close
121
+ end
122
+
123
+ def show_message(text)
124
+ box = Qt::MessageBox.new
125
+ box.setText text
126
+ box.exec
127
+ end
128
+ end
@@ -0,0 +1,68 @@
1
+ # coding: UTF-8
2
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3
+ require 'Qt'
4
+ require 'date'
5
+ require_relative 'ui_export_general_timetable'
6
+ require_relative '../../engine/database'
7
+ require_relative '../../engine/export/timetable_exporter.rb'
8
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9
+ require 'contracts'
10
+ #include Contracts
11
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12
+ class ExportGeneralTimetableDialog < Qt::Dialog
13
+
14
+ slots 'on_exportButtonBox_accepted()'
15
+ slots 'on_exportButtonBox_rejected()'
16
+ slots 'on_browsePushButton_clicked()'
17
+
18
+ def initialize(initial_date, parent = nil)
19
+ super parent
20
+ @ui = Ui::ExportGeneralTimetableDialog.new
21
+ @ui.setup_ui self
22
+ @ui.dateDateEdit.setDate Qt::Date.fromString(initial_date.to_s, Qt::ISODate)
23
+ end
24
+
25
+ def on_browsePushButton_clicked
26
+ @ui.pathLineEdit.text = Qt::FileDialog::getSaveFileName(self, 'Save File', 'NewTimetable', 'XLS Spreadsheet(*.xls)')
27
+ end
28
+
29
+ def on_exportButtonBox_accepted
30
+ filename = @ui.pathLineEdit.text.force_encoding 'UTF-8'
31
+ if filename.empty?
32
+ show_message 'Выберите путь к файлу'
33
+ else
34
+ path = Pathname.new(filename)
35
+ if path.dirname.writable?
36
+ date = Date.parse @ui.dateDateEdit.date.toString(Qt::ISODate)
37
+ export(date, path)
38
+ close
39
+ else
40
+ show_message 'Файл не может быть записан!'
41
+ end
42
+ end
43
+ end
44
+
45
+ def on_exportButtonBox_rejected
46
+ close
47
+ end
48
+
49
+ def export(date, path)
50
+ if path.exist?
51
+ path.delete
52
+ spreadsheet = SpreadsheetCreater.create path.to_s
53
+ else
54
+ spreadsheet = SpreadsheetCreater.create path.to_s
55
+ end
56
+ if @ui.weeklyRadioButton.isChecked
57
+ TimetableExporter.new(spreadsheet, GeneralTimetableExportStratagy.new(date.monday..date.monday + 5)).export.save
58
+ else
59
+ TimetableExporter.new(spreadsheet, GeneralTimetableExportStratagy.new([date])).export.save
60
+ end
61
+ end
62
+
63
+ def show_message(text)
64
+ box = Qt::MessageBox.new
65
+ box.setText text
66
+ box.exec
67
+ end
68
+ end