From: Martin Mares Date: Tue, 5 Jun 2007 16:45:18 +0000 (+0200) Subject: The first bits of the contest GUI. X-Git-Tag: python-dummy-working~385 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=65ff89923436ec785ce2b35d26827aa95ce8c3ce;p=eval.git The first bits of the contest GUI. --- diff --git a/submit/MO/Submit.pm b/submit/MO/Submit.pm index 0ae3f05..15e6d7c 100644 --- a/submit/MO/Submit.pm +++ b/submit/MO/Submit.pm @@ -16,6 +16,7 @@ sub new($) { my $mo = "$home/.mo"; my $root = $ENV{"MO_ROOT"} or die "Environment variable MO_ROOT not set\n"; my $self = { + "Contest" => "CPSPC 2007", "Server" => "localhost:8888", "Key" => "$mo/key.pem", "Cert" => "$mo/cert.pem", @@ -35,7 +36,7 @@ sub DESTROY($) { sub log($$) { my ($self, $msg) = @_; - print STDERR "LOG: $msg\n" if $self->{"Trace"}; + print STDERR "SUBMIT: $msg\n" if $self->{"Trace"}; } sub err($$) { diff --git a/submit/config b/submit/config index dfece60..8116349 100644 --- a/submit/config +++ b/submit/config @@ -39,7 +39,7 @@ Access { PlainText 0 # Maximum number of connections per IP address allowed - MaxConn 1 + MaxConn 2 } # Trace TLS parameters diff --git a/submit/contest b/submit/contest new file mode 100755 index 0000000..e9ebd68 --- /dev/null +++ b/submit/contest @@ -0,0 +1,202 @@ +#!/usr/bin/perl +# Contest UI for the MO Submitter +# (c) 2007 Martin Mares + +use strict; +use warnings; + +BEGIN { + defined $ENV{"MO_ROOT"} or die "Please set MO_ROOT to the contest root directory first.\n"; +} +use lib $ENV{"MO_ROOT"} . "/submit"; +use lib $ENV{"MO_ROOT"} . "/submit/lib/perl5"; + +use MO::Submit; +use Sherlock::Object; +use Gtk2 -init; + +my $conn = new MO::Submit; + +### GUI INITIALIZATION ### + +sub init_refresh(); +sub timed_refresh(); +sub refresh($); + +my $busy_cursor = Gtk2::Gdk::Cursor->new('watch'); + +# The main window +my $window = Gtk2::Window->new('toplevel'); +$window->signal_connect("delete-event" => sub { Gtk2->main_quit }); +$window->set_title($conn->{"Contest"} . " Submitter"); +$window->set_wmclass("submitter", "Submitter"); +$window->set_default_size(320, 400); + +# The title label +my $title_lab = Gtk2::Label->new; +$title_lab->set_markup("" . $conn->{"Contest"} . ""); + +# The row of buttons +my $b_submit = Gtk2::Button->new('Submit'); +$b_submit->signal_connect(clicked => sub { Gtk2->main_quit }); +$b_submit->set_sensitive(0); + +my $b_check = Gtk2::Button->new('Check'); +$b_check->signal_connect(clicked => sub { Gtk2->main_quit }); +$b_check->set_sensitive(0); + +my $b_refresh = Gtk2::Button->new('Refresh'); +$b_refresh->signal_connect(clicked => sub { refresh(0) }); + +my $button_box = Gtk2::HBox->new; +$button_box->pack_start_defaults($b_submit); +$button_box->pack_start_defaults($b_check); +$button_box->pack_start_defaults($b_refresh); +$button_box->set_border_width(5); + +# The list of tasks +my $task_store = Gtk2::ListStore->new('Glib::String', 'Glib::String', 'Glib::String'); + +my $task_view = Gtk2::TreeView->new($task_store); +my $task_renderer = Gtk2::CellRendererText->new; +my $task_col1 = Gtk2::TreeViewColumn->new_with_attributes("Task", $task_renderer, "text", 0); +$task_view->append_column($task_col1); +my $task_col2 = Gtk2::TreeViewColumn->new_with_attributes("Part", $task_renderer, "text", 1); +$task_view->append_column($task_col2); +my $task_col3 = Gtk2::TreeViewColumn->new_with_attributes("Status", $task_renderer, "text", 2); +$task_view->append_column($task_col3); +$task_view->set_headers_visible(0); + +my $task_scroll = Gtk2::ScrolledWindow->new; +$task_scroll->set_policy("automatic", "automatic"); +$task_scroll->add($task_view); +$task_scroll->set_border_width(5); + +my $task_frame = Gtk2::Frame->new("Tasks"); +$task_frame->add($task_scroll); + +my $selected_task; +my $task_sel = $task_view->get_selection; +$task_sel->set_mode('single'); +$task_sel->signal_connect(changed => sub { + my $iter = $_[0]->get_selected; + if ($iter) { + $selected_task = $task_store->get($iter, 0); + print "Selected $selected_task\n"; + $b_submit->set_sensitive(1); + $b_check->set_sensitive(1); + } else { + $selected_task = undef; + print "Deselected task\n"; + $b_submit->set_sensitive(0); + $b_check->set_sensitive(0); + } +}); + +my $status_bar = Gtk2::Statusbar->new; +my $bar_ctx = $status_bar->get_context_id('xyzzy'); + +my $vbox = Gtk2::VBox->new; +$vbox->pack_start($title_lab, 0, 0, 10); +$vbox->pack_start($task_frame, 1, 1, 0); +$vbox->pack_start($button_box, 0, 0, 0); +$vbox->pack_start($status_bar, 0, 0, 0); + +$window->add($vbox); +$window->signal_connect("expose-event" => sub { init_refresh(); return 0; }); +$window->show_all; + +Glib::Timeout->add(5000, \&timed_refresh); +Gtk2->main; +exit 0; + +### ACTIONS ### + +my $last_status_id; + +sub status($) { + print "GUI: ", $_[0], "\n" if $conn->{"Trace"}; + defined $last_status_id and $status_bar->remove($bar_ctx, $last_status_id); + $last_status_id = $status_bar->push($bar_ctx, shift @_); +} + +sub busy($) { + status($_[0]); + $window->window->set_cursor($busy_cursor); + $window->Gtk2::Gdk::flush; +} + +sub ready($) { + status($_[0]); + $window->window->set_cursor(undef); + $window->Gtk2::Gdk::flush; +} + +my $window_inited = 0; +sub init_refresh() +{ + if (!$window_inited) { + refresh(1); + $window_inited = 1; + } + return 1; +} + +sub timed_refresh() +{ + refresh(0); # FIXME: If-modified-since version? + return 1; # We wish to re-run the timer +} + +my $task_status_object; +my $task_parts = {}; + +sub recalc_task_list() { + $task_parts = {}; + $task_store->clear; + foreach my $t ($task_status_object->getarray("(T")) { + my $task = $t->get("T"); + foreach my $p ($t->getarray("(P")) { + my $part = $p->get("P"); + $task_parts->{$task}->{$part} = $p; + my $status = "---"; + my $iter = $task_store->append; + $task_store->set($iter, + 0, $task, + 1, ($task eq $part ? "" : $part), + 2, $status); + } + } +} + +sub refresh($) +{ + my $force = shift @_; + if (!$conn->is_connected || $force) { + busy("Connecting to server..."); + if ($conn->connect) { + ready("Connected successfully"); + } else { + ready($conn->{"error"}); + } + } + if ($conn->is_connected) { + busy("Updating status..."); + my $r = new Sherlock::Object("!" => "STATUS"); + $r = $conn->request($r); + if (!defined $r) { + ready($conn->{"error"}); + } elsif ($r->get("-")) { + ready($r->get("-")); + } else { + $task_status_object = $r; + recalc_task_list; + ready("Ready"); + } + } + if (!$conn->is_connected && !$force) { + # Retry + $conn->log("Retrying"); + refresh(1); + } +}