]> mj.ucw.cz Git - moe.git/blob - submit/contest
The first bits of the contest GUI.
[moe.git] / submit / contest
1 #!/usr/bin/perl
2 # Contest UI for the MO Submitter
3 # (c) 2007 Martin Mares <mj@ucw.cz>
4
5 use strict;
6 use warnings;
7
8 BEGIN {
9         defined $ENV{"MO_ROOT"} or die "Please set MO_ROOT to the contest root directory first.\n";
10 }
11 use lib $ENV{"MO_ROOT"} . "/submit";
12 use lib $ENV{"MO_ROOT"} . "/submit/lib/perl5";
13
14 use MO::Submit;
15 use Sherlock::Object;
16 use Gtk2 -init;
17
18 my $conn = new MO::Submit;
19
20 ### GUI INITIALIZATION ###
21
22 sub init_refresh();
23 sub timed_refresh();
24 sub refresh($);
25
26 my $busy_cursor = Gtk2::Gdk::Cursor->new('watch');
27
28 # The main window
29 my $window = Gtk2::Window->new('toplevel');
30 $window->signal_connect("delete-event" => sub { Gtk2->main_quit });
31 $window->set_title($conn->{"Contest"} . " Submitter");
32 $window->set_wmclass("submitter", "Submitter");
33 $window->set_default_size(320, 400);
34
35 # The title label
36 my $title_lab = Gtk2::Label->new;
37 $title_lab->set_markup("<span size='x-large'>" . $conn->{"Contest"} . "</span>");
38
39 # The row of buttons
40 my $b_submit = Gtk2::Button->new('Submit');
41 $b_submit->signal_connect(clicked => sub { Gtk2->main_quit });
42 $b_submit->set_sensitive(0);
43
44 my $b_check = Gtk2::Button->new('Check');
45 $b_check->signal_connect(clicked => sub { Gtk2->main_quit });
46 $b_check->set_sensitive(0);
47
48 my $b_refresh = Gtk2::Button->new('Refresh');
49 $b_refresh->signal_connect(clicked => sub { refresh(0) });
50
51 my $button_box = Gtk2::HBox->new;
52 $button_box->pack_start_defaults($b_submit);
53 $button_box->pack_start_defaults($b_check);
54 $button_box->pack_start_defaults($b_refresh);
55 $button_box->set_border_width(5);
56
57 # The list of tasks
58 my $task_store = Gtk2::ListStore->new('Glib::String', 'Glib::String', 'Glib::String');
59
60 my $task_view = Gtk2::TreeView->new($task_store);
61 my $task_renderer = Gtk2::CellRendererText->new;
62 my $task_col1 = Gtk2::TreeViewColumn->new_with_attributes("Task", $task_renderer, "text", 0);
63 $task_view->append_column($task_col1);
64 my $task_col2 = Gtk2::TreeViewColumn->new_with_attributes("Part", $task_renderer, "text", 1);
65 $task_view->append_column($task_col2);
66 my $task_col3 = Gtk2::TreeViewColumn->new_with_attributes("Status", $task_renderer, "text", 2);
67 $task_view->append_column($task_col3);
68 $task_view->set_headers_visible(0);
69
70 my $task_scroll = Gtk2::ScrolledWindow->new;
71 $task_scroll->set_policy("automatic", "automatic");
72 $task_scroll->add($task_view);
73 $task_scroll->set_border_width(5);
74
75 my $task_frame = Gtk2::Frame->new("Tasks");
76 $task_frame->add($task_scroll);
77
78 my $selected_task;
79 my $task_sel = $task_view->get_selection;
80 $task_sel->set_mode('single');
81 $task_sel->signal_connect(changed => sub {
82         my $iter = $_[0]->get_selected;
83         if ($iter) {
84                 $selected_task = $task_store->get($iter, 0);
85                 print "Selected $selected_task\n";
86                 $b_submit->set_sensitive(1);
87                 $b_check->set_sensitive(1);
88         } else {
89                 $selected_task = undef;
90                 print "Deselected task\n";
91                 $b_submit->set_sensitive(0);
92                 $b_check->set_sensitive(0);
93         }
94 });
95
96 my $status_bar = Gtk2::Statusbar->new;
97 my $bar_ctx = $status_bar->get_context_id('xyzzy');
98
99 my $vbox = Gtk2::VBox->new;
100 $vbox->pack_start($title_lab, 0, 0, 10);
101 $vbox->pack_start($task_frame, 1, 1, 0);
102 $vbox->pack_start($button_box, 0, 0, 0);
103 $vbox->pack_start($status_bar, 0, 0, 0);
104
105 $window->add($vbox);
106 $window->signal_connect("expose-event" => sub { init_refresh(); return 0; });
107 $window->show_all;
108
109 Glib::Timeout->add(5000, \&timed_refresh);
110 Gtk2->main;
111 exit 0;
112
113 ### ACTIONS ###
114
115 my $last_status_id;
116
117 sub status($) {
118         print "GUI: ", $_[0], "\n" if $conn->{"Trace"};
119         defined $last_status_id and $status_bar->remove($bar_ctx, $last_status_id);
120         $last_status_id = $status_bar->push($bar_ctx, shift @_);
121 }
122
123 sub busy($) {
124         status($_[0]);
125         $window->window->set_cursor($busy_cursor);
126         $window->Gtk2::Gdk::flush;
127 }
128
129 sub ready($) {
130         status($_[0]);
131         $window->window->set_cursor(undef);
132         $window->Gtk2::Gdk::flush;
133 }
134
135 my $window_inited = 0;
136 sub init_refresh()
137 {
138         if (!$window_inited) {
139                 refresh(1);
140                 $window_inited = 1;
141         }
142         return 1;
143 }
144
145 sub timed_refresh()
146 {
147         refresh(0);     # FIXME: If-modified-since version?
148         return 1;       # We wish to re-run the timer
149 }
150
151 my $task_status_object;
152 my $task_parts = {};
153
154 sub recalc_task_list() {
155         $task_parts = {};
156         $task_store->clear;
157         foreach my $t ($task_status_object->getarray("(T")) {
158                 my $task = $t->get("T");
159                 foreach my $p ($t->getarray("(P")) {
160                         my $part = $p->get("P");
161                         $task_parts->{$task}->{$part} = $p;
162                         my $status = "---";
163                         my $iter = $task_store->append;
164                         $task_store->set($iter,
165                                 0, $task,
166                                 1, ($task eq $part ? "" : $part),
167                                 2, $status);
168                 }
169         }
170 }
171
172 sub refresh($)
173 {
174         my $force = shift @_;
175         if (!$conn->is_connected || $force) {
176                 busy("Connecting to server...");
177                 if ($conn->connect) {
178                         ready("Connected successfully");
179                 } else {
180                         ready($conn->{"error"});
181                 }
182         }
183         if ($conn->is_connected) {
184                 busy("Updating status...");
185                 my $r = new Sherlock::Object("!" => "STATUS");
186                 $r = $conn->request($r);
187                 if (!defined $r) {
188                         ready($conn->{"error"});
189                 } elsif ($r->get("-")) {
190                         ready($r->get("-"));
191                 } else {
192                         $task_status_object = $r;
193                         recalc_task_list;
194                         ready("Ready");
195                 }
196         }
197         if (!$conn->is_connected && !$force) {
198                 # Retry
199                 $conn->log("Retrying");
200                 refresh(1);
201         }
202 }