]> mj.ucw.cz Git - moe.git/commitdiff
The first bits of the contest GUI.
authorMartin Mares <mj@ucw.cz>
Tue, 5 Jun 2007 16:45:18 +0000 (18:45 +0200)
committerMartin Mares <mj@ucw.cz>
Tue, 5 Jun 2007 16:45:18 +0000 (18:45 +0200)
submit/MO/Submit.pm
submit/config
submit/contest [new file with mode: 0755]

index 0ae3f059d35c835c2be98e1e4e0f1e4e29a99b13..15e6d7c3584030291c0123b4d23045ac13a9ee64 100644 (file)
@@ -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($$) {
index dfece6082c900b79d8ad5cdc170160d4dffb8559..811634934e1a5edde4749362b94fa0f0d84ffcc3 100644 (file)
@@ -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 (executable)
index 0000000..e9ebd68
--- /dev/null
@@ -0,0 +1,202 @@
+#!/usr/bin/perl
+# Contest UI for the MO Submitter
+# (c) 2007 Martin Mares <mj@ucw.cz>
+
+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("<span size='x-large'>" . $conn->{"Contest"} . "</span>");
+
+# 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);
+       }
+}