summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoretienne2015-12-30 15:00:21 +0000
committeretienne2015-12-30 15:00:21 +0000
commit6265c3a3a8dc28a04f4e76893c22bcf6f0664b77 (patch)
tree289e209cc53637c873952830a2de7f2b94b7bc97 /src
parent4ff70bb45789dc21d853f6539c4b000401cded03 (diff)
downloadivymon-6265c3a3a8dc28a04f4e76893c22bcf6f0664b77.zip
ivymon-6265c3a3a8dc28a04f4e76893c22bcf6f0664b77.tar.gz
ivymon-6265c3a3a8dc28a04f4e76893c22bcf6f0664b77.tar.bz2
ivymon-6265c3a3a8dc28a04f4e76893c22bcf6f0664b77.tar.xz
* ivymon :
. New option -buf for bufferizing messages from the begining. Use this option to minimize processings when ivymon is intended to receive very large flows of messages. You can always display them later using the "Scroll" button. . The -history option now accepts 3 types of value : . N => only the N first received messages are kept (unchanged) . Nm => only the messages received during the N first minutes are kept . infinite => all received messages are kept (according to memory capacity) . New option -verbose. . Improved bufferized mode management (in save function, etc.). . Fix : crash during input file loading. . Loggued ivymon bindings changes. . Added a button to enlarge the "Bindings" frame. . Added a status bar. . Added some ballon help informations. . Minor fixes. * ivyreplay : . Updated code to take into account new ivymon tags. . Minor fixes.
Diffstat (limited to 'src')
-rwxr-xr-xsrc/ivymon1262
-rwxr-xr-xsrc/ivyreplay79
2 files changed, 904 insertions, 437 deletions
diff --git a/src/ivymon b/src/ivymon
index c1f2592..052b8d1 100755
--- a/src/ivymon
+++ b/src/ivymon
@@ -83,6 +83,7 @@ use Tk::FBox;
use Tk::ErrorDialog;
use Tk::Dialog;
use Tk::ProgressBar;
+use Tk::ProgressBar;
use Sys::Hostname;
use Time::HiRes qw(gettimeofday);
use Ivy;
@@ -90,10 +91,10 @@ use Carp;
use strict;
use Getopt::Long;
use Tk::CmdLine;
-use vars qw/$VERSION $opt_help $opt_b $opt_bus $opt_history @opt_bind
- @opt_send $opt_size $opt_undersize $opt_out $opt_debug/;
+use vars qw/$VERSION $opt_help $opt_b $opt_bus $opt_history @opt_bind $opt_verbose
+ @opt_send $opt_size $opt_undersize $opt_out $opt_debug $opt_buf/;
# **** VERSION ****
-$VERSION = '1.23';
+$VERSION = '1.25';
# options initialisation
# geometry
@@ -103,11 +104,14 @@ my $smallsized = 0;
my $coef = 1;
my $ivy_port; # undef:=> default value is treated by ivy-perl
-my $history = 200000;
+my $historynumber = 0; # history messages number
+my $infinitehistory = 0; # set to 1 if infinite
+my $historyduration = 60; # history duration in minutes
+my $historylabel = "$historyduration minutes"; # history label
+
my $casesensitiveflag = 1;
my $regexpflag = 0;
# misc
-my $enlarge = 0;
my $hostname = hostname();
my %clientsMessagesTpl;
my %connectedClients;
@@ -137,31 +141,41 @@ my $bindHistoryIndex = -1;
my $clockbackwardflag = 0;
my @packinfo = ();
-my @messagesbuffer;
+my @databuffer;
my $markers_cnt = 0;
-# displayed messages counters
-my $messagesNumber = 0;
-my $messagesLastNumber = 0;
-my $messagesSpeed = 0;
-my $recordedNumber = 0;
-my $deletedNumber = 0;
-my $bufNumber = 0;
+# messages counters
+my $messagesLastNumber = 0; # counter used to compute reception instantaneous speed
+my $messagesSpeed = 0; # reception instantaneous speed
+my $displayedNumber = 0; # displayed messages number (comments and markers are ignored)
+my $deletedNumber = 0; # deleted messages number
+my $bufNumber = 0; # bufferized messages number (comments and markers are ignored, so
+ # $bufNumber <= scalar(@databuffer))
+
+# messages sizes (for verbose mode)
+my $bufSize = 0;
+my $displayedSize = 0;
my $bindingsFlag = 0;
-my $stopFlag = 0;
+my $bufmode = 0;
my $noMessageYet = 1;
my $jump_cnt = 0;
-my $outputfile;
+my $startingtime;
+my $runningtime_min;
+my $runningtime_str;
+
+my $outputfile; # effective output file
+my $ivyoutputfile; # outputfile get by ivy
+my $datasaved;
+my $fileloaded;
my $noUpdateFlag = 0;
-my $loadedFileFlag = 0;
my $loadingFlag = 0;
-my $appname = 'IvyMon';
-$appname =~ s/ /_/g;
+my $myappname = 'IvyMon';
+$myappname =~ s/ /_/g;
# messages array
my @send_def;
@@ -182,28 +196,30 @@ Tk::CmdLine::SetArguments(-font =>
Tk::CmdLine::SetArguments();
if (not GetOptions('-help', '-history=s', '-b=s', '-bus=s', '-bind=s@',
- '-send=s@', '-size=s', '-undersize', '-debug',
+ '-send=s@', '-size=s', '-undersize', '-debug', '-buf', '-verbose',
'-out=s') or $opt_help) {
print "\n";
print "IvyMon version $VERSION\n";
print "\n";
print "Usage: ivymon [-b[us] bus] [-help] [-history length]\n";
- print " [-size size] [-undersize] [-debug]\n";
+ print " [-size size] [-undersize] [-debug] [-buf]\n";
print " [-bind regexp1] ... [-bind regexpN] \n";
print " [-send message1] ... [-send messageN] \n";
- print " [-out outputfile] [standard X11 options...]\n";
+ print " [-out outputfile] [-verbose] [standard X11 options...]\n";
print " [inputfile]\n";
print "\n";
print "Options :\n";
print " -b <[addr]:port> Ivy bus (\$IVYBUS by default)\n";
print " -history <length> Messages list history length\n";
- print " ($history messages by default)\n";
+ print " ($historylabel by default)\n";
print " -size <VGA|SVGA|XGA|SXGA|UXGA> Size of the main window\n";
print " -undersize If set, slightly reduces the main window\n";
print " -bind <regexp> Ivy binding regular expression\n";
print " ((.*) by default)\n";
print " -send <string> Ivy message to send\n";
- print " -out <file> output filename\n";
+ print " -buf No message displayed; all are bufferized\n";
+ print " -out <file> Output filename\n";
+ print " -verbose Periodically print informations on stdout\n";
print "\n";
exit ;
@@ -213,7 +229,26 @@ if ($opt_bus) {
} elsif ($opt_b) {
$ivy_port = $opt_b;
}
-$history = $opt_history if $opt_history;
+if ($opt_history) {
+ if ($opt_history =~ /^(\d+)m$/) {
+ my $m = $1;
+ $m = 1 if $m == 0;
+ my $s = "s" if $m > 1;
+ $historylabel = "$m minute".$s;
+ $historyduration = $m;
+ } elsif ($opt_history =~ /^(\d+)$/) {
+ $historynumber = $opt_history;
+ $historylabel = "$historynumber msgs";
+ $historyduration = undef;
+ } elsif ($opt_history eq "infinite") {
+ $infinitehistory = 1;
+ $historylabel = "all msgs";
+ } else {
+ print "Bad value (=$opt_history) for -history option.\n";
+ exit 1;
+ }
+}
+
my $title;
my $ivy_version = $Ivy::VERSION;
my $ivy_cvsrevision = 0;
@@ -348,20 +383,48 @@ my $top_fm =
-expand => 1,
-padx => 5*$coef, -pady => 5*$coef);
+$mw->Frame(-height => 5)->pack(-fill => 'both',
+ -side => 'bottom',
+ );
+my $status_fm =
+ $mw->Frame()->pack(-fill => 'both',
+ -side => 'bottom',
+ -expand => 0,
+ -padx => 5*$coef);
+$status_fm->Label(-text => "Status : ")->pack(-fill => 'both',
+ -side => 'left',
+ -expand => 0,
+ );
my $bottom_fm =
$mw->Frame()->pack(-fill => 'both',
-side => 'bottom',
-expand => 0,
-padx => 5*$coef, -pady => 5*$coef,
);
+
my $bindings_fm =
- $bottom_fm->LabFrame(-label => 'Bindings : ',
+ $bottom_fm->eLabFrame(-label => 'Bindings : ',
+ -buttonbmp => $enlargebmp,
-labelside => 'acrosstop',
-borderwidth => 3)->pack(-fill => 'both',
-side => 'left',
-padx => 5*$coef,
-expand => 0,
);
+my $bindingsEnlargeBtn = $bindings_fm->Subwidget('button');
+$bindingsEnlargeBtn->{enlarge} = 0;
+$bindingsEnlargeBtn->configure(-relief => 'flat',
+ -command => sub {
+ if ($bindingsEnlargeBtn->{enlarge}) {
+ &shrink_bindingsfm;
+ $bindingsEnlargeBtn->{enlarge} = 0;
+ $bindingsEnlargeBtn->configure(-image => $enlargebmp);
+ } else {
+ &enlarge_bindingsfm;
+ $bindingsEnlargeBtn->{enlarge} = 1;
+ $bindingsEnlargeBtn->configure(-image => $shrinkbmp);
+ }
+ });
my $clients_fm =
$bottom_fm->LabFrame(-label => 'Applications : ',
-labelside => 'acrosstop',
@@ -380,15 +443,16 @@ my $send_fm =
-padx => 5*$coef,
);
my $sendEnlargeBtn = $send_fm->Subwidget('button');
+$sendEnlargeBtn->{enlarge} = 0;
$sendEnlargeBtn->configure(-relief => 'flat',
-command => sub {
- if ($enlarge) {
- &shrink;
- $enlarge = 0;
+ if ($sendEnlargeBtn->{enlarge}) {
+ &shrink_sendfm;
+ $sendEnlargeBtn->{enlarge} = 0;
$sendEnlargeBtn->configure(-image => $enlargebmp);
} else {
- &enlarge;
- $enlarge = 1;
+ &enlarge_sendfm;
+ $sendEnlargeBtn->{enlarge} = 1;
$sendEnlargeBtn->configure(-image => $shrinkbmp);
}
});
@@ -414,27 +478,26 @@ my $control_fm =
#----------------------------------------------------------------------------------
# Progress bar
#----------------------------------------------------------------------------------
-my $tpl = $mw->Toplevel;
-$tpl->Popup;
-$tpl->raise($mw);
-$tpl->title("");
-$tpl->geometry("300x50");
+my $progressbar_tpl = $mw->Toplevel;
+$progressbar_tpl->geometry("300x50");
+$progressbar_tpl->title("");
+my $progressbar_step;
my $progressbar =
- $tpl->ProgressBar(-from => 0,
- -length => 200,
- -borderwidth => 2,
- -colors => [ 0 => 'yellow'],
- -relief => 'sunken',
- -resolution => 0,
- -anchor => 'w',
- )->pack(-fill => 'both',
- -expand => 1,
- );
+ $progressbar_tpl->ProgressBar(-from => 0,
+ -length => 200,
+ -borderwidth => 2,
+ -colors => [ 0 => 'yellow'],
+ -relief => 'sunken',
+ -resolution => 0,
+ -anchor => 'w',
+ )->pack(-fill => 'both',
+ -expand => 1,
+ );
$progressbar->value(0);
-$tpl->withdraw;
+$progressbar_tpl->withdraw;
#----------------------------------------------------------------------------------
-# Messages display area
+# Messages display frame
#----------------------------------------------------------------------------------
my $top2_fm = $top_fm->Frame()->pack(-side => 'top',
-fill => 'x',
@@ -443,12 +506,12 @@ my $messagesLabel =
$top2_fm->Label(-text => "Messages :")->pack(-side => 'left');
my $messagesCounterValue =
- $top2_fm->Label(-textvariable => \$recordedNumber,
+ $top2_fm->Label(-textvariable => \$displayedNumber,
-width => 8,
-anchor => 'w')->pack(-side => 'right');
my $messagesCounterLabel =
- $top2_fm->Label(-text => "Recorded :",
+ $top2_fm->Label(-text => "Displayed :",
-width => 15,
-anchor => 'e')->pack(-side => 'right');
@@ -468,12 +531,12 @@ my $messagesDeletedValue =
-anchor => 'w')->pack(-side => 'right');
my $messagesDeletedLabel =
- $top2_fm->Label(-text => "Skipped :",
+ $top2_fm->Label(-text => "Lost :",
-width => 14,
-anchor => 'e')->pack(-side => 'right');
my $messagesMaxLabel =
- $top2_fm->Label(-text => "Recordable : $history",
+ $top2_fm->Label(-text => "Recordable : $historylabel",
-width => 25)->pack(-side => 'right');
my $messagesText =
@@ -496,6 +559,12 @@ $messagesText->tagBind('sender', '<Double-1>', \&marker);
my $bgcolor = $messagesText->cget(-background);
# text tag creation
+# . 1 sender tag
+# . 1 time tag
+# . 1 ivymon special tag
+# . 5 markers tags
+# . 1 hidden tag
+# . 1 comment tag
$messagesText->tagConfigure('sender',
-background => 'gray50',
-foreground => 'gray90');
@@ -506,7 +575,7 @@ if ($Tk::VERSION ge 804) {
@hide_option = (-state => 'hidden');
}
$messagesText->tagConfigure('time', @hide_option);
-$messagesText->tagConfigure($appname, -foreground => 'gray30');
+$messagesText->tagConfigure($myappname, -foreground => 'gray30');
$messagesText->tagConfigure('marker0', -background => 'lightcoral',
-foreground => 'lightcoral');
$messagesText->tagConfigure('marker1', -background => 'LightGoldenrod',
@@ -517,34 +586,93 @@ $messagesText->tagConfigure('marker3', -background => 'darkseagreen',
-foreground => 'darkseagreen');
$messagesText->tagConfigure('marker4',
-background => 'ivory', -foreground => 'ivory');
+$messagesText->tagConfigure('hidden', @hide_option);
+$messagesText->tagConfigure('comment', -foreground => 'gray30');
for my $marker (qw(marker0 marker1 marker2 marker3 marker4)) {
$messagesText->tagBind($marker, '<Double-1>', \&marker);
}
-
+$startingtime = time();
# check received messages speed and adjust drawing frequency
$messagesCounterValue->repeat(1000, sub {
- $messagesSpeed = $messagesNumber - $messagesLastNumber;
- $messagesLastNumber = $messagesNumber;
- # if update mechanism is off, we flush data here
- if ($noUpdateFlag) {
- $messagesText->see('end');
- $messagesCounterValue->update;
+ my $receivedNumber = $displayedNumber + $bufNumber;
+ $messagesSpeed = $receivedNumber - $messagesLastNumber;
+ $messagesLastNumber = $receivedNumber;
+ # if update mechanism is off, we flush data here if necessary
+ if ($noUpdateFlag and $deletedNumber == 0 and not $bufmode) {
+ $messagesText->see('end');
+ $messagesCounterValue->idletasks;
}
# if too many messages, update mechanism is unset
if ($messagesSpeed > 50) {
- $noUpdateFlag = 1;
+ $noUpdateFlag = 1;
#print "$messagesSpeed received messages/second !\n";
# in nominal case, update mechanism is set
# (each time a message is received, update is forced in Text window)
} else {
- $noUpdateFlag = 0;
+ $noUpdateFlag = 0;
+ }
+ my $dt = time() - $startingtime;
+ $runningtime_min = int($dt / 60);
+ if ($dt < 3600) { # < 1 hour
+ $runningtime_str = sprintf("%d min", $runningtime_min);
+ } else {
+ my $hour = int($dt / 3600);
+ my $min = int(($dt % 3600) / 60);
+ $runningtime_str = sprintf("%02dh%02dm", $hour, $min);
}
});
+# print some informations on stdout
+if ($opt_verbose) {
+ eval { require Proc::ProcessTable; };
+ my $procfunc;
+ if ($@) {
+ print "warning : install Proc::ProcessTable to have memory and cpu usage report\n";
+ } else {
+ my $mypid = $$;
+ $procfunc = sub {
+ my $pt = Proc::ProcessTable->new;
+ for my $proc (@{$pt->table}) {
+ return ", mem=".$proc->pctmem."%, cpu=".$proc->pctcpu."%" if $proc->pid == $mypid;
+ }
+ };
+ }
+ $mw->repeat(10000, sub {
+ my $dt = time() - $startingtime;
+ my $h = int($dt / 3600);
+ my $s = $dt % 3600;
+ my $m = int($s / 60);
+ $s = $dt - $h * 3600 - $m * 60;
+ my $t = sprintf("%02d:%02d:%02d", $h, $m, $s);
+ my $bsizefmt = &fmt_size($bufSize);
+ my $dsizefmt = &fmt_size($displayedSize);
+ my $procinfo = &$procfunc if defined $procfunc;
+ print "Running_time=$t, bufferized=$bufNumber($bsizefmt), ".
+ "displayed=$displayedNumber($dsizefmt), lost=$deletedNumber ".
+ "$procinfo\n";
+ });
+}
+
#----------------------------------------------------------------------------------
-# Bindings area
+# Status frame
+#----------------------------------------------------------------------------------
+my $status_lb =
+ $status_fm->Label(-anchor => 'w', -bg => 'gray92')->pack(-fill => 'both',
+ -side => 'left',
+ -expand => 1,
+ );
+$status_fm->Label(-text => " Running time : ")->pack(-fill => 'both',
+ -side => 'left',
+ -expand => 0,
+ );
+$status_fm->Label(-bg => 'gray92', -textvariable => \$runningtime_str)->pack(-fill => 'both',
+ -side => 'left',
+ -expand => 0,
+ );
+#----------------------------------------------------------------------------------
+# Bindings frame
#----------------------------------------------------------------------------------
my $bindingsEntry =
$bindings_fm->Entry(-width => 30*$coef)->pack(-fill => 'x',
@@ -564,22 +692,25 @@ $bindingsEntry->bind('<Control-p>' => [\&bindingPrevExpression]);
$bindingsEntry->focus;
my $bindingsList =
- $bindings_fm->Scrolled('Listbox',
+ # need intermediate frame for balloon help
+ $bindings_fm->Frame()->pack(-fill => 'both', -expand => 1)->Scrolled('Listbox',
-scrollbars => 'osoe',
-height => 4,
- -width => 30*$coef)->pack(-fill => 'y',
+ -width => 30*$coef)->pack(-fill => 'both',
-side => 'top',
-anchor => 'w',
- -expand => 0);
+ -expand => 1);
$bindingsList->bind('<1>', [\&selectBinding]);
$bindingsList->bind('<Double-1>', [\&addBinding]);
$bindingsEntry->bind('<Key>' => [\&findExprInList, $bindingsList]);
my $effectivebindingsList =
- $bindings_fm->Scrolled('Listbox',
+ # need intermediate frame for balloon help
+ $bindings_fm->Frame()->pack(-fill => 'both', -expand => 1)
+ ->Scrolled('Listbox',
-scrollbars => 'osoe',
-height => 4,
- -width => 30*$coef)->pack(-fill => 'y',
+ -width => 30*$coef)->pack(-fill => 'both',
-side => 'bottom',
-anchor => 'w',
-expand => 1);
@@ -588,7 +719,7 @@ $effectivebindingsList->bind('<Double-1>', [\&removeBinding]);
&wheelmousebindings($bindingsList);
#----------------------------------------------------------------------------------
-# Connected applications area
+# Connected applications frame
#----------------------------------------------------------------------------------
my $clientsListbox =
$clients_fm->Scrolled('Listbox',
@@ -626,7 +757,7 @@ my $clientsKill_btn =
-expand => 1);
#----------------------------------------------------------------------------------
-# Messages to send area
+# Messages to send frame
#----------------------------------------------------------------------------------
my $send1_fm = $send_fm->Frame()->pack(-side => 'top',
@@ -690,6 +821,7 @@ my $sendList =
-anchor => 'w',
-side => 'top',
-expand => 1);
+
$sendEntry->bind('<Key>' => [\&findExprInList, $sendList]);
$sendEntry->bind('<Return>' => [\&addMsgToSend, undef, 1]);
@@ -704,7 +836,7 @@ $sendList->bind('<Double-1>', [\&addMsgToSend, undef, 1]);
#----------------------------------------------------------------------------------
-# Search area
+# Search frame
#----------------------------------------------------------------------------------
my $searchEntry =
$search_fm->Entry(-width => 24)->grid(-column => 1,
@@ -785,14 +917,14 @@ my $exitButton =
my $loadButton =
$control_fm->Button(-height => 2,
-width => 4,
- -command => [\&loadfile, 1],
+ -command => [\&selectandloadfile, 1],
-state => 'normal',
-text => 'Load')->grid(-column => 1,
-row => 2);
my $saveButton =
$control_fm->Button(-height => 2,
-width => 4,
- -command => [\&savefile, 1],
+ -command => [\&selectandsavefile, 1],
-state => 'normal',
-text => 'Save')->grid(-column => 2,
-row => 2);
@@ -805,19 +937,21 @@ my $jumpButton =
-text => 'Jump')->grid(-column => 3,
-row => 2);
-my $startButton =
+my $scrollButton =
$control_fm->Button(-height => 2,
-width => 4,
- -command => [\&start, 1],
+ -command => [\&displayOn],
-state => 'disabled',
-text => 'Scroll')->grid(-column => 1,
-row => 3);
-my $stopButton =
+my $scrollLockButton =
$control_fm->Button(-height => 2,
-width => 4,
- -command => [\&stop, 1],
+ -command => [\&displayOff],
-text => "Scroll\nLock")->grid(-column => 2,
-row => 3);
+$scrollLockButton->invoke() if $opt_buf;
+
my $clearButton =
$control_fm->Button(-height => 2,
-width => 4,
@@ -863,7 +997,7 @@ $balloonhelp->attach($messagesMaxLabel, -balloonmsg =>
);
$balloonhelp->attach($messagesDeletedLabel, -balloonmsg =>
"Counter for received messages which are\n".
- "skipped when history size is reached. "
+ "lost when history size is reached. "
);
$balloonhelp->attach($messagesBufLabel, -balloonmsg =>
"Counter for received messages which are bufferized\n".
@@ -881,22 +1015,25 @@ $balloonhelp->attach($bindingsEntry, -balloonmsg =>
$completionText."\n".
$insertionText
);
-$balloonhelp->attach($bindingsList, -balloonmsg =>
- "Available bindings list. Select an item for edition or\n".
- "double-click on a predefined binding to activate it. "
+$balloonhelp->attach($bindingsList->parent, -balloonmsg =>
+ "Available bindings, deducted from connected agents\n".
+ "ones. Select an item for edition or double-click \n".
+ "on a predefined binding to activate it \n".
+ "(so it will appear in the list below)."
);
-
-$balloonhelp->attach($effectivebindingsList, -balloonmsg =>
- "Effective bindings list. Double-click on binding to unset it."
+$balloonhelp->attach($effectivebindingsList->parent, -balloonmsg =>
+ "Effective bindings. Double-click on binding to unset it."
);
-$balloonhelp->attach($clientsListbox,-balloonmsg =>
- "Select an application name to highlight related\n".
- "Ivy messages in the Messages area. \n".
- "Double-click on it to display the application \n".
- "bindings or click on the 'See bindings' button.\n".
- "To display messages in a separate window, click\n".
- "on the 'Filter' button. \n".
- "To kill an agent, click on the 'Kill' button. ");
+$balloonhelp->attach($clientsListbox->parent,-balloonmsg =>
+ "Connected agents frame.\n".
+ "Select an application name to highlight its \n".
+ "ivy messages in the Messages frame. \n".
+ "After selection : \n".
+ " . click on the [See bindings] to display its bindings\n".
+ " (or double-click on item), \n".
+ " . click on the [Filter] button to display messages in \n".
+ " a separate window,\n".
+ " . click on the [Kill] button to kill the selected agent.\n");
$balloonhelp->attach($sendEntry, -balloonmsg =>
"This input field is used to enter new messages or\n".
"edit default one from list above. In both case, \n".
@@ -905,16 +1042,22 @@ $balloonhelp->attach($sendEntry, -balloonmsg =>
$completionText."\n".
$insertionText
);
-$balloonhelp->attach($sendList, -balloonmsg =>
- "Available messages list. Select an item for edition\n".
- "or double click on predefined message to send it. "
+$balloonhelp->attach($send2_fm, -balloonmsg =>
+ "Predefined 'Rejeu' messages. "
+ );
+$balloonhelp->attach($sendList->parent(), -balloonmsg =>
+ "Available messages list, deducted from connected \n".
+ "agents bindings and manual inputs. Select an item \n".
+ "for edition or double click on predefined \n".
+ "message to send it. "
);
$balloonhelp->attach($recipientLabel, -balloonmsg =>
"Number of last message recipients."
);
$balloonhelp->attach($messagesText, -balloonmsg =>
+ "Received ivy messages frame.\n".
"You can insert colored marker by double-clicking on a \n".
- "message application name (marker will be createafter\n".
+ "message sender name (marker will be create after\n".
"the message). Then, you can quickly access markers \n".
"using the [Jump] button in control panel. To remove a \n".
"marker, just double-click on it. "
@@ -926,42 +1069,63 @@ $balloonhelp->attach($searchEntry, -balloonmsg =>
"key to search backward. \n".
$historyText
);
-$balloonhelp->attach($stopButton, -balloonmsg =>
- "Stop scrolling in Messages area."
+$balloonhelp->attach($scrollLockButton, -balloonmsg =>
+ "Stop scrolling in Messages frame.\n".
+ "Generates bufferized messages."
);
-$balloonhelp->attach($startButton, -balloonmsg =>
- "Restart scrolling in Messages area."
+$balloonhelp->attach($scrollButton, -balloonmsg =>
+ "Restart scrolling in Messages frame."
);
$balloonhelp->attach($jumpButton, -balloonmsg =>
- "Access next marker in Messages area."
+ "Access next marker in Messages frame."
);
$balloonhelp->attach($clearButton, -balloonmsg =>
"Remove messages displayed\n".
- "in Messages area. "
+ "in Messages frame. "
);
$balloonhelp->attach($loadButton, -balloonmsg =>
"Load messages file and display\n".
- "its content in Messages area. "
+ "its content in Messages frame. "
);
$balloonhelp->attach($saveButton, -balloonmsg =>
- "Save the content of Messages\n".
- "area in a file. "
+ "Save the recorded and bufferized\n".
+ "messages in a file. "
);
$balloonhelp->attach($sendEnlargeBtn, -balloonmsg =>
"Click here to enlarge or shrink this frame"
);
+# animation on status bar at starting
+$mw->after(1000, sub {
+
+ if ($status_lb->cget(-text) eq '') {
+ my $msg = "Select the 'Balloon help' checkbutton for a better understanding.";
+ my $c = 0;
+ my $id;
+ $id = $mw->repeat(250, sub {
+ $c++;
+ my $t = ($c % 2) ? $msg : '';
+ $status_lb->configure(-text => $t);
+ $status_lb->idletasks();
+ $mw->afterCancel($id) if $c == 5;
+ });
+ $mw->after(15000, sub {
+ $status_lb->configure(-text => '') if $status_lb->cget(-text) eq $msg;
+ });
+ }
+
+});
#=================================================================================
#
# Ivy initialisation and Ivy bindings
#
#=================================================================================
# add Ivymon in connected applications list
-&addClient($appname, 'localhost');
+&addClient($myappname, 'localhost');
# init Ivy bus and start it.
Ivy->init(-loopMode => 'TK',
- -appName => $appname,
+ -appName => $myappname,
-ivyBus => $ivy_port,
-onDieFunc => [\&quit],
);
@@ -971,6 +1135,7 @@ $ivy->start;
# add Ivy bindings
for my $bind (@effectivebind) {
&addBinding(undef, $bind);
+ $mw->idletasks(); #/UPD 01/2015
}
#=================================================================================
@@ -979,21 +1144,12 @@ for my $bind (@effectivebind) {
#
#=================================================================================
-# load input files
-if (@ARGV > 0) {
- my $file = $ARGV[0];
- if ( not open(IN, $file)) {
- $mw->Tk::Error("Can't open file '$file' ($!)");
- } else {
- &showProgressbar();
- my $step = &stepsnumber();
- &loadfileForDisplay($step);
- &hideProgressbar();
- close(IN);
- }
-}
+# load input file
+&loadfile($ARGV[0], 1) if @ARGV > 0;
+
+$ivy->bindRegexp("^Ivymon Output=(.*)", [sub { $ivyoutputfile = $_[1]; }]);
+$mw->update(); #/UPD 01/2015
-$ivy->bindRegexp("^Ivymon Output=(.*)", [sub { $outputfile = $_[1]; }]);
MainLoop;
#==================================================================================
@@ -1001,9 +1157,19 @@ MainLoop;
# Functions
#
#==================================================================================
+# General ivy bindings functions
+# Functions related to the 'Applications' frame
+# Functions related to the 'Messages' frame
+# Functions related to the 'Bindings' frame
+# Functions related to the 'Messages to sent' frame
+# Functions related to the 'Search' frame
+# Functions related to the 'Control' frame
+# Functions related to input/output files
+# Utils functions
+
#----------------------------------------------------------------------------------
-# Ivy functions
+# General ivy bindings functions
#----------------------------------------------------------------------------------
sub addIvyBinding {
my $binding = shift;
@@ -1019,14 +1185,13 @@ sub addIvyBinding {
} else {
$message = shift;
}
- $messagesNumber++;
my $time = gettimeofday();
- if ($stopFlag) {
- &bufferizeMessages($sender, $message, $time);
+ if ($bufmode) {
+ &bufferizeMessage($sender, $message, $time);
} else {
- &beforeUpdatingMessages;
- &updateMessages($sender, $message, $time);
- &afterUpdatingMessages;
+ &beforeUpdatingMessagesFrame;
+ my $msgadded = &updateMessagesFrame($sender, $message, $time);
+ &afterUpdatingMessagesFrame($msgadded);
}
}]);
@@ -1041,7 +1206,7 @@ sub removeIvyBinding {
#----------------------------------------------------------------------------------
-# Functions related to connected applications management
+# Functions related to the 'Applications' frame
#----------------------------------------------------------------------------------
sub checkClientsStatus {
@@ -1059,13 +1224,16 @@ sub checkClientsStatus {
$host = $_[5];
$regexp = $host;
}
- $host =~ s/:.*//;
- #print "status=$status host=$host regexp=$regexp\n";
+ # $host =~ s/:.*//;
+ my $port;
+ ($host, $port) = $host =~ /^(.*):(\d+)/;
$appname =~ s/ /_/g;
if ($status eq 'died') {
&removeClient($appname, $host);
+ print "$appname disconnected from $host:$port\n";
} elsif ($status eq 'new') {
&addClient($appname, $host);
+ print "$appname connected from $host:$port\n";
} elsif ($status eq 'subscribing') {
$clientsBindings{$appname}->{$regexp}++;
&addBindingAndMsgToSend($regexp);
@@ -1079,8 +1247,10 @@ sub checkClientsStatus {
sub addClient {
+
my $client = shift;
my $host = shift;
+
$host = $hostname if $host eq 'localhost' or $host =~ /^$hostname\./;
#print "addClient $client on $host\n";
$connectedClients{$client}->{$host}++;
@@ -1090,8 +1260,10 @@ sub addClient {
sub removeClient {
+
my $client = shift;
my $host = shift;
+
$host = $hostname if $host eq 'localhost' or $host =~ /^$hostname\./;
$connectedClients{$client}->{$host}-- if $connectedClients{$client}->{$host} > 0;
my $num = 0;
@@ -1099,7 +1271,7 @@ sub removeClient {
$num += $connectedClients{$client}->{$host};
}
delete $clientsBindings{$client} if $num == 0;
- &manageClient($client, $host);
+ &manageClient($client, $host);
} # end removeClient
@@ -1107,12 +1279,13 @@ sub removeClient {
sub manageClient {
my $client = shift;
my $host = shift;
+
my $i = 0;
for ($clientsListbox->get(0, 'end')) {
- if ($_ =~ /^$client/ or $_ =~ /-- $client/) {
- $clientsListbox->delete($i);
- last;
- }
+ if ($_ =~ /^$client/ or $_ =~ /-- $client/) {
+ $clientsListbox->delete($i);
+ last;
+ }
$i++;
}
my $num = 0;
@@ -1140,6 +1313,7 @@ sub manageClient {
} # end manageClient
+
sub killClient {
my $selindex = $clientsListbox->curselection;
return unless defined $selindex;
@@ -1149,9 +1323,9 @@ sub killClient {
$client =~ s/\s.*//;
$ivy->sendDieTo($client);
-
} # end killClient
+
sub selectClient {
$messagesText->tagConfigure($selectedClient, -background => $bgcolor)
if $selectedClient;
@@ -1178,12 +1352,12 @@ sub filterClient {
$client =~ s/^-- //;
$client =~ s/\(\d+\)$//;
$client =~ s/\s.*//;
- # si une fenetre client existe, on la raise
+ # raise client toplevel if exists
if (defined $clientsMessagesTpl{$client} and
Tk::Exists $clientsMessagesTpl{$client}) {
$clientsMessagesTpl{$client}->toplevel->raise;
return;
- # sinon, on la crée
+ # create toplevel otherwise
} else {
my $tpl = $mw->Toplevel;
$tpl->group($mw);
@@ -1228,7 +1402,6 @@ sub filterClient {
} # end filterClient
-
sub showClientBindings {
my $selindex = $clientsListbox->curselection;
return unless defined $selindex;
@@ -1268,14 +1441,44 @@ sub showClientBindings {
)->pack(-side => 'top',
-padx => 10,
-pady => 10);
-
} # end showClientBindings
+sub updateClientMessages {
+ my ($sender, $message) = @_;
+ return unless $clientsMessagesTpl{$sender} and
+ Tk::Exists $clientsMessagesTpl{$sender};
+ $clientsMessagesTpl{$sender}->configure(-state => 'normal');
+ $clientsMessagesTpl{$sender}->insert('end', $message);
+ $clientsMessagesTpl{$sender}->insert('end', "\n");
+ $clientsMessagesTpl{$sender}->idletasks unless $noUpdateFlag;
+ $clientsMessagesTpl{$sender}->see('end');
+ $clientsMessagesTpl{$sender}->configure(-state => 'disabled');
+
+} # end updateClientMessages
+
+
#----------------------------------------------------------------------------------
-# Functions related to messages display management
+# Functions related to the 'Messages' frame
#----------------------------------------------------------------------------------
+# add comment to Messages frame
+# (doesn't increment messages counter)
+sub addcomment {
+ my $comment = shift;
+ my $text = "comment=$comment\n";
+ my $index1 = $messagesText->index('end')." - 1 lines";
+ my $index2 = "$index1 + ".length("comment=")." chars";
+ $messagesText->insert('end', $text);
+ $messagesText->tagAdd('hidden', $index1, $index2);
+ my $index3 = "$index2 + 1 chars";
+ my $index4 = "$index3 + ".length($comment)." chars";
+ $messagesText->tagAdd('comment', $index3, $index4);
+
+} # end addcomment
+
+
+# callback : add or delete marker in Messages frame
sub marker {
return if $noMessageYet;
my @markers = $messagesText->markNames;
@@ -1293,129 +1496,180 @@ sub marker {
last;
}
}
+ &beforeUpdatingMessagesFrame();
if ($foundmarker) {
&deletemarker($foundmarker);
} else {
my $index = $messagesText->index('current linestart + 1 lines');
my $nb = $markers_cnt % 5;
&addmarker($index, 'marker'.$nb);
- $markers_cnt++;
}
+ &afterUpdatingMessagesFrame();
} # end marker
+# delete marker from Messages frame
+# (doesn't decrement messages counter)
sub deletemarker {
my $marker = shift;
- $messagesText->configure(-state => 'normal');
$messagesText->delete($marker, "$marker lineend + 1 chars");
$messagesText->markUnset($marker);
- $messagesText->configure(-state => 'disabled');
} # end deletemarker
+# add marker to Messages frame
+# (doesn't increment messages counter)
sub addmarker {
my $index = shift;
my $marker = shift;
#print "index=$index marker=$marker\n";
- $messagesText->configure(-state => 'normal');
$messagesText->insert($index, "$marker\n");
$messagesText->tagAdd($marker, $index, "$index + ".(length($marker)+1)." chars");
$messagesText->markSet('ivymon'.$markers_cnt, $index);
$jumpButton->configure(-state => 'normal');
- $messagesText->configure(-state => 'disabled');
+ $markers_cnt++;
-} # ens addmarker
+} # end addmarker
-sub bufferizeMessages {
+# increment deleted counter
+sub increment_deleted {
+ my $n = shift;
+ $n = 1 unless defined $n;
+ if ($deletedNumber == 0) {
+ $messagesDeletedLabel->configure(-foreground => 'red');
+ $messagesDeletedValue->configure(-foreground => 'red');
+ }
+ $deletedNumber += $n;
+
+} # end increment_deleted
+
+
+# bufferize 1 message instead of displaying it
+# (and increment buffer counter) according to history constraint.
+sub bufferizeMessage {
my ($sender, $message, $time) = @_;
- $bufNumber++;
- # if scrolling is locked, don't force display, just put message in buffer
- push(@messagesbuffer, [$sender, $message, $time]);
- splice(@messagesbuffer, 0, 1) if @messagesbuffer > $history;
+ my $yesyoucan = 0; # buffering only if 1
+ # no history constraint
+ if ($infinitehistory) {
+ $yesyoucan = 1;
+ # history constraint == duration
+ } elsif (defined $historyduration) {
+ $yesyoucan = 1 if $runningtime_min < $historyduration;
+ # history constraint == messages max number
+ } else {
+ my $diff = $bufNumber + $displayedNumber - $historynumber;
+ $yesyoucan = 1 if $diff < 0;
+ }
+ if ($yesyoucan) {
+ $bufNumber++;
+ $bufSize += length($message) if $opt_verbose;
+ push(@databuffer, [$sender, $message, $time]);
+ } else {
+ &increment_deleted();
+ }
+} # end bufferizeMessage
-} # end bufferizeMessages
+# bufferize 1 marker instead of displaying it
+# (doesn't increment buffer counter)
+sub bufferizeMarker {
+ my ($marker) = @_;
+ push(@databuffer, ['ivymon_marker', $marker]);
+
+} # end bufferizeMarker
-sub beforeUpdatingMessages {
+
+# bufferize 1 comment instead of displaying it
+# (doesn't increment buffer counter)
+sub bufferizeComment {
+ my ($comment) = @_;
+ push(@databuffer, ['ivymon_comment', $comment]);
+
+} # end bufferizeComment
+
+
+sub beforeUpdatingMessagesFrame {
$messagesText->configure(-state => 'normal');
-} # end beforeUpdatingMessages
+} # end beforeUpdatingMessagesFrame
-sub updateMessages {
+# update Messages frame : add 1 message in the Messages frame, according
+# to the history size (so, former messages may be deleted or new ones
+# may be ignored)
+sub updateMessagesFrame {
my ($sender, $message, $time) = @_;
chomp($message);
$message = '"' . $message . '"' ;
- # If scrolling is available, format and then display message.
- # Unless file has been loaded, look at history : compare widget text lines
- # number with history size
- if ($loadedFileFlag) {
- &loadMessage($sender, $message, $time);
- $messagesText->update unless $noUpdateFlag;
-
+ my $messageadded = 0;
+ my $loadmessagefunc = sub {
+ &loadMessage($sender, $message, $time);
+ $displayedNumber++;
+ $displayedSize += length($message) if $opt_verbose;
+ $messagesText->idletasks unless $noUpdateFlag;
+ $messageadded = 1;
+ };
+ if ($infinitehistory) {
+ &$loadmessagefunc;
+ # history size is taken in account here
+ } elsif (defined $historyduration) {
+ if ($runningtime_min >= $historyduration) {
+ &increment_deleted(1);
+ $messageadded = 0;
+ } else {
+ &$loadmessagefunc;
+ }
} else {
- my ($linesNb) = split(/\./, $messagesText->index('end'));
- $linesNb--;
- #print "linesNb=$linesNb\n";
- if ($linesNb > $history) {
- $deletedNumber += 1;
- if ($deletedNumber == 1) {
- $messagesDeletedLabel->configure(-foreground => 'red');
- $messagesDeletedValue->configure(-foreground => 'red');
- }
- } else {
- &loadMessage($sender, $message, $time);
- $messagesText->update unless $noUpdateFlag;
- }
+ my $diff = $bufNumber + $displayedNumber - $historynumber + 1; # diff if message is added
+ if ($diff > 0) {
+ &increment_deleted($diff);
+ $messageadded = 0;
+ } else {
+ &$loadmessagefunc;
+ }
}
-
-} # end updateMessages
-
-
-sub updateClientMessages {
- my ($sender, $message) = @_;
- return unless $clientsMessagesTpl{$sender} and
- Tk::Exists $clientsMessagesTpl{$sender};
- $clientsMessagesTpl{$sender}->configure(-state => 'normal');
- $clientsMessagesTpl{$sender}->insert('end', $message);
- $clientsMessagesTpl{$sender}->insert('end', "\n");
- $clientsMessagesTpl{$sender}->update unless $noUpdateFlag;
- $clientsMessagesTpl{$sender}->see('end');
- $clientsMessagesTpl{$sender}->configure(-state => 'disabled');
+ return $messageadded;
-} # end updateClientMessages
+} # end updateMessagesFrame
+# insert 1 message in the text widget of the Messages frame
sub loadMessage {
my ($sender, $message, $time) = @_;
- $recordedNumber++;
+ # print "in loadMessage sender=[$sender] message=[$message] time=[$time]\n"; #DEBUG
$noMessageYet = 0;
+ # note tags creation slows down display...
my $text = "$sender $time $message\n";
my $index1 = $messagesText->index('end')." - 1 lines";
my $index2 = "$index1 + ".length($sender)." chars";
$messagesText->insert('end', $text);
$messagesText->tagAdd('sender', $index1, $index2);
- my $index3 = "$index2 + 1 chars";
- my $index4 = "$index3 + ".length($time)." chars";
- $messagesText->tagAdd('time', $index3, $index4);
+ my $index4;
+ if (defined $time) {
+ my $index3 = "$index2 + 1 chars";
+ $index4 = "$index3 + ".length($time)." chars";
+ $messagesText->tagAdd('time', $index3, $index4);
+ } else {
+ $index4 = $index2;
+ }
my $index5 = "$index4 + 1 chars";
my $index6 = "$index5 + ".length($message)." chars";
$messagesText->tagAdd($sender, $index5, $index6);
&updateClientMessages($sender, $message) if $clientsMessagesTpl{$sender} and
Tk::Exists $clientsMessagesTpl{$sender};
-
-} # end loadmessages
+} # end loadMessage
-sub afterUpdatingMessages {
- $messagesText->see('end');
+sub afterUpdatingMessagesFrame {
+ my $msgadded = shift;
+ $messagesText->see('end') if $msgadded;
$messagesText->configure(-state => 'disabled');
-} # end afterUpdatingMessages
+} # end afterUpdatingMessagesFrame
sub highlightString {
@@ -1437,7 +1691,7 @@ sub highlightStringOff {
#----------------------------------------------------------------------------------
-#Functions related to Ivy bindings management
+# Functions related to the 'Bindings' frame
#----------------------------------------------------------------------------------
sub addBindingExpression {
$bindingsEntry->insert('insert', '(.*)');
@@ -1488,24 +1742,34 @@ sub clearBinding {
} # end clearBinding
+# add ivymon binding
sub addBinding {
- my ($sender, $entry) = @_;
- unless ($entry) {
- $entry = $bindingsEntry->get;
- return unless $entry;
+ shift;
+ my $regexp = shift;
+ unless ($regexp) {
+ $regexp = $bindingsEntry->get;
+ return unless $regexp;
}
- &bindHistoryGenList($entry);
- if ($effectivebindings{$entry}) {
+ &bindHistoryGenList($regexp);
+ if ($effectivebindings{$regexp}) {
&warning2($bindingsEntry);
return ;
}
- $effectivebindingsList->insert('end', "bound to ".$entry);
- $effectivebindings{$entry} = 1;
- &addBindingInList($entry);
+ my $comment = "Bound to $regexp";
+ if ($bufmode) {
+ &bufferizeComment($comment);
+ } else {
+ &beforeUpdatingMessagesFrame();
+ &addcomment($comment);
+ &afterUpdatingMessagesFrame(1);
+ }
+ $effectivebindingsList->insert('end', "bound to ".$regexp);
+ $effectivebindings{$regexp} = 1;
+ &addBindingInList($regexp);
&warning3($bindingsEntry);
- &addIvyBinding($entry);
+ &addIvyBinding($regexp);
&bindingsGenList;
- $clientsBindings{$appname}->{"$entry"}++;
+ $clientsBindings{$myappname}->{"$regexp"}++;
} # end addBinding
@@ -1603,16 +1867,24 @@ sub selectBinding {
} # end selectBinding
+# remove ivymon binding
sub removeBinding {
my $selindex = $effectivebindingsList->curselection;
return unless defined($selindex);
my $selected = $effectivebindingsList->get($selindex);
$selected =~ s/^bound to //;
+ my $comment = "Unbound to $selected";
+ if ($bufmode) {
+ &bufferizeComment($comment);
+ } else {
+ &beforeUpdatingMessagesFrame();
+ &addcomment($comment);
+ &afterUpdatingMessagesFrame(1);
+ }
&removeIvyBinding($selected);
$effectivebindingsList->delete($selindex);
$effectivebindings{$selected} = undef;
- $clientsBindings{$appname}->{"$selected"}--;
-
+ $clientsBindings{$myappname}->{"$selected"}--;
} # end removeBinding
@@ -1643,7 +1915,7 @@ sub bindHistoryGenList {
} # end bindHistoryGenList
#----------------------------------------------------------------------------------
-# Fucntions related to messages emission.
+# Functions related to the 'Messages to sent' frame
#----------------------------------------------------------------------------------
sub sendNextExpression {
@@ -1707,10 +1979,13 @@ sub addMsgToSend {
sub sendMsg {
my $entry = shift;
- $messagesNumber++;
- &beforeUpdatingMessages;
- &updateMessages($appname, $entry, scalar gettimeofday());
- &afterUpdatingMessages;
+ if ($bufmode) {
+ &bufferizeMessage($myappname, $entry, scalar gettimeofday());
+ } else {
+ &beforeUpdatingMessagesFrame;
+ my $msgadded = &updateMessagesFrame($myappname, $entry, scalar gettimeofday());
+ &afterUpdatingMessagesFrame($msgadded);
+ }
my $c = $ivy->sendMsgs($entry);
$recipientLabel->configure(-text => $c);
@@ -1788,7 +2063,7 @@ sub clockswitch {
#----------------------------------------------------------------------------------
-# Functions related to search panel
+# Functions related to the 'Search' frame
#----------------------------------------------------------------------------------
sub searchNextExpression {
my $cursorIndex = $searchEntry->index('insert');
@@ -1959,20 +2234,26 @@ sub searchAll {
} # end searchAll
#----------------------------------------------------------------------------------
-# Functions related to control panel
+# Functions related to the 'Control' frame
#----------------------------------------------------------------------------------
+
+# called when [Exit] button is pressed
sub bye {
- if ($messagesNumber > 0) {
+ if (($bufNumber + $displayedNumber) > 0) {
my $diag = $mw->Dialog(-text =>
"Really quit Ivymon ?",
-default_button => 'OK',
- -buttons => [qw(OK Cancel)]);
- my $answer = $diag->Show;
+ -buttons => [qw(OK Cancel)],
+ -title => "Exit dialog");
+ my $answer = $diag->Show(-popover => 'cursor');
if ($answer eq 'Cancel') {
return;
}
}
- &quit;
+ if (defined $opt_out and not $datasaved) {
+ $mw->Tk::Error("$!\n") if &save() < 0;
+ }
+ exit;
}
sub jump {
@@ -1990,18 +2271,43 @@ sub jump {
} # end jump
-sub stop {
+# called when [Scroll Lock] button is pressed
+sub displayOff {
my $flag = shift;
- @messagesbuffer = ();
- $stopFlag = 1;
- $startButton->configure(-state => 'normal');
- $stopButton->configure(-state => 'disabled');
-
-} # end stop
-
+ my $msg = "Bufferized mode enabled.";
+ $msg .= " Press the 'Scroll' button to display ivy messages in the main frame." if $opt_buf;
+ $status_lb->configure(-text => $msg);
+ @databuffer = ();
+ $bufmode = 1;
+ $scrollButton->configure(-state => 'normal');
+ $scrollLockButton->configure(-state => 'disabled');
+
+} # end displayOff
+
+
+# called when [Scroll] button is pressed
+sub displayOn {
+ my $nmax = 100000;
+ my $showprogressbar = 0;
+ if ($bufNumber > $nmax) {
+ my $diag = $mw->Dialog(-text =>
+ "More than $nmax messages are bufferized.\n".
+ "Displaying them may take a long time.\n".
+ "Do you want to continue ?",
+ -default_button => 'Continue',
+ -buttons => [qw(Continue Cancel)],
+ -title => "Load dialog");
+ my $answer = $diag->Show(-popover => 'cursor');
+ if ($answer eq 'Cancel') {
+ return;
+ }
+ &configProgressbar($bufNumber);
+ &showProgressbar("Be patient...");
+ $showprogressbar = 1;
+ }
+
+ $status_lb->configure(-text => "") if $status_lb->cget(-text) =~ /^Bufferized/;
-sub start {
- my $flag = shift;
if ($messagesText->index('insert') !~ /\.0$/) {
$messagesText->insert('insert', "\n");
}
@@ -2012,37 +2318,72 @@ sub start {
$saveButton->configure(-state => 'disabled');
$jumpButton->configure(-state => 'disabled');
$clearButton->configure(-state => 'disabled');
- $startButton->configure(-state => 'disabled');
- $stopButton->configure(-state => 'disabled');
- $mw->update;
+ $scrollButton->configure(-state => 'disabled');
+ $scrollLockButton->configure(-state => 'disabled');
+ $mw->idletasks;
$noUpdateFlag = 1;
- &beforeUpdatingMessages;
- for my $msg (@messagesbuffer) {
- &updateMessages($msg->[0], $msg->[1], $msg->[2]);
- $bufNumber--;
+
+ &beforeUpdatingMessagesFrame;
+ # print "before updating frame, databuffer length = ", scalar(@databuffer), "\n"; #DEBUG
+ my $n = 0;
+ # As perl hold memory allocated by the OS for the life of the process,
+ # it is better to shorten the @databuffer at each iteration than to keep
+ # it complete and to clean it at the end.
+ # In my tests, this approach saves 30% of memory.
+ #
+ # for my $msg (@databuffer) {
+ while (my $msg = shift(@databuffer)) {
+ $n++;
+ if ($msg->[0] eq "ivymon_marker") {
+ my $index = $messagesText->index('end')." - 1 lines";
+ &addmarker($index, $msg->[1]);
+ } elsif ($msg->[0] eq "ivymon_comment") {
+ &addcomment($msg->[1]);
+ } else {
+ &loadMessage($msg->[0], $msg->[1], $msg->[2]);
+ $displayedNumber++;
+ $bufNumber--;
+ }
+ &setProgressbar($n) if $showprogressbar;
}
- &afterUpdatingMessages;
+ &hideProgressbar if $showprogressbar;
+ # print "after, databuffer processed messages number = ", $n, "\n"; #DEBUG
+ # print "after, new databuffer length = ", scalar(@databuffer), "\n"; #DEBUG
+ $messagesText->idletasks;
+ # print "after Text update\n"; #DEBUG
+ &afterUpdatingMessagesFrame(1);
+ # print "after afterUpdatingMessagesFrame\n"; #DEBUG
$noUpdateFlag = 0;
- $stopFlag = 0;
-
+ $bufmode = 0;
+ # print "before reset databuffer\n"; #DEBUG
+ @databuffer = ();
+ $#databuffer = -1;
+ # print "after reset databuffer\n"; #DEBUG
+ $bufNumber = 0;
+ $displayedSize += $bufSize if $opt_verbose;
+ $bufSize = 0 if $opt_verbose;
+
# restore other buttons state
$loadButton->configure(-state => 'normal');
$saveButton->configure(-state => 'normal');
$jumpButton->configure(-state => $jumpstate);
$clearButton->configure(-state => 'normal');
- $stopButton->configure(-state => 'normal');
-
-} # end start
+ $scrollLockButton->configure(-state => 'normal');
+} # end displayOn
+# called when the [clear] button is pressed
sub clear {
- if ($messagesNumber > 0) {
- my $diag = $mw->Dialog(-text =>
- "Do you really want to remove displayed messages ?",
+ if ($displayedNumber > 0) {
+ my $msg = "Do you really want to remove displayed messages ?";
+ $msg .= "\n(some messages are bufferized and will be kept)"
+ if $bufNumber > 0;
+ my $diag = $mw->Dialog(-text => $msg,
-default_button => 'OK',
- -buttons => [qw(OK Cancel)]);
- my $answer = $diag->Show;
+ -buttons => [qw(OK Cancel)],
+ -title => "Clear dialog");
+ my $answer = $diag->Show(-popover => 'cursor');
if ($answer eq 'Cancel') {
return;
}
@@ -2050,19 +2391,19 @@ sub clear {
# disable other buttons
my $jumpstate = $jumpButton->cget(-state);
- my $startstate = $startButton->cget(-state);
- my $stopstate = $stopButton->cget(-state);
+ my $scrollState = $scrollButton->cget(-state);
+ my $scrollLockState = $scrollLockButton->cget(-state);
$loadButton->configure(-state => 'disabled');
$saveButton->configure(-state => 'disabled');
$jumpButton->configure(-state => 'disabled');
$clearButton->configure(-state => 'disabled');
- $startButton->configure(-state => 'disabled');
- $stopButton->configure(-state => 'disabled');
- $mw->update;
+ $scrollButton->configure(-state => 'disabled');
+ $scrollLockButton->configure(-state => 'disabled');
+ $mw->idletasks;
$messagesText->configure(-state => 'normal');
- $messagesNumber = 0;
- $recordedNumber = 0;
+ $displayedNumber = 0;
+ $displayedSize = 0 if $opt_verbose;
#$messagesText->delete('1.0', 'end');
while ($messagesText->compare($messagesText->index('end'), ">", "2.0")) {
$messagesText->delete('1.0', '1000.0');
@@ -2075,128 +2416,161 @@ sub clear {
$saveButton->configure(-state => 'normal');
$jumpButton->configure(-state => $jumpstate);
$clearButton->configure(-state => 'normal');
- $startButton->configure(-state => $startstate);
- $stopButton->configure(-state => $stopstate);
+ $scrollButton->configure(-state => $scrollState);
+ $scrollLockButton->configure(-state => $scrollLockState);
} # end clear
#----------------------------------------------------------------------------------
# Functions related to input/output files
#----------------------------------------------------------------------------------
-sub loadfile {
-
- my $file = $mw->getOpenFile(-filetypes => [['Ivy Files', '.ivy'],
- ['All Files', '*']],
- );
- return unless $file;
+sub loadfile {
+
+ my $file = shift;
+ my $initflag = shift;
# open file
unless (open(IN, "$file")) {
$mw->Tk::Error("$!\n");
return;
}
- &showProgressbar();
- my $step = &stepsnumber();
- &loadfileForDisplay($step);
+ $fileloaded = 1;
+ &showProgressbar("Loading file...");
+ my $lines_num = &configProgressbar();
+ $progressbar_tpl->title("Big file! Be patient...") if $lines_num > 1000000;
+ my $skipped = &loadfileForDisplay($initflag);
&hideProgressbar();
close(IN);
+ if ($skipped > 0) {
+ use Tk::Dialog;
+ my $diag = $mw->Dialog(-text => "$skipped lines have been skipped.\nSee stdout for details.",
+ -bitmap => "warning",
+ -title => "Warning!",
+ -buttons => ["OK"]);
+ $diag->Show(-popover => $mw, -popanchor => 'c');
+ $diag->destroy();
+ }
} # end loadfile
-sub stepsnumber {
+# called when the [Load] button is pressed
+sub selectandloadfile {
- my $step = 0;
- my $lc = 0;
+ my $file = $mw->getOpenFile(-filetypes => [['Ivy Files', '.ivy'],
+ ['All Files', '*']],
+ );
+ &loadfile($file) if $file;
- # get lines number and test if exists time field
- while(<IN>) {
- chomp;
- next if (/^applications=/ or /^(marker\d+)$/ or /^(messages_number=)/
- or /^\#/);
- $lc++;
- }
- $step = int($lc/10);
- $progressbar->configure(-to => $step*10);
- seek(IN, 0, 0);
- return $step;
-
-} # end stepsnumber
+} # end selectandloadfile
+# read an ivy traffic file and display its content.
+# called by loadfile function
+# called by main if an input file is passed to the command
sub loadfileForDisplay {
- my $step = shift;
- if ($messagesNumber > 0) {
+ my $initflag = shift;
+
+ if (($bufNumber + $displayedNumber) > 0 and not $initflag) {
my $diag = $mw->Dialog(-text =>
- "Some Ivy messages are already displayed. ".
+ "Some Ivy messages are already recorded. ".
"If you continue, loaded messages will ".
"be appended without distinction.\n",
-default_button => 'Continue',
- -buttons => [qw(Continue Cancel)]);
- my $answer = $diag->Show;
+ -buttons => [qw(Continue Cancel)],
+ -title => "Load dialog");
+ my $answer = $diag->Show(-popover => 'cursor');
if ($answer eq 'Cancel') {
return;
}
}
# set load flags...
- $loadedFileFlag = 1;
$loadingFlag = 1;
$balloonhelp->attach($messagesMaxLabel, -balloonmsg =>
"No history limit when file is loaded");
$balloonhelp->attach($messagesDeletedLabel, -balloonmsg =>
"Messages deletion is deactivated when file is loaded");
- $messagesDeletedLabel->configure(-foreground => 'gray60');
- $messagesDeletedValue->configure(-foreground => 'gray60');
- $messagesMaxLabel->configure(-foreground => 'gray60');
+ $status_lb->configure(-text => "History is set to infinite when file is loaded");
+ $infinitehistory = 1;
+ $historylabel = 'all';
+ $messagesMaxLabel->configure(-text => "Recordable : $historylabel");
+
# disable other buttons
my $jumpstate = $jumpButton->cget(-state);
- my $startstate = $startButton->cget(-state);
- my $stopstate = $stopButton->cget(-state);
+ my $scrollState = $scrollButton->cget(-state);
+ my $scrollLockState = $scrollLockButton->cget(-state);
$loadButton->configure(-state => 'disabled');
$saveButton->configure(-state => 'disabled');
$jumpButton->configure(-state => 'disabled');
$clearButton->configure(-state => 'disabled');
- $startButton->configure(-state => 'disabled');
- $stopButton->configure(-state => 'disabled');
- $mw->update;
+ $scrollButton->configure(-state => 'disabled');
+ $scrollLockButton->configure(-state => 'disabled');
+ $mw->idletasks;
- my %client;
+ my %client;
my $line = 0;
$noUpdateFlag = 1;
- &beforeUpdatingMessages;
+ &beforeUpdatingMessagesFrame;
+ my $t0 = time();
+ my $skipped = 0;
while(<IN>) {
chomp;
- if (/^applications=/ or /^messages_number=/) {
+ # print "in loadfileForDisplay line=[$_]\n"; #DEBUG
+ if (/^applications=/ or /^messages_number=/) { # special fields
next;
- } elsif (/^\s*$/) {
+ } elsif (/^\s*$/) { # skip empty lines
next;
$line++;
- } elsif (/^(marker\d+)$/) {
- my $index = $messagesText->index('current linestart');
- &addmarker($index, $1);
+ } elsif (/^(marker\d+)$/) { # colored markers
+ if ($bufmode) {
+ &bufferizeMarker($1);
+ } else {
+ my $index = $messagesText->index('end')." - 1 lines";
+ &addmarker($index, $1);
+ }
+ } elsif (/^comment=(.*)/) { # comments
+ if ($bufmode) {
+ &bufferizeComment($1);
+ } else {
+ &addcomment($1);
+ }
} else {
my ($sender, $message) = split(/ /, $_, 2);
my $time = undef;
- if ($message =~ /^(\d+)\s+(.*)/) {
+ if ($message =~ /^(\d+\.?\d+)\s+(.*)/) {
$time = $1;
$message = $2;
}
- unless ($client{$sender}) {
+ # print "in loadfileForDisplay sender=[$sender], message=[$message] time=[$time]\n"; #DEBUG
+ if (not $message or not $sender) {
+ print "Skip line [$_]\n";
+ $skipped++;
+ next;
+ }
+ # next unless $message;
+ unless ($client{$sender} or $connectedClients{$sender}) {
$client{$sender} = 1;
$clientsListbox->insert('end', $sender);
}
- $messagesNumber++;
$line++;
- #$message =~ s/^\"(.*)\"$/$1/;
- &loadMessage($sender, $message, $time);
- #print "sender=$sender message=$message step=$step line=$line\n";
- &setProgressbar($line, $step);
+ if ($bufmode) {
+ &bufferizeMessage($sender, $message, $time);
+ } else {
+ &loadMessage($sender, $message, $time);
+ $displayedNumber++;
+ $displayedSize += length($message) if $opt_verbose;
+ }
+ &setProgressbar($line);
}
}
- &afterUpdatingMessages;
+ my $dt_sec = time() - $t0;
+ my $dt_min = int($dt_sec / 60);
+ $dt_sec = $dt_sec % 60;
+ print "Loading file duration = ".$dt_min."m".$dt_sec."s\n";
+ &afterUpdatingMessagesFrame(1);
$noUpdateFlag = 0;
# restore other buttons state
@@ -2204,40 +2578,45 @@ sub loadfileForDisplay {
$saveButton->configure(-state => 'normal');
$jumpButton->configure(-state => $jumpstate);
$clearButton->configure(-state => 'normal');
- $startButton->configure(-state => $startstate);
- $stopButton->configure(-state => $stopstate);
+ $scrollButton->configure(-state => $scrollState);
+ $scrollLockButton->configure(-state => $scrollLockState);
$loadingFlag = 0;
+ return $skipped;
} # end loadfileForDisplay
-
-
-
-sub savefile {
+# called when the [Save] button is pressed
+sub selectandsavefile {
my ($d, $m, $y, $h, $M) = (localtime(time))[3,4,5,2,1];
$y =~ s/^\d// if $y >= 100;
$m++;
- my $default = (defined $outputfile) ? $outputfile :
- sprintf("ivylog%02s%02s%02s_%02s:%02s.ivy", $d, $m, $y, $h, $M);
+ my $default;
+ if (defined $ivyoutputfile) {
+ $default = $ivyoutputfile;
+ } elsif (defined $opt_out) {
+ $default = $opt_out;
+ } else {
+ $default = sprintf("ivylog%02s%02s%02s_%02s:%02s.ivy", $d, $m, $y, $h, $M);
+ }
my $file = $mw->getSaveFile(-initialfile => $default,
-filetypes => [['Ivy Files', '.ivy'],
['All Files', '*']],
);
return unless $file;
$outputfile = $file;
- &showProgressbar();
+
# disable other buttons
my $jumpstate = $jumpButton->cget(-state);
- my $startstate = $startButton->cget(-state);
- my $stopstate = $stopButton->cget(-state);
+ my $scrollState = $scrollButton->cget(-state);
+ my $scrollLockState = $scrollLockButton->cget(-state);
$loadButton->configure(-state => 'disabled');
$saveButton->configure(-state => 'disabled');
$jumpButton->configure(-state => 'disabled');
$clearButton->configure(-state => 'disabled');
- $startButton->configure(-state => 'disabled');
- $stopButton->configure(-state => 'disabled');
- $mw->update;
+ $scrollButton->configure(-state => 'disabled');
+ $scrollLockButton->configure(-state => 'disabled');
+ $mw->idletasks;
my $restorestate = sub {
&hideProgressbar();
@@ -2246,58 +2625,66 @@ sub savefile {
$saveButton->configure(-state => 'normal');
$jumpButton->configure(-state => $jumpstate);
$clearButton->configure(-state => 'normal');
- $startButton->configure(-state => $startstate);
- $stopButton->configure(-state => $stopstate);
+ $scrollButton->configure(-state => $scrollState);
+ $scrollLockButton->configure(-state => $scrollLockState);
};
- my $status = 0;
- if (&save < 0) {
+ if (&save($outputfile) < 0) {
$mw->Tk::Error("$!\n");
+ close(OUT);
&$restorestate;
return;
}
- close(OUT);
&$restorestate;
-} # end savefile
-
+} # end selectandsavefile
-sub openfile {
+# called by save() function
+sub openoutfile {
- my $file = $outputfile;
- $file = $opt_out unless defined $file;
+ my $file = shift;
return 0 unless defined $file;
if (open(OUT, ">$file")) {
- return 1;
+ return 1;
} else {
- close(OUT);
- $mw->Tk::messageBox(-icon => "warning",
+ close(OUT);
+ $mw->Tk::messageBox(-icon => "warning",
-message =>
"Can't write to file $file ($!). ".
"Save data in ivymon-rescue.ivy",
-type => 'OK',
);
- if (open(OUT, ">ivymon-rescue.ivy")) {
- return 1;
- } else {
- close(OUT);
- $mw->Tk::Error("Can't write to output file ($!)");
- return -1;
- }
+ if (open(OUT, ">ivymon-rescue.ivy")) {
+ return 1;
+ } else {
+ close(OUT);
+ $mw->Tk::Error("Can't write to output file ($!)");
+ return -1;
+ }
}
-} # sub openfile
+} # end openoutfile
+# save ivy messages into a file
+# called by selectandsavefile(), quit() and bye() (if -out option defined) functions
sub save {
- my $of = &openfile();
+ my $file = shift;
+ &showProgressbar("Saving data...");
+ unless (defined $file) {
+ if (defined $ivyoutputfile) {
+ $file = $ivyoutputfile;
+ } elsif (defined $opt_out) {
+ $file = $opt_out;
+ } else {
+ my ($d, $m, $y, $h, $M) = (localtime(time))[3,4,5,2,1];
+ $file = sprintf("ivylog%02s%02s%02s_%02s:%02s.ivy", $d, $m, $y, $h, $M);
+ }
+ }
+ my $of = &openoutfile($file);
return $of unless $of == 1;
- my $tpl = $mw->Toplevel;
- $tpl->Popup;
- $tpl->title("Save");
- $tpl->geometry("200x50");
- $tpl->Label(-text => "Saving data...")->pack(-expand => 1, -fill => 'both');
+ my $t0 = time();
# save connected applications name
my @clients = $clientsListbox->get(0, 'end');
print OUT "applications=", join(',', @clients),"\n" or return -1;
@@ -2306,67 +2693,107 @@ sub save {
#print "nblines=$nblines\n";
$nblines =~ s/\.\d+$//;
$nblines -= 2;
- $progressbar->configure(-to => $nblines);
- my $step = int($nblines/10);
- #print "step=$step\n";
- print OUT "messages_number=$nblines\n" or return -1;
+ my $nbuf = scalar(@databuffer);
+ my $totnb = $nbuf + $nblines;
+ &configProgressbar($totnb);
+ $progressbar_tpl->title("Saving! Be patient...") if $totnb > 1000000;
+
+ print OUT "messages_number=$totnb\n" or return -1;
# save messages 100 by 100, in order to reduce memory usage
my $index = "1.0";
my $counter = 0;
while(1) {
my $messages = $messagesText->get($index, "$index + 100 lines");
$index = "$index + 100 lines";
+ # if less than 100 are to be treated...
unless ($messages) {
&setProgressbar($nblines);
- $progressbar->update;
last;
}
print OUT $messages or return -1;
- &setProgressbar($counter);
$counter += 100;
- $progressbar->update if ($step == 0 or $counter % $step == 0);
+ &setProgressbar($counter);
}
- &setProgressbar(0);
- $mw->after(300, sub {$tpl->destroy;});
- $tpl->waitWindow;
+ # then save bufferized msgs
+ for (my $j = 0; $j < scalar(@databuffer); $j++) {
+ $counter++;
+ if ($databuffer[$j]->[0] eq "ivymon_marker") {
+ print OUT "$databuffer[$j]->[1]\n";
+ } elsif ($databuffer[$j]->[0] eq "ivymon_comment") {
+ print OUT "comment=$databuffer[$j]->[1]\n";
+ } else {
+ my ($sender, $message, $time) = @{$databuffer[$j]};
+ print OUT "$sender $time \"$message\"\n" or return -1;
+ }
+ &setProgressbar($counter);
+ }
+ close(OUT);
+ my $dt_sec = time() - $t0;
+ my $dt_min = int($dt_sec / 60);
+ $dt_sec = $dt_sec % 60;
+ print "Saving duration = ".$dt_min."m".$dt_sec."s\n";
+ $datasaved = 1;
return 1;
} # end save
+#----------------------------------------------------------------------------------
+# Functions related to the progress bar
+#----------------------------------------------------------------------------------
sub showProgressbar {
+ my $title = shift;
+ $progressbar_tpl->title($title);
$progressbar->value(0);
- $progressbar->toplevel->deiconify;
- $progressbar->toplevel->raise($mw);
+ $progressbar_tpl->Popup(-popover => $mw, -popanchor => 'c');
+ $progressbar_tpl->raise($mw);
} # end showProgressbar
sub hideProgressbar {
- $progressbar->toplevel->withdraw;
+ $progressbar_tpl->withdraw;
} # end hideProgressbar
sub setProgressbar {
- my ($line, $step) = @_;
+ my ($line) = @_;
+ return unless ($progressbar_step == 0 or $line % $progressbar_step == 0);
$progressbar->value($line);
- $progressbar->toplevel->raise($mw);
- return unless defined $step;
- $progressbar->update if ($step == 0 or $line % $step == 0);
+ $progressbar->idletasks;
+ $progressbar_tpl->raise($mw);
} # end setProgressbar
+sub configProgressbar {
+
+ my $lc = shift;
+ $progressbar_step = 0;
+
+ if (not defined $lc) {
+ $lc = 0;
+ while(<IN>) {
+ $lc++;
+ }
+ seek(IN, 0, 0);
+ }
+ # don't reduce $step value ($progressbar_max/10 is a good value)
+ $progressbar_step = int($lc/10);
+ $progressbar->configure(-to => $progressbar_step*10);
+ return $lc;
+
+} # end configProgressbar
#----------------------------------------------------------------------------------
-# General functions
+# Utils functions
#----------------------------------------------------------------------------------
-sub enlarge {
+sub enlarge_bindingsfm {
@packinfo = ();
push(@packinfo, [$bindings_fm->packInfo]);
@@ -2375,13 +2802,38 @@ sub enlarge {
push(@packinfo, [$searchandcontrol_fm->packInfo]);
$searchandcontrol_fm->packForget;
$clients_fm->packForget;
+ $send_fm->packForget;
+ $bindings_fm->pack(-expand => 1);
+
+} # end enlarge_bindingsfm
+
+
+sub shrink_bindingsfm {
+
$bindings_fm->packForget;
+ $bindings_fm->pack(@{$packinfo[0]});
+ $clients_fm->pack(@{$packinfo[1]});
+ $send_fm->pack(@{$packinfo[2]});
+ $searchandcontrol_fm->pack(@{$packinfo[3]});
+
+} # end shrink_bindingsfm
+
+sub enlarge_sendfm {
+
+ @packinfo = ();
+ push(@packinfo, [$bindings_fm->packInfo]);
+ push(@packinfo, [$clients_fm->packInfo]);
+ push(@packinfo, [$send_fm->packInfo]);
+ push(@packinfo, [$searchandcontrol_fm->packInfo]);
+ $searchandcontrol_fm->packForget;
+ $clients_fm->packForget;
+ $bindings_fm->packForget;
-} # end expand
+} # end enlarge_sendfm
-sub shrink {
+sub shrink_sendfm {
$send_fm->packForget;
$bindings_fm->pack(@{$packinfo[0]});
@@ -2389,7 +2841,7 @@ sub shrink {
$send_fm->pack(@{$packinfo[2]});
$searchandcontrol_fm->pack(@{$packinfo[3]});
-} # end shrink
+} # end shrink_sendfm
sub wheelmousebindings {
@@ -2518,6 +2970,19 @@ sub findRvalue {
} # end findRvalue
+sub fmt_size {
+ my ($size) = shift;
+ my $unit = 'B';
+ if ($size >= 1024*1024) {
+ $unit = "MB";
+ $size = sprintf("%.0f", $size/(1024*1024));
+ } elsif ($size >= 1024) {
+ $unit = "kB";
+ $size = sprintf("%.0f", $size/1024);
+ }
+ return($size.$unit);
+}
+
sub warning1 {
my $widget = shift;
$widget->configure(-background => 'gray90');
@@ -2544,10 +3009,13 @@ sub warning3 {
} # end warning3
+# called on INT/QUIT signals or die messages.
sub quit {
print "Quit\n";
- $mw->Tk::Error("$!\n") if &save < 0;
+ if (defined $opt_out and not $datasaved) {
+ $mw->Tk::Error("$!\n") if &save() < 0;
+ }
exit;
} # end quit
@@ -2562,28 +3030,28 @@ ivymon - a graphical application for monitoring Ivy
=head1 SYNOPSIS
-B<ivymon> [B<-b> ivybus] [B<-help>] [B<-history> size]
+B<ivymon> [B<-b> ivybus] [B<-help>] [B<-history> size] [B<-buf>]
[B<-size> window size] [B<-undersize>]
[B<-bind> regexpB<1>] ... [B<-bind> regexpB<N>]
[B<-send> messageB<1>] ... [B<-send> messageB<N>]
- [B<-out> outputfile] [standard X11 options...]
+ [B<-out> outputfile] [-verbose] [standard X11 options...]
[INPUT-FILE]
=head1 DESCRIPTION
IvyMon is dedicated to monitor an Ivy bus. It prints out messages that match regular expressions, lets you send messages on bus and provides a keywords search interface.
-The main area is the window labeled B<Messages> where are printed messages that forward on bus. Each message is preceded by sender application's name. You can insert a colored marker by double-clicking between two messages.
+The main frame is the window labeled B<Messages> where are printed messages that forward on bus. Each message is preceded by sender application's name. You can insert a colored marker by double-clicking between two messages.
-The B<Applications> area lists the connected applications names. When you select an item in the listbox, the messages sent by this application are highlighted. You can display the agent's bindings or kill an agent by using the dedicated buttons.
+The B<Applications> frame lists the connected applications names. When you select an item in the listbox, the messages sent by this application are highlighted. You can display the agent's bindings or kill an agent by using the dedicated buttons.
-The B<Bindings> area is used to manage regular expressions to subscribe to ivy messages. It provides an input field to enter new regexp, a first listbox which contains an alphabetical list of available bindings, and a second listbox of effective bindings. To bind a new regular expression, double-click on the corresponding item in the first list or select one, edit it in the input field and then hit the I<Return> key to validate. To remove subscription, double-click on the corresponding item in the second listbox. Pressing the I<Escape> key inserts I<(.*)> string in entry field. This field provides completion and history functionalities. The bindings of connected ivy agents are automaticalley added to the list. You can add your own bindings using the I<-bind> option.
+The B<Bindings> frame is used to manage regular expressions to subscribe to ivy messages. It provides an input field to enter new regexp, a first listbox which contains an alphabetical list of available bindings, and a second listbox of effective bindings. To bind a new regular expression, double-click on the corresponding item in the first list or select one, edit it in the input field and then hit the I<Return> key to validate. To remove subscription, double-click on the corresponding item in the second listbox. Pressing the I<Escape> key inserts I<(.*)> string in entry field. This field provides completion and history functionalities. The bindings of connected ivy agents are automaticalley added to the list. You can add your own bindings using the I<-bind> option.
-The B<Messages to send> area is used to manage a list of predefined messages ready to be sent. It provides an input field to enter new message or edit existing one, and a listbox which contains an alphabetical list of available messages. When you validate an input (by pressing the I<Return> key), the new message is added to the listbox and sent on ivy bus. To send predefined messages, simply I<double-click> on corresponding item in the listbox. This field provides completion and history functionalities, and assistance for entering values. The application fits the bindings of connected ivy agents to build this list. You can add your own messages using the I<-send> option.
+The B<Messages to send> frame is used to manage a list of predefined messages ready to be sent. It provides an input field to enter new message or edit existing one, and a listbox which contains an alphabetical list of available messages. When you validate an input (by pressing the I<Return> key), the new message is added to the listbox and sent on ivy bus. To send predefined messages, simply I<double-click> on corresponding item in the listbox. This field provides completion and history functionalities, and assistance for entering values. The application fits the bindings of connected ivy agents to build this list. You can add your own messages using the I<-send> option.
-The B<Search> area provides an interface for searching pattern in messages window. It provides an input field to enter new pattern, and control buttons. To highlight all matches, press the I<All> button. To make incremental search, press the I<Next> button or the I<Return> key to proceed forward, and press the I<Previous> button or the I<Shift-Return> key to proceed backward. This field provides an history functionality.
+The B<Search> frame provides an interface for searching pattern in messages window. It provides an input field to enter new pattern, and control buttons. To highlight all matches, press the I<All> button. To make incremental search, press the I<Next> button or the I<Return> key to proceed forward, and press the I<Previous> button or the I<Shift-Return> key to proceed backward. This field provides an history functionality.
-The B<Control> panel contains some general control buttons. Set or unset balloon help functionality with the I<Balloon help> checkbutton. Stop the messages scrolling with the I<Scroll lock> button. You must do it if you want to insert a marker in the messages window. Restart scrolling with the I<Scroll> button. To access markers sequentially, press the I<Jump> button. With the I<Load> and I<Save> buttons, you can select input and output files. The I<Clear> button removes all displayed messages. At last, the I<Exit> button closes the application.
+The B<Control> panel contains some general control buttons. Set or unset balloon help functionality with the I<Balloon help> checkbutton. Stop the messages scrolling with the I<Scroll Lock> button. You must do it if you want to insert a marker in the messages window. Restart scrolling with the I<Scroll> button. To access markers sequentially, press the I<Jump> button. With the I<Load> and I<Save> buttons, you can select input and output files. The I<Clear> button removes all displayed messages. At last, the I<Exit> button closes the application.
=head1 OPTIONS
@@ -2596,11 +3064,15 @@ Set the bus domain and port number to be used. Use $IVYBUS variable if defined.
=item B<-help>
-Get some help
+Get some help.
+
+=item B<-buf>
-=item B<-history> size
+Bufferize received messages from the begining. To display them in the 'Messages' window, you need to press the Scroll button. Use this option when ivymon is intended to receive very large flows of messages.
-Set the history size of messages window (default: 200000). If ivymon receives more messages, they won't be displayed neither stored.
+=item B<-history> size, minutes_number or infinite
+
+Set the history size of kept messages (default: 200000). If size is integer, only the <size> first received messages will be kept. If size ends with 'm' character, only the messages received during the <size> first minutes will be kept. If size is set to 'infinite', ivymon will keep all messages.
=item B<-size> window size
@@ -2620,14 +3092,18 @@ Add an ivy message in the list of potential messages to send. This option may be
=item B<-out> output file
-Specify the output filename and pass in storage mode : the content of the Messages area will be written to file when you exit the application. You can do manually the same using the B<Save> button. Note that output filename can be set or updated by sending the following message "Ivymon Output=<filename>".
+Specify the output filename and pass in storage mode : the content of the Messages frame will be written to file when you exit the application excepted if the B<Save> function was invoked manually. Note that output filename can be set or updated by sending the following message "Ivymon Output=<filename>". This option guarantees that data will be saved even if ivymon is interrupted (by Ctrl-C or ivy die message)
+
+=item B<-verbose>
+
+If set, periodically print some informations to stdout : running time, messages counters, messages size and such like.
=back
=head1 EXAMPLE
-ivymon -b 10.192.36.255:3456 -history 20000 -bind 'PLN:(.*) SectorActivation sector=(.*)' -bind 'CLOCK start' -send 'TRAFFIC RadarEnd' -send 'AIRCRAFT: Activated' -size SVGA -undersize
+ivymon -b 10.192.36.255:3456 -history 30m -bind 'PLN:(.*) SectorActivation sector=(.*)' -bind 'CLOCK start' -send 'TRAFFIC RadarEnd' -send 'AIRCRAFT: Activated' -size SVGA -undersize
=head1 HISTORY
diff --git a/src/ivyreplay b/src/ivyreplay
index e1ab41b..b4d9adb 100755
--- a/src/ivyreplay
+++ b/src/ivyreplay
@@ -23,7 +23,7 @@ use vars qw/$opt_help $opt_b $opt_bus
$opt_repeat $opt_startregexp $opt_padding
$opt_stopregexp $opt_timegranularity $opt_debug/;
-our $VERSION = '1.24';
+our $VERSION = '1.25';
# geometry
@@ -62,8 +62,8 @@ my $replay_fg = 'black';
my $replay_bg_orig;
my $replay_fg_orig;
my $replay_hour;
-$opt_startregexp = '^ClockStart\$';
-$opt_stopregexp = '^ClockStop\$';
+$opt_startregexp = '^ClockStart$';
+$opt_stopregexp = '^ClockStop$';
my $padding = 2;
#----------------------------------------------------------------------------------
@@ -114,20 +114,9 @@ if ($opt_bus) {
} elsif ($opt_b) {
$ivy_port = $opt_b;
}
-my $title;
-my $ivy_version = $Ivy::VERSION;
-my $ivy_cvsrevision = 0;
-my $ivy_versionstring = "v$ivy_version";
-if ($ivy_version =~ s/Revision: (.*)//) {
- $ivy_version = $1;
- $ivy_cvsrevision = 1;
- $ivy_versionstring = "v$ivy_version (cvs revision)";
-}
-if ($ivy_port) {
- $title = "Ivyreplay ($ivy_port) - Ivy $ivy_versionstring";
-} else {
- $title = "Ivyreplay (default port) - Ivy $ivy_versionstring";
-}
+my $title = "Ivyreplay v$VERSION ";
+$title .= ($ivy_port) ? "($ivy_port)" : "(default port)";
+
$replay_time_granularity = $opt_timegranularity if $opt_timegranularity > 0;
if ($replay_time_granularity >= 1) {
$replay_time_decimalplaces = 0;
@@ -202,34 +191,35 @@ $ivy->start;
# load input files
my @files = @ARGV;
-my $lines = 0;
my $steps = 0;
if (@files == 0) {
$mw->Tk::Error("Error : an input file is expected");
} else {
- &showProgressbar();
- for my $file (@files) {
- if (not open(IN, $file)) {
- $mw->Tk::Error("Can't open file '$file' ($!)");
- next;
- } else {
- my ($l, $timefound) = &stepsnumber;
- $lines += $l;
- if ($timefound) {
+ &showProgressbar("Loading file...");
+ my $file = $files[0];
+ if (not open(IN, $file)) {
+ $mw->Tk::Error("Can't open file '$file' ($!)");
+ } else {
+ my ($lines, $timefound) = &stepsnumber;
+ $title .= " - $lines messages";
+ $mw->title($title);
+ $steps = int($lines/10);
+ $progressbar->configure(-to => $steps*10);
+ if ($timefound) {
&loadfileForReplay();
- } else {
+ &hideProgressbar();
+ } else {
$mw->Tk::Error("No time information in file '$file'. ".
"Can't be replayed.");
- next;
- }
+ }
}
close(IN);
- }
- $steps = int($lines/10);
- $progressbar->configure(-to => 10);
- &displayMessages() unless $opt_light;
- &hideProgressbar();
- &replayStart() if $opt_autostart;
+ unless ($opt_light) {
+ &showProgressbar("Displaying msgs...");
+ &displayMessages();
+ &hideProgressbar();
+ }
+ &replayStart() if $opt_autostart;
}
MainLoop;
@@ -255,7 +245,7 @@ sub stepsnumber {
while(<IN>) {
chomp;
next if (/^applications=/ or /^(marker\d+)$/ or /^(messages_number=)/
- or /^\#/ or /^delay=/);
+ or /^\#/ or /^delay=/ or /^comment=/ or /^\s*$/);
my ($sender, $message) = split(/\s+/, $_, 2);
if ($message =~ /^(\d[\d\.]+\d)\s+.*/) {
$timefound = 1;
@@ -387,15 +377,15 @@ sub build {
sub loadfileForReplay {
-
# display messsages to replay
my ($sender, $time, $message);
my $delay = 0;
+ my $line = 0;
while(<IN>) {
chomp;
next if /^\#/ or /^applications=/ or /^messages_number=/
- or /^\s*$/ or /^(marker\d+)$/;
+ or /^\s*$/ or /^(marker\d+)$/ or /^comment=/;
if (/^delay=(\d.*)/) {
if ($1 < 0) {
carp "delay (=$1) must be >=0\n";
@@ -405,6 +395,7 @@ sub loadfileForReplay {
#print "delay=$delay\n";
next;
}
+ $line++;
($sender, $time, $message) = split(/\s+/, $_, 3);
$time += $delay;
if ($replay_time_granularity >= 1) {
@@ -425,6 +416,7 @@ sub loadfileForReplay {
$message =~ s/^\"//;
$message =~ s/\"$//;
push(@{$replay_msg{$time}}, $message);
+ &setProgressbar($line);
}
$mw->raise;
$replay_time = $replay_min_time;
@@ -446,9 +438,7 @@ sub displayMessages {
$replay_text->insert('end', &replayTime($time)." ".$message."\n", $time);
$line++;
- if ($steps != 0) {
- &setProgressbar($line/$steps) if $line % $steps == 0;
- }
+ &setProgressbar($line);
# when user click on a message the begin time changes.
$replay_text->tagBind($time, '<1>', [sub {
my $ti = $_[1];
@@ -478,13 +468,13 @@ sub displayMessages {
}
$replay_text->configure(-state => 'disabled') if $replay_text;
-
}
sub showProgressbar {
+ $progressbar->toplevel->title(shift);
$progressbar->value(0);
- $progressbar->toplevel->deiconify;
+ $progressbar->toplevel->Popup(-popover => $mw, -popanchor => 'c');
$progressbar->toplevel->raise($mw);
} # end showProgressbar
@@ -500,6 +490,7 @@ sub hideProgressbar {
sub setProgressbar {
my ($line) = @_;
+ return unless ($steps == 0 or $line % $steps == 0);
$progressbar->value($line);
$progressbar->toplevel->raise($mw);
$progressbar->update;