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