#! /usr/local/bin/perl -w # (Updated: $Id: disamb-gui.pl,v 1.7 2006/12/24 12:18:47 sidz1979 Exp $) # # disamb-gui.pl version 0.09 # # Program that reads in a Senseval-2 formatted lexical sample file, and # disambiguates the instances using WordNet::SenseRelate::TargetWord. # # Copyright (c) 2005 # # Ted Pedersen, University of Minnesota, Duluth # tpederse@d.umn.edu # # Satanjeev Banerjee, Carnegie Mellon University # banerjee+@cs.cmu.edu # # Siddharth Patwardhan, University of Utah # sidd@cs.utah.edu # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # #----------------------------------------------------------------------------- # Uses: use strict; use WordNet::SenseRelate::Reader::Senseval2; use WordNet::SenseRelate::TargetWord; use WordNet::SenseRelate::Tools; use Getopt::Long; use Gtk; # Now get the options! our ($opt_config, $opt_wnpath, $opt_help, $opt_version); &GetOptions("config=s", "wnpath=s", "help", "version"); # My global variables my $VERSION = '0.09'; my $options = {}; my $lastDir = undef; my $instanceData = undef; my $wntools; my $targetWord; my $error; my $esColor = {}; my @warnings = (); my %posMap = ('n' => 'NOUN', 'v' => 'VERB', 'a' => 'ADJECTIVE', 'r' => 'ADVERB'); my %moduleNames = ('PREPROCESS' => ['WordNet::SenseRelate::Preprocess::Compounds'], 'POSTPROCESS' => [], 'CONTEXT' => ['WordNet::SenseRelate::Context::NearestWords'], 'ALGORITHM' => ['WordNet::SenseRelate::Algorithm::Local', 'WordNet::SenseRelate::Algorithm::Global', 'WordNet::SenseRelate::Algorithm::SenseOne', 'WordNet::SenseRelate::Algorithm::Random']); my %moduleOptions = ('WordNet::SenseRelate::Preprocess::Compounds' => {}, 'WordNet::SenseRelate::Context::NearestWords' => {'contextpos' => 's!!0!!nvar', 'windowsize' => 'i!!0!!5', 'windowstop' => 'f!!0!!'}, 'WordNet::SenseRelate::Algorithm::Local' => {'measure' => 'm!!0!!WordNet::Similarity::vector', 'measureconfig' => 'f!!0!!'}, 'WordNet::SenseRelate::Algorithm::Global' => {'measure' => 'm!!0!!WordNet::Similarity::vector', 'measureconfig' => 'f!!0!!'}, 'WordNet::SenseRelate::Algorithm::SenseOne' => {}, 'WordNet::SenseRelate::Algorithm::Random' => {}); # If help is requested if (defined $opt_help) { &printHelp(); exit; } # If version information is requested if (defined $opt_version) { &printVersion(); exit; } # Load configuration options, if config file specified. # (Pop warning message box, if error reading config file) # Else set up default configuration if(defined $opt_config) { # Make all the options undefined first $options = {}; $options->{preprocess} = []; $options->{preprocessconfig} = []; $options->{postprocess} = []; $options->{postprocessconfig} = []; $options->{context} = undef; $options->{contextconfig} = undef; $options->{algorithm} = undef; $options->{algorithmconfig} = undef; $options->{wntools} = undef; # Read the configuration file my $optStruct = &readConfigFile($opt_config); if (!defined $optStruct) { &askHelp("disamb.pl: Configuration file format error.\n"); $options = {}; } else { # Now get the options from the options structure # First, the preprocess modules and options if (defined $optStruct->{'PREPROCESS'}) { foreach my $element (@{$optStruct->{'PREPROCESS'}}) { push(@{$options->{preprocess}}, $element->{'name'}); delete $element->{'name'}; push(@{$options->{preprocessconfig}}, $element); } } # Next, the postprocess modules and options if (defined $optStruct->{'POSTPROCESS'}) { foreach my $element (@{$optStruct->{'POSTPROCESS'}}) { push(@{$options->{postprocess}}, $element->{'name'}); delete $element->{'name'}; push(@{$options->{postprocessconfig}}, $element); } } # Next, get the context selection module and options if (defined $optStruct->{'CONTEXT'}) { # There should be only one context selection module specified &askHelp("disamb.pl: Multiple context selection modules specified in configuration file. Using first.") if (scalar(@{$optStruct->{'CONTEXT'}}) > 1); # Get the context selection module name, and options # If none are specified, the default will be used my $element = shift(@{$optStruct->{'CONTEXT'}}); if (defined $element && defined $element->{'name'}) { $options->{context} = $element->{'name'}; delete $element->{'name'}; $options->{contextconfig} = $element; } } # Next, get the algorithm module and options if (defined $optStruct->{'ALGORITHM'}) { # Only one algorithm module must be specified &askHelp("disamb.pl: Multiple algorithm modules specified in configuration file. Using first.") if (scalar(@{$optStruct->{'ALGORITHM'}}) > 1); # Get the algorithm module name, and options # If none are specified, then the default will be used my $element = shift(@{$optStruct->{'ALGORITHM'}}); if (defined $element && defined $element->{'name'}) { $options->{algorithm} = $element->{'name'}; delete $element->{'name'}; $options->{algorithmconfig} = $element; } } } } # Load WordNet::SenseRelate::Tools... # Exit with warning message, if unable to load... print STDERR "Loading WordNet::SenseRelate::Tools... "; $wntools = WordNet::SenseRelate::Tools->new($opt_wnpath); if(!defined $wntools) { print STDERR "disamb-gui.pl: Unable to load WordNet::SenseRelate::Tools.\n"; print STDERR "Type \'disamb-gui.pl --help\' for help.\n"; exit; } print STDERR "done.\n"; $options->{'wntools'} = $wntools; # Load WordNet::SenseRelate::TargetWord... # Exit with warning message, if unable to load... print STDERR "Loading WordNet::SenseRelate::TargetWord... "; ($targetWord, $error) = WordNet::SenseRelate::TargetWord->new($options, 1); if (!defined $targetWord) { print STDERR "$error\n"; exit; } print STDERR "done.\n"; # Call "readXMLFile", if an argument was passed if(scalar(@ARGV) > 0) { print STDERR "Reading XML data... "; $instanceData = WordNet::SenseRelate::Reader::Senseval2->new($ARGV[0]); &askHelp("Error reading XML file.") if(!defined $instanceData); print STDERR "done.\n"; } # Initialize Gtk. print STDERR "Starting interface... \n"; set_locale Gtk; init Gtk; # Initialize colors $esColor->{'red'} = 0xFFFF; $esColor->{'green'} = 0xD000; $esColor->{'blue'} = 0xD000; my $cmap = Gtk::Gdk::Colormap->get_system(); &askHelp("Couldn't allocate green color.") unless(defined($cmap->color_alloc($esColor))); # Build the graphical user interface # Create the main window... my $window = Gtk::Window->new('toplevel'); $window->set_usize(800, 515); $window->set_policy(0, 0, 1); #$window->set_resizable(0); $window->signal_connect('destroy', sub{ Gtk->exit(0); }); $window->set_title("WordNet::SenseRelate::TargetWord"); $window->set_position('center'); $window->border_width(0); # Create a menubar my @menu_items = ( { path => '/_File', type => '' }, { path => '/File/_Open', accelerator => 'O', callback => \&readFileDialog }, { path => '/File/_Setup', accelerator => 'S', callback => \&setupDialog }, { path => '/File/sep1', type => ''}, { path => '/File/E_xit', callback => sub { Gtk->exit(0); } }, { path => '/_Help', type => '' }, { path => '/_Help/About', callback => \&showAbout } ); my $accel_group = new Gtk::AccelGroup(); my $item_factory = new Gtk::ItemFactory('Gtk::MenuBar', '
', $accel_group); $item_factory->create_items(@menu_items); $window->add_accel_group($accel_group); my $menubar = $item_factory->get_widget('
'); $menubar->show(); # Create a text input box my $textBox = Gtk::Text->new(); $textBox->set_usize(450, 200); $textBox->set_editable(0); $textBox->set_word_wrap(1); $textBox->set_line_wrap(1); $textBox->show(); # Create the scrollbar my $vscrollbar = Gtk::VScrollbar->new($textBox->vadj); $vscrollbar->show(); # Create a HBox my $textHBox = Gtk::HBox->new(0, 0); $textHBox->pack_end($vscrollbar, 0, 0, 0); $textHBox->pack_end($textBox, 0, 0, 0); $textHBox->show(); # Create instance label my $inLabel = Gtk::Label->new("Instance ID: \nLexical Element: \nAnswer: \nTarget part-of-speech:"); $inLabel->set_justify('left'); $inLabel->show(); my $inFrame = Gtk::Frame->new(""); $inFrame->add($inLabel); $inFrame->show(); # Create VBox for text and labels my $instanceVBox = Gtk::VBox->new(0, 5); $instanceVBox->pack_end($inFrame, 0, 0, 0); $instanceVBox->pack_start($textHBox, 1, 1, 0); $instanceVBox->show(); # Create clist my $clist = Gtk::CList->new_with_titles("Id", "Lexelt", "Target POS", " Answer"); $clist->set_selection_mode('browse'); $clist->set_column_justification(0, 'center'); $clist->set_column_justification(1, 'center'); $clist->set_column_justification(2, 'center'); $clist->set_column_justification(3, 'left'); $clist->set_column_width(0, 70); $clist->set_column_width(1, 70); $clist->set_column_width(2, 70); $clist->set_column_width(3, 110); $clist->column_titles_active(); $clist->show(); # Create a Scrolled Window for CList my $scrolled_window = Gtk::ScrolledWindow->new(); $scrolled_window->set_policy('automatic', 'always'); $scrolled_window->add($clist); $scrolled_window->show(); # Create HBox for clist-window and text-vbox my $readerHBox = Gtk::HBox->new(0, 0); $readerHBox->pack_end($instanceVBox, 0, 0, 0); $readerHBox->pack_start($scrolled_window, 1, 1, 0); $readerHBox->show(); # Create output Label my $outLabel = Gtk::Label->new("Selected Sense: "); $outLabel->set_justify('left'); $outLabel->show(); # Create output textbox my $outText = Gtk::Text->new(); $outText->set_usize(600, 50); $outText->set_editable(0); $outText->set_word_wrap(1); $outText->set_line_wrap(1); $outText->show(); # Create VBox for output my $outVBox = Gtk::VBox->new(0, 0); $outVBox->pack_start($outLabel, 0, 0, 0); $outVBox->pack_end($outText, 1, 1, 0); $outVBox->show(); # Create disambiguate button my $disambBox = Gtk::Button->new("Disambiguate"); $disambBox->show(); # Create table for button my $disambTable = Gtk::Table->new(3, 1, 1); $disambTable->attach_defaults($disambBox, 0, 1, 1, 2); $disambTable->show(); # Create HBox for button and output my $pHBox = Gtk::HBox->new(0, 0); $pHBox->pack_start($disambTable, 0, 0, 0); $pHBox->pack_end($outVBox, 1, 1, 0); $pHBox->show(); # Create frame my $pFrame = Gtk::Frame->new("Process"); $pFrame->add($pHBox); $pFrame->show(); # Create a VBox my $vbox = Gtk::VBox->new(0, 5); $vbox->pack_start($menubar, 0, 0, 0); $vbox->pack_start($readerHBox, 1, 1, 0); $vbox->pack_start($pFrame, 0, 0, 0); $vbox->show(); # Set up all the signals $clist->signal_connect('select_row', \&displayInstanceData); $disambBox->signal_connect('clicked', \&disambiguateInstance); # Show the main window $window->add($vbox); $window->show(); # Put the data onto the form &refreshGUI($instanceData); # Display warnings from startup, if any &displayStartupWarnings(@warnings) if(scalar(@warnings)); # Gtk event loop main Gtk; # Should never get here exit; # Create read Senseval file dialog sub readFileDialog { my $fDialog = Gtk::FileSelection->new("Select Senseval2 Lexical Sample File"); $fDialog->set_policy(0, 0, 1); # $fDialog->set_resizable(0); $fDialog->set_position('center'); $fDialog->border_width(0); $fDialog->set_modal(1); $fDialog->set_filename($lastDir) if(defined $lastDir); # Connect Signals $fDialog->ok_button->signal_connect("clicked", \&fileSelect, $fDialog); $fDialog->cancel_button->signal_connect("clicked", sub{ $fDialog->destroy(); }); # Display it $fDialog->show(); } # This function is a callback for the file # selection dialog. This is where the filename # selected by the user is determined. sub fileSelect { # Get the parameters my ($widget, $dialog) = @_; my $file; # The dialog pointer must be given return if(!defined $dialog); # Get the filename $file = $dialog->get_filename(); $lastDir = $file if(defined $file); $lastDir =~ s|\/[^\/]*$||; $lastDir .= "/"; $dialog->destroy(); # Read the file $instanceData = &readXMLFile($file); # Refresh the GUI with the new data && remove "Reading file... " window &refreshGUI($instanceData); } # This method loads a Senseval2 formatted XML file sub readXMLFile { my $fname = shift; # Show message box "Unable to read XML file" if not defined $fname && return if(!defined $fname) { &showMessageBox("Error", "Unable to read XML file."); return; } # Show "Reading file... " window my $messybox = Gtk::Window->new('dialog'); $messybox->set_usize(400, 100); $messybox->set_policy(0, 0, 1); # $messybox->set_resizable(0); $messybox->set_title("Information: Reading XML File... Please Wait."); $messybox->set_position('center'); $messybox->border_width(0); $messybox->set_modal(1); #my $mesLab = Gtk::Label->new("Reading XML file. Please Wait."); #$mesLab->set_justify('left'); #$mesLab->show(); my $mesLab = Gtk::Text->new(); $mesLab->set_usize(200, 50); $mesLab->set_editable(0); $mesLab->set_word_wrap(1); $mesLab->set_line_wrap(1); $mesLab->freeze(); $mesLab->insert(undef, undef, undef, "Reading XML file. Please Wait."); $mesLab->thaw(); $mesLab->show(); my $meshbox = Gtk::VBox->new(0, 20); $meshbox->pack_start($mesLab, 0, 0, 0); $meshbox->show(); $messybox->add($meshbox); $messybox->show_now(); # Read the XML file my $reader = WordNet::SenseRelate::Reader::Senseval2->new($fname); # Remove "Reading file... " window, && Show message box of errors, if any, && return $messybox->destroy(); if(!defined $reader || !ref($reader)) { &showMessageBox("Error", "Error reading XML file."); return; } return $reader; } # Refresh the GUI with new data sub refreshGUI { my $reader = shift; return if(!defined $reader); # Freeze the CList. $clist->freeze(); # Empty the CList. $clist->clear(); # Iterate through the data structure and # add the entries to the CList. foreach my $index (0 .. $reader->instanceCount() - 1) { my $theInst = $reader->instance($index); my $theID = ""; $theID = $theInst->{id} if(defined $theInst->{id}); my $theLexelt = ""; $theLexelt = $theInst->{lexelt} if(defined $theInst->{lexelt}); my $tPOS = "NOUN"; $tPOS = $theInst->{targetpos} if(defined $theInst->{targetpos}); $tPOS = $posMap{$theInst->{targetpos}} if(defined $theInst->{targetpos} && $theInst->{targetpos} =~ /^[nvar]$/); my $answerkey = ""; $answerkey = $theInst->{answer} if(defined $theInst->{answer}); $clist->append($theID, $theLexelt, $tPOS, $answerkey); } # Thaw the CList for the changes to suddenly # show up on screen. $clist->thaw(); } # Display the instance data of selected row sub displayInstanceData { my @selected = $clist->selection(); return if(scalar(@selected) <= 0); my $index = shift(@selected); $textBox->freeze(); my $selectedInstance = $instanceData->instance($index); return if(!defined $selectedInstance); # Delete all the text in there. my $tLength = $textBox->get_length(); $textBox->set_point($tLength); $textBox->backward_delete($tLength); foreach my $textindex (0 .. scalar(@{$selectedInstance->{text}}) - 1) { my $background = undef; $background = $esColor if($textindex == $selectedInstance->{head}); my $printedStuff = $selectedInstance->{text}->[$textindex]; $printedStuff =~ s/^\s+//; $printedStuff =~ s/\s+$//; $printedStuff =~ s/\[[^\]]*\]//g; $textBox->insert(undef, undef, $background, $printedStuff); $textBox->insert(undef, undef, undef, " "); } $textBox->thaw(); my $daID = ""; $daID = $selectedInstance->{id} if(defined $selectedInstance->{id}); my $daLexelt = ""; $daLexelt = $selectedInstance->{lexelt} if(defined $selectedInstance->{lexelt}); my $daAns = ""; $daAns = $selectedInstance->{answer} if(defined $selectedInstance->{answer}); my $daPos = "NOUN"; $daPos = $selectedInstance->{targetpos} if(defined $selectedInstance->{targetpos}); $daPos = $posMap{$selectedInstance->{targetpos}} if(defined $selectedInstance->{targetpos} && $selectedInstance->{targetpos} =~ /^[nvar]$/); $inLabel->set_text("Instance ID: $daID\nLexical Element: $daLexelt\nAnswer: $daAns\nTarget part-of-speech: $daPos"); } # Disambiguate the current instance sub disambiguateInstance { my @selected = $clist->selection(); return if(scalar(@selected) <= 0); my $index = shift(@selected); my $traceWindow = Gtk::Window->new('dialog'); $traceWindow->set_usize(500, 400); $traceWindow->set_policy(0, 0, 1); # $traceWindow->set_resizable(0); $traceWindow->set_title("Trace Information: Disambiguating Instance..."); $traceWindow->set_position('center'); $traceWindow->border_width(0); $traceWindow->set_modal(1); my $traceBox = Gtk::Text->new(); $traceBox->set_usize(480, 360); $traceBox->set_editable(0); $traceBox->set_word_wrap(1); $traceBox->set_line_wrap(1); $traceBox->show(); my $tracebar = Gtk::VScrollbar->new($traceBox->vadj); $tracebar->show(); my $traceHBox = Gtk::HBox->new(0, 0); $traceHBox->pack_end($tracebar, 0, 0, 0); $traceHBox->pack_end($traceBox, 0, 0, 0); $traceHBox->show(); my $closeButton = Gtk::Button->new("Close"); $closeButton->signal_connect('clicked', sub{ $traceWindow->destroy(); }); $closeButton->set_sensitive(0); $closeButton->show(); my $closeTable = Gtk::Table->new(1, 7); $closeTable->attach_defaults($closeButton, 3, 4, 0, 1); $closeTable->show(); my $traceVBox = Gtk::VBox->new(); $traceVBox->pack_start($traceHBox, 0, 0, 0); $traceVBox->pack_start($closeTable, 0, 0, 0); $traceVBox->show(); $traceWindow->add($traceVBox); $traceWindow->show_now(); my ($sense, $errorStr) = $targetWord->disambiguate($instanceData->instance($index)); $traceBox->insert(undef, undef, undef, $targetWord->getTraceString()); if(!defined $sense) { $traceWindow->destroy(); &showMessageBox("Error", $errorStr); return; } $outLabel->set_text("Selected sense: $sense"); $outText->freeze(); # Delete all the text in there. my $tLength = $outText->get_length(); $outText->set_point($tLength); $outText->backward_delete($tLength); $outText->insert(undef, undef, undef, $wntools->{wn}->querySense($sense, "glos")); $outText->thaw(); $traceWindow->set_title("Trace Information"); $closeButton->set_sensitive(1); $closeButton->show(); $traceWindow->show(); } # General purpose message box sub showMessageBox { my $title = shift; my $message = shift; return if(!defined $title || !defined $message); my $mbox = Gtk::Window->new('dialog'); $mbox->set_usize(400, 100); $mbox->set_policy(0, 0, 1); # $mbox->set_resizable(0); $mbox->set_title($title); $mbox->set_position('center'); $mbox->border_width(0); $mbox->set_modal(1); my $mesLabel = Gtk::Label->new($message); $mesLabel->show(); my $okButton = Gtk::Button->new("Ok"); $okButton->signal_connect('clicked', sub{ $mbox->destroy(); }); $okButton->show(); my $okTable = Gtk::Table->new(1, 5, 1); $okTable->attach_defaults($okButton, 2, 3, 0, 1); $okTable->show(); my $mesBox = Gtk::VBox->new(0, 20); $mesBox->pack_start($mesLabel, 0, 0, 0); $mesBox->pack_start($okTable, 0, 0, 0); $mesBox->show(); $mbox->add($mesBox); $mbox->show(); } # Create read setup options dialog sub setupDialog { # Create the setup window my $setupWindow = Gtk::Window->new('dialog'); $setupWindow->set_usize(600, 350); $setupWindow->set_policy(0, 0, 1); $setupWindow->set_title("WordNet::SenseRelate::TargetWord Setup: Select Modules"); $setupWindow->set_position('center'); $setupWindow->border_width(0); $setupWindow->set_modal(1); my $prelist = Gtk::CList->new_with_titles("Preprocess Modules"); $prelist->set_selection_mode('multiple'); $prelist->set_column_justification(0, 'center'); $prelist->set_column_width(0, 250); $prelist->column_titles_passive(); foreach my $mod (@{$moduleNames{'PREPROCESS'}}) { $prelist->append($mod); } $prelist->show(); # Create a Scrolled Window for CList my $scroll = Gtk::ScrolledWindow->new(); $scroll->set_policy('automatic', 'always'); $scroll->set_usize(300, 150); $scroll->add($prelist); $scroll->show(); my $postlist = Gtk::CList->new_with_titles("Postprocess Modules"); $postlist->set_selection_mode('extended'); $postlist->set_column_justification(0, 'center'); $postlist->set_column_width(0, 70); $postlist->column_titles_passive(); foreach my $mod (@{$moduleNames{'POSTPROCESS'}}) { $postlist->append($mod); } $postlist->show(); # Create a Scrolled Window for CList my $scroll2 = Gtk::ScrolledWindow->new(); $scroll2->set_policy('automatic', 'always'); $scroll2->set_usize(300,150); $scroll2->add($postlist); $scroll2->show(); # Create HBox for clist-window and text-vbox my $modHBox = Gtk::HBox->new(0, 0); $modHBox->pack_start($scroll, 0, 0, 0); $modHBox->pack_start($scroll2, 1, 1, 0); $modHBox->show(); my $conlist = Gtk::CList->new_with_titles("Context Modules"); $conlist->set_selection_mode('browse'); $conlist->set_column_justification(0, 'center'); $conlist->column_titles_passive(); foreach my $mod (@{$moduleNames{'CONTEXT'}}) { $conlist->append($mod); } $conlist->show(); # Create a Scrolled Window for CList my $scroll3 = Gtk::ScrolledWindow->new(); $scroll3->set_policy('automatic', 'always'); $scroll3->set_usize(300, 150); $scroll3->add($conlist); $scroll3->show(); my $algolist = Gtk::CList->new_with_titles("Algorithm Modules"); $algolist->set_selection_mode('browse'); $algolist->set_column_justification(0, 'center'); $algolist->column_titles_passive(); foreach my $mod (@{$moduleNames{'ALGORITHM'}}) { $algolist->append($mod); } $algolist->show(); # Create a Scrolled Window for CList my $scroll4 = Gtk::ScrolledWindow->new(); $scroll4->set_policy('automatic', 'always'); $scroll4->set_usize(300,150); $scroll4->add($algolist); $scroll4->show(); # Create HBox for clist-window and text-vbox my $modHBox2 = Gtk::HBox->new(0, 0); $modHBox2->pack_start($scroll3, 0, 0, 0); $modHBox2->pack_start($scroll4, 1, 1, 0); $modHBox2->show(); my $canButton = Gtk::Button->new("Cancel"); $canButton->show(); $canButton->signal_connect('clicked', sub{ $setupWindow->destroy(); }); my $nextButton = Gtk::Button->new("Next >"); $nextButton->show(); $nextButton->signal_connect('clicked', \&setupModuleOptions, $setupWindow, $prelist, $postlist, $conlist, $algolist); my $cTable = Gtk::Table->new(1, 5); $cTable->attach_defaults($canButton, 1, 2, 0, 1); $cTable->attach_defaults($nextButton, 3, 4, 0, 1); $cTable->show(); # Create VBox for clist-window and text-vbox my $modVBox = Gtk::VBox->new(0, 0); $modVBox->pack_start($modHBox, 0, 0, 0); $modVBox->pack_start($modHBox2, 1, 1, 0); $modVBox->pack_end($cTable, 0, 0, 0); $modVBox->show(); $setupWindow->add($modVBox); $setupWindow->show(); } sub setupModuleOptions { my $widget = shift; my $prevWindow = shift; my $prelist = shift; my $postlist = shift; my $conlist = shift; my $algolist = shift; my @preMods = (); my @postMods = (); my @conMod = (); my @algoMod = (); my %codes = ('i' => 'Integer', 'f' => 'File Name', 's' => 'String', 'm' => 'Module Name'); @preMods = $prelist->selection() if(defined $prelist); @postMods = $postlist->selection() if(defined $postlist); @conMod = $conlist->selection() if(defined $conlist); @algoMod = $algolist->selection() if(defined $algolist); $prevWindow->destroy(); my $setupWindow = Gtk::Window->new('dialog'); $setupWindow->set_usize(700, 350); $setupWindow->set_policy(0, 0, 1); $setupWindow->set_title("WordNet::SenseRelate::TargetWord Setup: Select Module Options"); $setupWindow->set_position('center'); $setupWindow->border_width(0); $setupWindow->set_modal(1); my $modVBox = Gtk::VBox->new(0, 0); my %textboxHash; my $moduleList = {preprocess => [], postprocess => [], context => undef, algorithm => undef}; foreach my $presel (@preMods) { my $mName = $moduleNames{'PREPROCESS'}->[$presel]; push(@{$moduleList->{preprocess}}, $mName); foreach my $oName (keys(%{$moduleOptions{$mName}})) { my $theCode = $moduleOptions{$mName}->{$oName}; my ($typo, $reqd, $defval) = split(/!!/, $theCode); my $label = Gtk::Label->new("$mName $oName ($codes{$typo}, ".(($reqd)?(""):("Not "))."Required) "); $label->show(); my $tbox = Gtk::Entry->new(); $tbox->set_text($defval) if(defined $defval && $defval ne ""); $tbox->show(); $textboxHash{$mName}{$oName} = $tbox; my $hhbox = Gtk::HBox->new(0, 0); $hhbox->pack_start($label, 0, 0, 0); $hhbox->pack_end($tbox, 1, 1, 0); $hhbox->show(); $modVBox->pack_start($hhbox, 0, 0, 0); } } foreach my $postsel (@postMods) { my $mName = $moduleNames{'POSTPROCESS'}->[$postsel]; push(@{$moduleList->{postprocess}}, $mName); foreach my $oName (keys(%{$moduleOptions{$mName}})) { my $theCode = $moduleOptions{$mName}->{$oName}; my ($typo, $reqd, $defval) = split(/!!/, $theCode); my $label = Gtk::Label->new("$mName $oName ($codes{$typo}, ".(($reqd)?(""):("Not "))."Required) "); $label->show(); my $tbox = Gtk::Entry->new(); $tbox->set_text($defval) if(defined $defval && $defval ne ""); $tbox->show(); $textboxHash{$mName}{$oName} = $tbox; my $hhbox = Gtk::HBox->new(0, 0); $hhbox->pack_start($label, 0, 0, 0); $hhbox->pack_end($tbox, 1, 1, 0); $hhbox->show(); $modVBox->pack_start($hhbox, 0, 0, 0); } } my $consel = shift(@conMod); if(defined $consel && $consel ne "") { my $mName = $moduleNames{'CONTEXT'}->[$consel]; $moduleList->{context} = $mName; foreach my $oName (keys(%{$moduleOptions{$mName}})) { my $theCode = $moduleOptions{$mName}->{$oName}; my ($typo, $reqd, $defval) = split(/!!/, $theCode); my $label = Gtk::Label->new("$mName $oName ($codes{$typo}, ".(($reqd)?(""):("Not "))."Required) "); $label->show(); my $tbox = Gtk::Entry->new(); $tbox->set_text($defval) if(defined $defval && $defval ne ""); $tbox->show(); $textboxHash{$mName}{$oName} = $tbox; my $hhbox = Gtk::HBox->new(0, 0); $hhbox->pack_start($label, 0, 0, 0); $hhbox->pack_end($tbox, 1, 1, 0); $hhbox->show(); $modVBox->pack_start($hhbox, 0, 0, 0); } } my $algosel = shift(@algoMod); if(defined $algosel && $algosel ne "") { my $mName = $moduleNames{'ALGORITHM'}->[$algosel]; $moduleList->{algorithm} = $mName; foreach my $oName (keys(%{$moduleOptions{$mName}})) { my $theCode = $moduleOptions{$mName}->{$oName}; my ($typo, $reqd, $defval) = split(/!!/, $theCode); my $label = Gtk::Label->new("$mName $oName ($codes{$typo}, ".(($reqd)?(""):("Not "))."Required) "); $label->show(); my $tbox = Gtk::Entry->new(); $tbox->set_text($defval) if(defined $defval && $defval ne ""); $tbox->show(); $textboxHash{$mName}{$oName} = $tbox; my $hhbox = Gtk::HBox->new(0, 0); $hhbox->pack_start($label, 0, 0, 0); $hhbox->pack_end($tbox, 1, 1, 0); $hhbox->show(); $modVBox->pack_start($hhbox, 0, 0, 0); } } my $canButton = Gtk::Button->new("Cancel"); $canButton->show(); $canButton->signal_connect('clicked', sub{ $setupWindow->destroy(); }); my $nextButton = Gtk::Button->new("Next >"); $nextButton->show(); $nextButton->signal_connect('clicked', \&getOptionsFromFields, $setupWindow, $moduleList, \%textboxHash); my $cTable = Gtk::Table->new(1, 5); $cTable->attach_defaults($canButton, 1, 2, 0, 1); $cTable->attach_defaults($nextButton, 3, 4, 0, 1); $cTable->show(); # Create VBox for clist-window and text-vbox $modVBox->pack_end($cTable, 0, 0, 0); $modVBox->show(); $setupWindow->add($modVBox); $setupWindow->show(); } sub getOptionsFromFields { my $widget = shift; my $prevWindow = shift; my $modList = shift; my $textList = shift; $modList->{preprocessconfig} = []; $modList->{postprocessconfig} = []; $modList->{contextconfig} = undef; $modList->{algorithmconfig} = undef; $modList->{wntools} = $wntools; foreach my $premod ($modList->{preprocess}) { my $modOptions = {}; if(exists $textList->{$premod}) { foreach my $theopt (keys %{$textList->{$premod}}) { my $theText = $textList->{$premod}->{$theopt}->get_text(); $modOptions->{$theopt} = $theText if(defined $theText && $theText ne ""); } } push(@{$modList->{preprocessconfig}}, $modOptions); } foreach my $premod ($modList->{postprocess}) { my $modOptions = {}; if(exists $textList->{$premod}) { foreach my $theopt (keys %{$textList->{$premod}}) { my $theText = $textList->{$premod}->{$theopt}->get_text(); $modOptions->{$theopt} = $theText if(defined $theText && $theText ne ""); } } push(@{$modList->{postprocessconfig}}, $modOptions); } my $conmod = $modList->{context}; if(defined $conmod && $conmod ne "") { my $modOptions = {}; if(exists $textList->{$conmod}) { foreach my $theopt (keys %{$textList->{$conmod}}) { my $theText = $textList->{$conmod}->{$theopt}->get_text(); $modOptions->{$theopt} = $theText if(defined $theText && $theText ne ""); } } $modList->{contextconfig} = $modOptions; } $conmod = $modList->{algorithm}; if(defined $conmod && $conmod ne "") { my $modOptions = {}; if(exists $textList->{$conmod}) { foreach my $theopt (keys %{$textList->{$conmod}}) { my $theText = $textList->{$conmod}->{$theopt}->get_text(); $modOptions->{$theopt} = $theText if(defined $theText && $theText ne ""); } } $modList->{algorithmconfig} = $modOptions; } $prevWindow->destroy(); # Load WordNet::SenseRelate::TargetWord... # Exit with warning message, if unable to load... # Show "Loading TargetWord... " window my $messybox = Gtk::Window->new('dialog'); $messybox->set_usize(400, 100); $messybox->set_policy(0, 0, 1); # $messybox->set_resizable(0); $messybox->set_title("Information: Reloading WordNet::SenseRelate::TargetWord... Please Wait."); $messybox->set_position('center'); $messybox->border_width(0); $messybox->set_modal(1); #my $mesLab = Gtk::Label->new("Reading XML file. Please Wait."); #$mesLab->set_justify('left'); #$mesLab->show(); my $mesLab = Gtk::Text->new(); $mesLab->set_usize(200, 50); $mesLab->set_editable(0); $mesLab->set_word_wrap(1); $mesLab->set_line_wrap(1); $mesLab->freeze(); $mesLab->insert(undef, undef, undef, "Reloading WordNet::SenseRelate::TargetWord. Please Wait."); $mesLab->thaw(); $mesLab->show(); my $meshbox = Gtk::VBox->new(0, 20); $meshbox->pack_start($mesLab, 0, 0, 0); $meshbox->show(); $messybox->add($meshbox); $messybox->show_now(); my ($newTargetWord, $newError) = WordNet::SenseRelate::TargetWord->new($modList, 1); # Remove "Reloading... " window, && Show message box of errors, if any, && return $messybox->destroy(); if(!defined $newTargetWord || !ref($newTargetWord)) { &showMessageBox("Error", "Error loading module: $newError"); return; } $targetWord = $newTargetWord; } # Create Help->About window sub showAbout { # Create the about window my $about = Gtk::Window->new('dialog'); $about->set_usize(360, 250); $about->set_policy(0, 0, 1); $about->set_title("About WordNet::SenseRelate::TargetWord"); $about->set_position('center'); $about->border_width(0); $about->set_modal(1); # Create a TextBox my $aboutText = Gtk::Text->new(); $aboutText->set_editable(0); $aboutText->set_word_wrap(1); $aboutText->set_line_wrap(1); $aboutText->set_usize(360, 220); my $name = "-misc-fixed-bold-r-normal--15-140-75-75-c-90-iso8859-1"; my $fixed_font = Gtk::Gdk::Font->load($name); $aboutText->insert($fixed_font, undef, undef, "\n WordNet::SenseRelate::TargetWord\n\n"); $name = "-misc-fixed-medium-r-normal--14-130-75-75-c-70-iso8859-1"; $fixed_font = Gtk::Gdk::Font->load($name); $aboutText->insert($fixed_font, undef, undef, " v$VERSION\n"); $aboutText->insert($fixed_font, undef, undef, " Copyright (c) 2005\n\n"); $aboutText->insert($fixed_font, undef, undef, " Ted Pedersen\n"); $aboutText->insert($fixed_font, undef, undef, " tpederse\@d.umn.edu\n\n"); $aboutText->insert($fixed_font, undef, undef, " Siddharth Patwardhan\n"); $aboutText->insert($fixed_font, undef, undef, " sidd\@cs.utah.edu\n\n"); $aboutText->insert($fixed_font, undef, undef, " Satanjeev Banerjee\n"); $aboutText->insert($fixed_font, undef, undef, " banerjee+\@cs.cmu.edu\n"); $aboutText->show(); # Create a close Button my $aboutButton = Gtk::Button->new("Close"); $aboutButton->signal_connect('clicked', sub{ $about->destroy(); }); $aboutButton->show(); # Create a VBox my $aboutVBox = Gtk::VBox->new(0, 5); $aboutVBox->pack_start($aboutText, 0, 0, 0); $aboutVBox->pack_start($aboutButton, 0, 0, 0); $aboutVBox->show(); # Display it $about->add($aboutVBox); $about->show(); } # Show startup warnings sub displayStartupWarnings { return if(scalar(@_) <= 0); my $mbox = Gtk::Window->new('dialog'); $mbox->set_usize(400, 150); $mbox->set_policy(0, 0, 1); # $mbox->set_resizable(0); $mbox->set_title("Warning(s)"); $mbox->set_position('center'); $mbox->border_width(0); $mbox->set_modal(1); my $message = "Warning(s):\n".(join("\n", @_))."\n"; my $mesLabel = Gtk::Label->new($message); $mesLabel->show(); my $okButton = Gtk::Button->new("Ok"); $okButton->signal_connect('clicked', sub{ $mbox->destroy(); }); $okButton->show(); my $okTable = Gtk::Table->new(1, 5, 1); $okTable->attach_defaults($okButton, 2, 3, 0, 1); $okTable->show(); my $mesBox = Gtk::VBox->new(0, 20); $mesBox->pack_start($mesLabel, 0, 0, 0); $mesBox->pack_start($okTable, 0, 0, 0); $mesBox->show(); $mbox->add($mesBox); $mbox->show(); } # Subroutine that reads the options file sub readConfigFile { my $fname = shift; if(!open(CONFIG, "$fname")) { &askHelp("disamb-gui.pl: Unable to open specified configuration file."); return undef; } my $line = ; $line =~ s/[\r\f\n]//; $line =~ s/^\s+//; $line =~ s/\s+$//; if ($line !~ /^WordNet::SenseRelate::TargetWord$/) { &askHelp("disamb.pl: File format error (in header) in config file."); return undef; } my $struct = {}; my $section = ""; my $modname = ""; my $modata = undef; while ($line = ) { $line =~ s/[\r\f\n]//; $line =~ s/\#.*//; $line =~ s/^\s+//; $line =~ s/\s+$//; if ($line =~ /\[SECTION:([^\]]*)\]/) { $section = $1; $struct->{$section} = [] if ( defined $section && $section ne "" && !exists($struct->{$section})); } elsif ($line =~ /\[START\s+([^\]]+)\]/) { return undef if (!defined $section || $section eq ""); $modname = $1; $modata = {}; } elsif ($line =~ /\[END\]/) { return undef if ( !defined $section || $section eq "" || !defined $modname || $modname eq ""); return undef if (!defined $modata); $modata->{'name'} = $modname; push(@{$struct->{$section}}, $modata); $modname = ""; $modata = undef; } elsif ($line =~ /([^=]+)\s*=\s*([^=]+)/) { return undef if ( !defined $section || !defined $modname || $section eq "" || $modname eq ""); $modata->{$1} = $2; } elsif ($line ne "") { return undef; } } close(CONFIG); return $struct; } # function to output help messages for this program sub printHelp { print "Performs Word Sense Disambiguation on Senseval-2 lexical sample data\n"; print "(graphical interface to WordNet::SenseRelate::TargetWord).\n"; print "Usage: disamb-gui.pl [ [--config FILE] [--wnpath WNPATH] [XMLFILE] | --help | --version]\n"; print "--config Specifies a configuration file (FILE) to set up the\n"; print " various configuration options.\n"; print "--wnpath WNPATH specifies the path of the WordNet data files.\n"; print " Ordinarily, this path is determined from the \$WNHOME\n"; print " environment variable. But this option overides this\n"; print " behavior.\n"; print "--help Displays this help screen.\n"; print "--version Displays version information.\n\n"; } # function to output "ask for help" message when the user's goofed up! sub askHelp { my $message = shift; push(@warnings, $message) if (defined $message && $message ne ""); } # Subroutine to print the version information sub printVersion { print "disamb-gui.pl version $VERSION\n"; print "Copyright (c) 2005 Ted Pedersen, Satanjeev Banerjee, and Siddharth Patwardhan.\n"; } __END__ =head1 NAME disamb-gui.pl - graphical interface for WordNet::SenseRelate::TargetWord, a Word Sense Disambiguation module. =head1 SYNOPSIS disamb-gui.pl [ [--config FILE] [--wnpath WNPATH] [XMLFILE] | --help | --version ] =head1 DESCRIPTION This program is a graphical interface to the WordNet::SenseRelate::TargetWord Word Sense Disambiguation module. It takes as input a Senseval-2 formatted input file and disambiguated each instance specified in file. The module is highly configurable. The user is allowed to choose different preprocessing and postprocessing tasks for the data, the dismabiguation algorithm and the context selection algorithm. =head1 OPTIONS Usage: disamb-gui.pl [ [--config FILE] [--wnpath WNPATH] [XMLFILE] | --help | --version ] B<--config>=I Specifies a configuration file (FILE) to set up the various configuration options. B<--wnpath>=I WNPATH specifies the path of the WordNet data files. Ordinarily, this path is determined from the $WNHOME environment variable. But this option overides this behavior. B<--help> Displays this help screen. B<--version> Displays version information. =head1 AUTHORS Ted Pedersen, University of Minnesota, Duluth tpederse at d.umn.edu Siddharth Patwardhan, University of Utah, Salt Lake City sidd at cs.utah.edu Satanjeev Banerjee, Carnegie Mellon University, Pittsburgh banerjee+ at cs.cmu.edu =head1 KNOWN BUGS None. =head1 SEE ALSO I(1pm) I(3pm) I(3pm) L L L =head1 COPYRIGHT Copyright (c) 2005 Ted Pedersen, Siddharth Patwardhan, Satanjeev Banerjee This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =cut