| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package ProgressMonitor::Stringify::AbstractMonitor; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 10 |  |  | 10 |  | 10108 | use warnings; | 
|  | 10 |  |  |  |  | 29 |  | 
|  | 10 |  |  |  |  | 480 |  | 
| 4 | 10 |  |  | 10 |  | 60 | use strict; | 
|  | 10 |  |  |  |  | 21 |  | 
|  | 10 |  |  |  |  | 358 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 10 |  |  | 10 |  | 980884 | use ProgressMonitor::Exceptions; | 
|  | 10 |  |  |  |  | 131 |  | 
|  | 10 |  |  |  |  | 695 |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  | require ProgressMonitor::AbstractStatefulMonitor if 0; | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | # Attributes: | 
| 11 |  |  |  |  |  |  | #	width | 
| 12 |  |  |  |  |  |  | #		The final width the field(s) this monitor manages will occupy | 
| 13 |  |  |  |  |  |  | use classes | 
| 14 | 10 |  |  |  |  | 70 | extends       => 'ProgressMonitor::AbstractStatefulMonitor', | 
| 15 |  |  |  |  |  |  | class_methods => ['_new'], | 
| 16 |  |  |  |  |  |  | attrs_ro      => ['width',], | 
| 17 |  |  |  |  |  |  | attrs_pr      => ['msgto'], | 
| 18 | 10 |  |  | 10 |  | 66 | ; | 
|  | 10 |  |  |  |  | 18 |  | 
| 19 |  |  |  |  |  |  |  | 
| 20 | 10 |  |  | 10 |  | 8330 | use ProgressMonitor::SubTask; | 
|  | 10 |  |  |  |  | 38 |  | 
|  | 10 |  |  |  |  | 311 |  | 
| 21 | 10 |  |  | 10 |  | 65 | use ProgressMonitor::SetMessageFlags; | 
|  | 10 |  |  |  |  | 16 |  | 
|  | 10 |  |  |  |  | 14451 |  | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | sub _new | 
| 24 |  |  |  |  |  |  | { | 
| 25 | 11 |  |  | 11 |  | 24 | my $class  = shift; | 
| 26 | 11 |  |  |  |  | 24 | my $cfg    = shift; | 
| 27 | 11 |  |  |  |  | 27 | my $cfgPkg = shift; | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | # get the instance from the super class | 
| 30 |  |  |  |  |  |  | # | 
| 31 | 11 |  |  |  |  | 123 | my $self = $class->SUPER::_new($cfg, $cfgPkg); | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | # retrieve the configuration for easy reference | 
| 34 |  |  |  |  |  |  | # | 
| 35 | 11 |  |  |  |  | 100 | $cfg = $self->_get_cfg; | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  | # what max width has the user asked for? | 
| 38 |  |  |  |  |  |  | # | 
| 39 | 11 |  |  |  |  | 39 | my $maxWidth = $cfg->get_maxWidth; | 
| 40 |  |  |  |  |  |  |  | 
| 41 | 11 |  |  |  |  | 80 | my $allFields = $cfg->get_fields; | 
| 42 |  |  |  |  |  |  |  | 
| 43 |  |  |  |  |  |  | # what is the minimum combined width needed to begin with? | 
| 44 |  |  |  |  |  |  | # | 
| 45 | 11 |  |  |  |  | 48 | my $wsum = 0; | 
| 46 | 11 |  |  |  |  | 100 | $wsum += $_->get_width for (@$allFields); | 
| 47 | 11 | 50 |  |  |  | 96 | print STDERR ("WARNING: Insufficient width for monitor ($maxWidth < $wsum). Feedback output will not display properly.\n") if $wsum > $maxWidth; | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | # now try to make the stringification fit 'best possible' | 
| 50 |  |  |  |  |  |  | # | 
| 51 | 11 |  |  |  |  | 24 | my $remainingWidth = $maxWidth - $wsum; | 
| 52 | 11 | 50 |  |  |  | 54 | if ($remainingWidth < 0) | 
| 53 |  |  |  |  |  |  | { | 
| 54 |  |  |  |  |  |  | # in this case, the available line is too short | 
| 55 |  |  |  |  |  |  | # | 
| 56 |  |  |  |  |  |  | # just set the width we can use, regardless | 
| 57 |  |  |  |  |  |  | # | 
| 58 | 0 |  |  |  |  | 0 | $self->{$ATTR_width} = $maxWidth; | 
| 59 |  |  |  |  |  |  | } | 
| 60 |  |  |  |  |  |  | else | 
| 61 |  |  |  |  |  |  | { | 
| 62 |  |  |  |  |  |  | # in this case, the line may provide extra space for dynamic fields to get more | 
| 63 |  |  |  |  |  |  | # than they minimally need, which may make them look nicer | 
| 64 |  |  |  |  |  |  | # | 
| 65 |  |  |  |  |  |  | # in a round robin fashion, try to fairly give dynfields | 
| 66 |  |  |  |  |  |  | # extra width until all are full, or width is exhausted | 
| 67 |  |  |  |  |  |  | # | 
| 68 |  |  |  |  |  |  |  | 
| 69 |  |  |  |  |  |  | # first make a separate list of the dynamic fields | 
| 70 |  |  |  |  |  |  | # | 
| 71 | 11 |  |  |  |  | 18 | my @dynFields; | 
| 72 | 11 |  |  |  |  | 31 | for (@$allFields) | 
| 73 |  |  |  |  |  |  | { | 
| 74 | 11 | 50 |  |  |  | 84 | push(@dynFields, $_) if $_->isDynamic; | 
| 75 |  |  |  |  |  |  | } | 
| 76 |  |  |  |  |  |  |  | 
| 77 |  |  |  |  |  |  | # begin with the width we have left to give out | 
| 78 |  |  |  |  |  |  | # and loop while there is any width left and there are any dynamic fields | 
| 79 |  |  |  |  |  |  | # that are 'still hungry'... | 
| 80 |  |  |  |  |  |  | # | 
| 81 | 11 |  | 33 |  |  | 99 | while ($remainingWidth && @dynFields) | 
| 82 |  |  |  |  |  |  | { | 
| 83 | 0 |  |  |  |  | 0 | my $dynFieldCount = @dynFields; | 
| 84 |  |  |  |  |  |  |  | 
| 85 |  |  |  |  |  |  | # make a list with the current width we have fairly distributed | 
| 86 |  |  |  |  |  |  | # | 
| 87 | 0 |  |  |  |  | 0 | my @allotments; | 
| 88 | 0 |  |  |  |  | 0 | $allotments[$_ % $dynFieldCount]++ for (0 .. ($remainingWidth - 1)); | 
| 89 |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  | # now iterate over the list and give the corresponding dynfield the | 
| 91 |  |  |  |  |  |  | # width it has been allotted. | 
| 92 |  |  |  |  |  |  | # it will report how much it 'used' (due to its own constraints, if any) | 
| 93 |  |  |  |  |  |  | # and we can disseminate remains in the next loop | 
| 94 |  |  |  |  |  |  | # | 
| 95 | 0 |  |  |  |  | 0 | for (0 .. (@allotments - 1)) | 
| 96 |  |  |  |  |  |  | { | 
| 97 | 0 |  |  |  |  | 0 | my $allottedExtraWidth = $allotments[$_]; | 
| 98 | 0 |  |  |  |  | 0 | my $unusedExtraWidth   = $dynFields[$_]->grabExtraWidth($allottedExtraWidth); | 
| 99 | 0 |  |  |  |  | 0 | $remainingWidth -= $allottedExtraWidth - $unusedExtraWidth; | 
| 100 |  |  |  |  |  |  | } | 
| 101 |  |  |  |  |  |  |  | 
| 102 |  |  |  |  |  |  | # now recalculate the list with dynfields (any fields that have | 
| 103 |  |  |  |  |  |  | # reached their max width are no longer (dynamic') | 
| 104 |  |  |  |  |  |  | # | 
| 105 | 0 |  |  |  |  | 0 | @dynFields = (); | 
| 106 | 0 |  |  |  |  | 0 | for (@$allFields) | 
| 107 |  |  |  |  |  |  | { | 
| 108 | 0 | 0 |  |  |  | 0 | push(@dynFields, $_) if $_->isDynamic; | 
| 109 |  |  |  |  |  |  | } | 
| 110 |  |  |  |  |  |  | } | 
| 111 |  |  |  |  |  |  |  | 
| 112 |  |  |  |  |  |  | # finally set the width we've actually used | 
| 113 |  |  |  |  |  |  | # | 
| 114 | 11 |  |  |  |  | 151 | $self->{$ATTR_width} = $maxWidth - $remainingWidth; | 
| 115 |  |  |  |  |  |  | } | 
| 116 |  |  |  |  |  |  |  | 
| 117 | 11 |  |  |  |  | 41 | return $self; | 
| 118 |  |  |  |  |  |  | } | 
| 119 |  |  |  |  |  |  |  | 
| 120 |  |  |  |  |  |  | sub setMessage | 
| 121 |  |  |  |  |  |  | { | 
| 122 | 200 |  |  | 200 | 0 | 808 | my $self = shift; | 
| 123 | 200 |  |  |  |  | 245 | my $msg  = shift; | 
| 124 | 200 |  | 50 |  |  | 747 | my $when = shift || SM_NOW; | 
| 125 |  |  |  |  |  |  |  | 
| 126 | 200 | 50 |  |  |  | 558 | $self->{$ATTR_msgto} = undef if $when == SM_NOW; | 
| 127 |  |  |  |  |  |  |  | 
| 128 | 200 |  |  |  |  | 674 | return $self->SUPER::setMessage($msg, $when); | 
| 129 |  |  |  |  |  |  | } | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | sub subMonitor | 
| 132 |  |  |  |  |  |  | { | 
| 133 | 0 |  |  | 0 | 0 | 0 | my $self   = shift; | 
| 134 | 0 |  | 0 |  |  | 0 | my $subCfg = shift || {}; | 
| 135 |  |  |  |  |  |  |  | 
| 136 | 0 |  |  |  |  | 0 | $subCfg->{parent} = $self; | 
| 137 | 0 |  |  |  |  | 0 | return ProgressMonitor::SubTask->new($subCfg); | 
| 138 |  |  |  |  |  |  | } | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  | sub setErrorMessage | 
| 141 |  |  |  |  |  |  | { | 
| 142 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 143 | 0 |  |  |  |  | 0 | my $msg  = shift; | 
| 144 |  |  |  |  |  |  |  | 
| 145 | 0 |  |  |  |  | 0 | return $msg; | 
| 146 |  |  |  |  |  |  | } | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | ### protected | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  | sub _get_message | 
| 151 |  |  |  |  |  |  | { | 
| 152 | 600 |  |  | 600 |  | 726 | my $self = shift; | 
| 153 |  |  |  |  |  |  |  | 
| 154 | 600 |  |  |  |  | 796 | my $now = time; | 
| 155 | 600 | 50 |  |  |  | 1643 | if (defined($self->{$ATTR_msgto})) | 
| 156 |  |  |  |  |  |  | { | 
| 157 | 0 | 0 |  |  |  | 0 | $self->_set_message(undef) if ($self->{$ATTR_msgto} <= $now); | 
| 158 |  |  |  |  |  |  | } | 
| 159 |  |  |  |  |  |  | else | 
| 160 |  |  |  |  |  |  | { | 
| 161 | 600 |  |  |  |  | 1608 | my $to = $self->_get_cfg->get_messageTimeout; | 
| 162 | 600 | 50 |  |  |  | 3104 | $self->{$ATTR_msgto} = time + $to if $to >= 0; | 
| 163 |  |  |  |  |  |  | } | 
| 164 |  |  |  |  |  |  |  | 
| 165 | 600 |  |  |  |  | 1966 | return $self->SUPER::_get_message; | 
| 166 |  |  |  |  |  |  | } | 
| 167 |  |  |  |  |  |  |  | 
| 168 |  |  |  |  |  |  | sub _set_message | 
| 169 |  |  |  |  |  |  | { | 
| 170 | 220 |  |  | 220 |  | 264 | my $self = shift; | 
| 171 | 220 |  |  |  |  | 373 | my $msg  = shift; | 
| 172 |  |  |  |  |  |  |  | 
| 173 | 220 |  |  |  |  | 362 | $self->{$ATTR_msgto} = undef; | 
| 174 |  |  |  |  |  |  |  | 
| 175 | 220 |  |  |  |  | 633 | return $self->SUPER::_set_message($msg); | 
| 176 |  |  |  |  |  |  | } | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  | # helper method to call each field and render a complete line | 
| 179 |  |  |  |  |  |  | # | 
| 180 |  |  |  |  |  |  | sub _toString | 
| 181 |  |  |  |  |  |  | { | 
| 182 | 411 |  |  | 411 |  | 533 | my $self            = shift; | 
| 183 | 411 |  |  |  |  | 498 | my $considerMessage = shift(); | 
| 184 |  |  |  |  |  |  |  | 
| 185 | 411 | 50 |  |  |  | 907 | $considerMessage = 1 unless defined($considerMessage); | 
| 186 |  |  |  |  |  |  |  | 
| 187 | 411 |  |  |  |  | 1072 | my $state      = $self->_get_state; | 
| 188 | 411 |  |  |  |  | 1056 | my $ticks      = $self->_get_ticks; | 
| 189 | 411 |  |  |  |  | 1162 | my $totalTicks = $self->_get_totalTicks; | 
| 190 |  |  |  |  |  |  |  | 
| 191 | 411 |  |  |  |  | 1115 | my $cfg       = $self->_get_cfg; | 
| 192 | 411 |  |  |  |  | 999 | my $ms        = $cfg->get_messageStrategy; | 
| 193 | 411 |  |  |  |  | 2097 | my $msg       = $self->_get_message; | 
| 194 | 411 |  |  |  |  | 583 | my $rendition = ''; | 
| 195 |  |  |  |  |  |  |  | 
| 196 | 411 |  |  |  |  | 505 | my $forceNewline = 0; | 
| 197 | 411 | 50 |  |  |  | 1140 | if ($ms eq 'overlay_newline') | 
|  |  | 50 |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | { | 
| 199 | 0 |  |  |  |  | 0 | $forceNewline = 1; | 
| 200 |  |  |  |  |  |  | } | 
| 201 |  |  |  |  |  |  | elsif ($ms eq 'overlay_honor_newline') | 
| 202 |  |  |  |  |  |  | { | 
| 203 | 0 |  | 0 |  |  | 0 | $forceNewline = ($msg && $msg =~ /\n$/); | 
| 204 |  |  |  |  |  |  | } | 
| 205 |  |  |  |  |  |  |  | 
| 206 | 411 |  |  |  |  | 1251 | my $allFields = $cfg->get_fields; | 
| 207 | 411 |  |  |  |  | 1929 | for (@$allFields) | 
| 208 |  |  |  |  |  |  | { | 
| 209 |  |  |  |  |  |  | # ask each field to render itself but ensure the result is exactly the width is | 
| 210 |  |  |  |  |  |  | # what its supposed to be | 
| 211 |  |  |  |  |  |  | # | 
| 212 | 411 |  | 33 |  |  | 2166 | my $fr = $_->render($state, $ticks, $totalTicks, ($forceNewline && $considerMessage && $msg)); | 
| 213 | 411 |  |  |  |  | 2419 | my $fw = $_->get_width; | 
| 214 | 411 |  |  |  |  | 3155 | $rendition .= sprintf("%*.*s", $fw, $fw, $fr); | 
| 215 |  |  |  |  |  |  | } | 
| 216 |  |  |  |  |  |  |  | 
| 217 | 411 | 50 |  |  |  | 1349 | if (!$cfg->get_allowOverflow) | 
| 218 |  |  |  |  |  |  | { | 
| 219 |  |  |  |  |  |  | # we must make sure the width of the rendition won't cause linewrapping | 
| 220 |  |  |  |  |  |  | # | 
| 221 | 411 |  |  |  |  | 2360 | my $w = $self->{$ATTR_width}; | 
| 222 | 411 | 50 |  |  |  | 1066 | $rendition = sprintf("%*.*s", $w, $w, $rendition) if (length($rendition) > $w); | 
| 223 |  |  |  |  |  |  | } | 
| 224 |  |  |  |  |  |  |  | 
| 225 | 411 | 100 |  |  |  | 1406 | if ($considerMessage) | 
| 226 |  |  |  |  |  |  | { | 
| 227 | 222 | 100 | 66 |  |  | 1046 | if ($msg && $ms ne 'none') | 
| 228 |  |  |  |  |  |  | { | 
| 229 | 40 |  |  |  |  | 70 | my $w = $self->{$ATTR_width}; | 
| 230 |  |  |  |  |  |  |  | 
| 231 | 40 | 100 |  |  |  | 89 | if ($ms eq 'newline') | 
| 232 |  |  |  |  |  |  | { | 
| 233 |  |  |  |  |  |  | # accept embedded newlines, but ensure the message filler is applied (if set) | 
| 234 |  |  |  |  |  |  | # the split will also avoid stray empty lines at the end | 
| 235 |  |  |  |  |  |  | # | 
| 236 | 20 |  |  |  |  | 27 | my $fullMsg = ''; | 
| 237 | 20 |  |  |  |  | 62 | foreach my $msgLine (split(/\n/, $msg)) | 
| 238 |  |  |  |  |  |  | { | 
| 239 | 20 | 50 |  |  |  | 107 | $msgLine .= $cfg->get_messageFiller x ($w - length($msgLine)) if ($w > length($msgLine)); | 
| 240 | 20 |  |  |  |  | 135 | $fullMsg .= "$msgLine\n"; | 
| 241 |  |  |  |  |  |  | } | 
| 242 | 20 |  |  |  |  | 61 | $rendition = sprintf("%s%s", $fullMsg, $rendition); | 
| 243 | 20 |  |  |  |  | 45 | $self->_set_message(undef); | 
| 244 |  |  |  |  |  |  | } | 
| 245 |  |  |  |  |  |  | else | 
| 246 |  |  |  |  |  |  | { | 
| 247 |  |  |  |  |  |  | # overlay or overlay_newline or overlay_honor_newline | 
| 248 |  |  |  |  |  |  | # | 
| 249 | 20 |  |  |  |  | 48 | my $nlConversion = $cfg->get_messageOverlayNewlineConversion; | 
| 250 | 20 |  |  |  |  | 95 | my $start_ovrfld = $cfg->get_messageOverlayStartField; | 
| 251 | 20 |  |  |  |  | 86 | my $end_ovrfld   = $cfg->get_messageOverlayEndField; | 
| 252 | 20 |  |  |  |  | 62 | my $start_ovrpos; | 
| 253 |  |  |  |  |  |  | my $end_ovrpos; | 
| 254 | 20 |  |  |  |  | 22 | my $offset = 0; | 
| 255 | 20 |  |  |  |  | 40 | for (1 .. @$allFields) | 
| 256 |  |  |  |  |  |  | { | 
| 257 | 20 | 50 |  |  |  | 39 | $start_ovrpos = $offset if $start_ovrfld == $_; | 
| 258 | 20 |  |  |  |  | 49 | $offset += $allFields->[$_ - 1]->get_width; | 
| 259 | 20 | 50 |  |  |  | 79 | $end_ovrpos = $offset if $end_ovrfld == $_; | 
| 260 | 20 | 50 | 33 |  |  | 64 | last if ($start_ovrpos && $end_ovrpos); | 
| 261 |  |  |  |  |  |  | } | 
| 262 |  |  |  |  |  |  |  | 
| 263 | 20 |  |  |  |  | 51 | $msg =~ s/\n/$nlConversion/g; | 
| 264 | 20 |  |  |  |  | 46 | my $mf = $cfg->get_messageFiller; | 
| 265 | 20 | 50 |  |  |  | 88 | my $len = $mf ? $end_ovrpos - $start_ovrpos : length($msg); | 
| 266 | 20 | 50 |  |  |  | 50 | $msg .= $mf x ($len - length($msg)) if ($len > length($msg)); | 
| 267 |  |  |  |  |  |  |  | 
| 268 | 20 | 50 | 0 |  |  | 119 | if ($ms eq 'overlay' || ($ms eq 'overlay_honor_newline' && !$forceNewline)) | 
|  |  |  | 33 |  |  |  |  | 
| 269 |  |  |  |  |  |  | { | 
| 270 | 20 |  |  |  |  | 45 | substr($rendition, $start_ovrpos, $len) = sprintf("%*.*s", $len, $len, $msg); | 
| 271 |  |  |  |  |  |  | } | 
| 272 |  |  |  |  |  |  | else | 
| 273 |  |  |  |  |  |  | { | 
| 274 | 0 |  |  |  |  | 0 | substr($rendition, $start_ovrpos) = $msg; | 
| 275 |  |  |  |  |  |  | } | 
| 276 |  |  |  |  |  |  |  | 
| 277 | 20 | 50 |  |  |  | 55 | if ($forceNewline) | 
| 278 |  |  |  |  |  |  | { | 
| 279 | 0 |  |  |  |  | 0 | $rendition .= "\n"; | 
| 280 | 0 |  |  |  |  | 0 | $self->_set_message(undef); | 
| 281 |  |  |  |  |  |  | } | 
| 282 |  |  |  |  |  |  | } | 
| 283 |  |  |  |  |  |  | } | 
| 284 |  |  |  |  |  |  | } | 
| 285 |  |  |  |  |  |  |  | 
| 286 | 411 |  |  |  |  | 1586 | return $rendition; | 
| 287 |  |  |  |  |  |  | } | 
| 288 |  |  |  |  |  |  |  | 
| 289 |  |  |  |  |  |  | ### | 
| 290 |  |  |  |  |  |  |  | 
| 291 |  |  |  |  |  |  | package ProgressMonitor::Stringify::AbstractMonitorConfiguration; | 
| 292 |  |  |  |  |  |  |  | 
| 293 | 10 |  |  | 10 |  | 72 | use strict; | 
|  | 10 |  |  |  |  | 26 |  | 
|  | 10 |  |  |  |  | 326 |  | 
| 294 | 10 |  |  | 10 |  | 50 | use warnings; | 
|  | 10 |  |  |  |  | 17 |  | 
|  | 10 |  |  |  |  | 351 |  | 
| 295 |  |  |  |  |  |  |  | 
| 296 | 10 |  |  | 10 |  | 51 | use Scalar::Util qw(blessed); | 
|  | 10 |  |  |  |  | 19 |  | 
|  | 10 |  |  |  |  | 970 |  | 
| 297 |  |  |  |  |  |  |  | 
| 298 |  |  |  |  |  |  | # Attributes: | 
| 299 |  |  |  |  |  |  | #	maxWidth | 
| 300 |  |  |  |  |  |  | #		The maximum width this monitor can occupy altogether. | 
| 301 |  |  |  |  |  |  | #   allowOverflow | 
| 302 |  |  |  |  |  |  | #       In case the width is too small, let it overflow and linewrap. | 
| 303 |  |  |  |  |  |  | #       Else, cut the finished rendition so no linewrap occurs, but loses info. | 
| 304 |  |  |  |  |  |  | #	fields | 
| 305 |  |  |  |  |  |  | #		An array of fields (or a single field if only one) that should be used | 
| 306 |  |  |  |  |  |  | #		A field instance can not be reused in the list! | 
| 307 |  |  |  |  |  |  | #   messageStrategy | 
| 308 |  |  |  |  |  |  | #       Determines the strategy to use when displaying messages. | 
| 309 |  |  |  |  |  |  | #       'none'   : doesn't display messages | 
| 310 |  |  |  |  |  |  | #       'overlay': requires 'messageOverlaysFields' to be set | 
| 311 |  |  |  |  |  |  | #       'newline': renders the message only with a newline at the end, in | 
| 312 |  |  |  |  |  |  | #                  effect pushing the other fields 'down'. Handles and 'honors' | 
| 313 |  |  |  |  |  |  | #                  embedded newlines, trailing newlines are dropped. | 
| 314 |  |  |  |  |  |  | #		'overlay_newline' : combines the effects of 'overlay' and 'newline' | 
| 315 |  |  |  |  |  |  | #		'overlay_honor_newline' : acts as 'overlay', but will ensure to make a | 
| 316 |  |  |  |  |  |  | #                                 newline if the message has a trailing one. | 
| 317 |  |  |  |  |  |  | #   messageOverlayStartfield | 
| 318 |  |  |  |  |  |  | #       The field on which message overlay should start. Defaults to 0. | 
| 319 |  |  |  |  |  |  | #   messageOverlayEndfield | 
| 320 |  |  |  |  |  |  | #       The field on which message overlay should end. Defaults to last field. | 
| 321 |  |  |  |  |  |  | #   messageFiller | 
| 322 |  |  |  |  |  |  | #       The character for filling out the length of the message if | 
| 323 |  |  |  |  |  |  | #       is not long enough to overlay the full length of the field(s) | 
| 324 |  |  |  |  |  |  | #       it is set to overlay. | 
| 325 |  |  |  |  |  |  | #   messageTimeout | 
| 326 |  |  |  |  |  |  | #       The time in seconds before the message is cleared automatically. This | 
| 327 |  |  |  |  |  |  | #       is only relevant for overlay (for newline, it only appears once). | 
| 328 |  |  |  |  |  |  | #       Defaults to 3 seconds. Set to -1 for 'no timeout'. | 
| 329 |  |  |  |  |  |  | #	messageOverlayNewlineConversion | 
| 330 |  |  |  |  |  |  | #		For 'overlay' and 'overlay_newline', any embedded/trailing newlines | 
| 331 |  |  |  |  |  |  | #		will be converted to another string, settable by this cfg variable. | 
| 332 |  |  |  |  |  |  | #		Defaults to ' ' (space). | 
| 333 |  |  |  |  |  |  | # | 
| 334 |  |  |  |  |  |  | use classes | 
| 335 | 10 |  |  |  |  | 66 | extends => 'ProgressMonitor::AbstractStatefulMonitorConfiguration', | 
| 336 |  |  |  |  |  |  | attrs   => [ | 
| 337 |  |  |  |  |  |  | 'maxWidth',               'allowOverflow', 'fields', | 
| 338 |  |  |  |  |  |  | 'messageStrategy',        'messageOverlayStartField', | 
| 339 |  |  |  |  |  |  | 'messageOverlayEndField', 'messageFiller', | 
| 340 |  |  |  |  |  |  | 'messageTimeout',         'messageOverlayNewlineConversion' | 
| 341 |  |  |  |  |  |  | ], | 
| 342 | 10 |  |  | 10 |  | 50 | ; | 
|  | 10 |  |  |  |  | 21 |  | 
| 343 |  |  |  |  |  |  |  | 
| 344 |  |  |  |  |  |  | sub defaultAttributeValues | 
| 345 |  |  |  |  |  |  | { | 
| 346 | 11 |  |  | 11 |  | 25 | my $self = shift; | 
| 347 |  |  |  |  |  |  |  | 
| 348 |  |  |  |  |  |  | return { | 
| 349 | 11 |  |  |  |  | 24 | %{$self->SUPER::defaultAttributeValues()}, | 
|  | 11 |  |  |  |  | 107 |  | 
| 350 |  |  |  |  |  |  | maxWidth                        => 0, | 
| 351 |  |  |  |  |  |  | allowOverflow					=> 0, | 
| 352 |  |  |  |  |  |  | fields                          => [], | 
| 353 |  |  |  |  |  |  | messageStrategy                 => 'newline', | 
| 354 |  |  |  |  |  |  | messageOverlayStartField        => 1, | 
| 355 |  |  |  |  |  |  | messageOverlayEndField          => undef, | 
| 356 |  |  |  |  |  |  | messageFiller                   => ' ', | 
| 357 |  |  |  |  |  |  | messageTimeout                  => -1, | 
| 358 |  |  |  |  |  |  | messageOverlayNewlineConversion => ' ', | 
| 359 |  |  |  |  |  |  | }; | 
| 360 |  |  |  |  |  |  | } | 
| 361 |  |  |  |  |  |  |  | 
| 362 |  |  |  |  |  |  | sub checkAttributeValues | 
| 363 |  |  |  |  |  |  | { | 
| 364 | 11 |  |  | 11 |  | 45 | my $self = shift; | 
| 365 |  |  |  |  |  |  |  | 
| 366 | 11 |  |  |  |  | 76 | $self->SUPER::checkAttributeValues; | 
| 367 |  |  |  |  |  |  |  | 
| 368 | 11 |  |  |  |  | 113 | my $maxWidth = $self->get_maxWidth; | 
| 369 | 11 | 50 |  |  |  | 76 | X::Usage->throw("invalid maxWidth: $maxWidth") unless $maxWidth >= 0; | 
| 370 |  |  |  |  |  |  |  | 
| 371 | 11 |  |  |  |  | 119 | my $fields = $self->get_fields; | 
| 372 | 11 | 50 |  |  |  | 122 | if (ref($fields) ne 'ARRAY') | 
| 373 |  |  |  |  |  |  | { | 
| 374 | 0 |  |  |  |  | 0 | $fields = [$fields]; | 
| 375 | 0 |  |  |  |  | 0 | $self->set_fields($fields); | 
| 376 |  |  |  |  |  |  | } | 
| 377 |  |  |  |  |  |  |  | 
| 378 | 11 |  |  |  |  | 23 | my %seenFields; | 
| 379 | 11 |  |  |  |  | 31 | for (@$fields) | 
| 380 |  |  |  |  |  |  | { | 
| 381 | 11 | 50 | 33 |  |  | 201 | X::Usage->throw("not a field: $_") unless (blessed($_) && $_->isa("ProgressMonitor::Stringify::Fields::AbstractField")); | 
| 382 | 11 | 50 |  |  |  | 54 | X::Usage->throw("same instance of field used more than once: $_") if $seenFields{$_}; | 
| 383 | 11 |  |  |  |  | 68 | $seenFields{$_} = 1; | 
| 384 |  |  |  |  |  |  | } | 
| 385 |  |  |  |  |  |  |  | 
| 386 | 11 |  |  |  |  | 85 | my $ms = $self->get_messageStrategy; | 
| 387 | 11 | 50 |  |  |  | 130 | X::Usage->throw("invalid value for messageStrategy: $ms") | 
| 388 |  |  |  |  |  |  | unless $ms =~ /^(?:none|overlay|newline|overlay_newline|overlay_honor_newline)$/; | 
| 389 |  |  |  |  |  |  |  | 
| 390 | 11 | 100 |  |  |  | 60 | if ($ms =~ /^overlay/) | 
| 391 |  |  |  |  |  |  | { | 
| 392 | 2 |  |  |  |  | 4 | my $maxFieldNum = @$fields; | 
| 393 | 2 | 50 |  |  |  | 13 | $self->set_messageOverlayEndField($maxFieldNum) unless defined($self->get_messageOverlayEndField); | 
| 394 |  |  |  |  |  |  |  | 
| 395 | 2 |  |  |  |  | 29 | my $start = $self->get_messageOverlayStartField; | 
| 396 | 2 |  |  |  |  | 11 | my $end   = $self->get_messageOverlayEndField; | 
| 397 | 2 | 50 | 33 |  |  | 18 | X::Usage->throw("illegal overlay start field: $start") if ($start < 1 || $start > $maxFieldNum); | 
| 398 | 2 | 50 | 33 |  |  | 30 | X::Usage->throw("illegal overlay end field: $end") | 
|  |  |  | 33 |  |  |  |  | 
| 399 |  |  |  |  |  |  | if ($end < 1 || $end > $maxFieldNum || $end < $start); | 
| 400 |  |  |  |  |  |  | } | 
| 401 |  |  |  |  |  |  |  | 
| 402 | 11 |  |  |  |  | 74 | my $mf = $self->get_messageFiller; | 
| 403 | 11 | 50 |  |  |  | 80 | X::Usage->throw("messageFiller not a character: $mf") if length($mf) > 1; | 
| 404 |  |  |  |  |  |  |  | 
| 405 | 11 |  |  |  |  | 49 | return; | 
| 406 |  |  |  |  |  |  | } | 
| 407 |  |  |  |  |  |  |  | 
| 408 |  |  |  |  |  |  | ############################ | 
| 409 |  |  |  |  |  |  |  | 
| 410 |  |  |  |  |  |  | =head1 NAME | 
| 411 |  |  |  |  |  |  |  | 
| 412 |  |  |  |  |  |  | ProgressMonitor::Stringify::AbstractMonitor - A reusable/abstract monitor implementation | 
| 413 |  |  |  |  |  |  | that deals in stringified feedback. | 
| 414 |  |  |  |  |  |  |  | 
| 415 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 416 |  |  |  |  |  |  |  | 
| 417 |  |  |  |  |  |  | This is an abstract base class for monitors that will render their result as a string | 
| 418 |  |  |  |  |  |  | through the use of 'fields' (see the L packages). | 
| 419 |  |  |  |  |  |  |  | 
| 420 |  |  |  |  |  |  | =head1 PROTECTED METHODS | 
| 421 |  |  |  |  |  |  |  | 
| 422 |  |  |  |  |  |  | =over 2 | 
| 423 |  |  |  |  |  |  |  | 
| 424 |  |  |  |  |  |  | =item _new( $hashRef, $package ) | 
| 425 |  |  |  |  |  |  |  | 
| 426 |  |  |  |  |  |  | Configuration data: | 
| 427 |  |  |  |  |  |  |  | 
| 428 |  |  |  |  |  |  | =over 2 | 
| 429 |  |  |  |  |  |  |  | 
| 430 |  |  |  |  |  |  | =item maxWidth (default => 79) | 
| 431 |  |  |  |  |  |  |  | 
| 432 |  |  |  |  |  |  | The monitor should have this maxWidth. The actual width used may be less. This | 
| 433 |  |  |  |  |  |  | depends on the fields it uses; specifically, if dynamic fields are used, they | 
| 434 |  |  |  |  |  |  | will be given width until all is used or until the dynamic fields themselves | 
| 435 |  |  |  |  |  |  | have reached their maxWidth if any. | 
| 436 |  |  |  |  |  |  |  | 
| 437 |  |  |  |  |  |  | If the maxWidth is too small to handle the minimum requirements for all fields | 
| 438 |  |  |  |  |  |  | the C setting controls whether the rendition causes linewrapping | 
| 439 |  |  |  |  |  |  | or if it's just cut. | 
| 440 |  |  |  |  |  |  |  | 
| 441 |  |  |  |  |  |  | =item allowOverflow (default => 0) | 
| 442 |  |  |  |  |  |  |  | 
| 443 |  |  |  |  |  |  | If set to true and maxWidth is exceeded, linewrapping will occur for a possibly ugly display. | 
| 444 |  |  |  |  |  |  | If set to false, the rendition will be cut to avoid linewrapping, for a possible loss of important | 
| 445 |  |  |  |  |  |  | information. | 
| 446 |  |  |  |  |  |  |  | 
| 447 |  |  |  |  |  |  | =item fields (default => []) | 
| 448 |  |  |  |  |  |  |  | 
| 449 |  |  |  |  |  |  | An array ref with field instances. | 
| 450 |  |  |  |  |  |  |  | 
| 451 |  |  |  |  |  |  | =item messageStrategy (default => newline) | 
| 452 |  |  |  |  |  |  |  | 
| 453 |  |  |  |  |  |  | An identifiers that describes how messages should be inserted into the | 
| 454 |  |  |  |  |  |  | rendition: | 
| 455 |  |  |  |  |  |  |  | 
| 456 |  |  |  |  |  |  | =over 2 | 
| 457 |  |  |  |  |  |  |  | 
| 458 |  |  |  |  |  |  | =item none | 
| 459 |  |  |  |  |  |  |  | 
| 460 |  |  |  |  |  |  | Not surprisingly, this suppresses message presentation. | 
| 461 |  |  |  |  |  |  |  | 
| 462 |  |  |  |  |  |  | =item overlay | 
| 463 |  |  |  |  |  |  |  | 
| 464 |  |  |  |  |  |  | This will cause the message to overlay one or more of the other | 
| 465 |  |  |  |  |  |  | fields, so as to keep things on one line. This setting will work | 
| 466 |  |  |  |  |  |  | in conjunction with messageTimeout, messageOverlayStartField and | 
| 467 |  |  |  |  |  |  | messageOverlayEndField. | 
| 468 |  |  |  |  |  |  |  | 
| 469 |  |  |  |  |  |  | =item newline | 
| 470 |  |  |  |  |  |  |  | 
| 471 |  |  |  |  |  |  | This will cause the message and a newline to be inserted in front | 
| 472 |  |  |  |  |  |  | of the regular rendition, causing the running rendition to be | 
| 473 |  |  |  |  |  |  | 'pushed' forward. | 
| 474 |  |  |  |  |  |  |  | 
| 475 |  |  |  |  |  |  | =item overlay_newline | 
| 476 |  |  |  |  |  |  |  | 
| 477 |  |  |  |  |  |  | This will combine the effects of 'overlay' and 'newline'. | 
| 478 |  |  |  |  |  |  |  | 
| 479 |  |  |  |  |  |  | =back | 
| 480 |  |  |  |  |  |  |  | 
| 481 |  |  |  |  |  |  | =item messageFiller (default => ' ') | 
| 482 |  |  |  |  |  |  |  | 
| 483 |  |  |  |  |  |  | If the message is too short for the allotted space, it will be filled with | 
| 484 |  |  |  |  |  |  | this character. Can be set to the empty string or undef to skip filling, | 
| 485 |  |  |  |  |  |  | causing a 'partial overlay', i.e. just as much as the string is, which | 
| 486 |  |  |  |  |  |  | obviously can give a confusing mixed message with the underlying field. | 
| 487 |  |  |  |  |  |  |  | 
| 488 |  |  |  |  |  |  | =item messageTimeout (default => 3 seconds) | 
| 489 |  |  |  |  |  |  |  | 
| 490 |  |  |  |  |  |  | This is only relevant for the 'overlay' strategy. If the code doesn't | 
| 491 |  |  |  |  |  |  | explicitly set the message to undef/blank, the timeout will automatically | 
| 492 |  |  |  |  |  |  | remove it. Set to -1 for infinite. | 
| 493 |  |  |  |  |  |  |  | 
| 494 |  |  |  |  |  |  | =item messageOverlayStartField, messageOverlayEndField (defaults => all fields) | 
| 495 |  |  |  |  |  |  |  | 
| 496 |  |  |  |  |  |  | Together these define the starting and ending field number that the message | 
| 497 |  |  |  |  |  |  | should overlay. This defaults to 'all fields'. | 
| 498 |  |  |  |  |  |  |  | 
| 499 |  |  |  |  |  |  | =item messageOverlayNewlineConversion (default => ' ') | 
| 500 |  |  |  |  |  |  |  | 
| 501 |  |  |  |  |  |  | Embedded/trailing newlines will be converted to this string for the 'overlay' | 
| 502 |  |  |  |  |  |  | and 'overlay_newline' strategies. | 
| 503 |  |  |  |  |  |  |  | 
| 504 |  |  |  |  |  |  | =back | 
| 505 |  |  |  |  |  |  |  | 
| 506 |  |  |  |  |  |  | =item _toString | 
| 507 |  |  |  |  |  |  |  | 
| 508 |  |  |  |  |  |  | Contains the logic to assemble the fields into a current string. | 
| 509 |  |  |  |  |  |  |  | 
| 510 |  |  |  |  |  |  | =back | 
| 511 |  |  |  |  |  |  |  | 
| 512 |  |  |  |  |  |  | =head1 AUTHOR | 
| 513 |  |  |  |  |  |  |  | 
| 514 |  |  |  |  |  |  | Kenneth Olwing, C<<  >> | 
| 515 |  |  |  |  |  |  |  | 
| 516 |  |  |  |  |  |  | =head1 BUGS | 
| 517 |  |  |  |  |  |  |  | 
| 518 |  |  |  |  |  |  | I wouldn't be surprised! If you can come up with a minimal test that shows the | 
| 519 |  |  |  |  |  |  | problem I might be able to take a look. Even better, send me a patch. | 
| 520 |  |  |  |  |  |  |  | 
| 521 |  |  |  |  |  |  | Please report any bugs or feature requests to | 
| 522 |  |  |  |  |  |  | C, or through the web interface at | 
| 523 |  |  |  |  |  |  | L. | 
| 524 |  |  |  |  |  |  | I will be notified, and then you'll automatically be notified of progress on | 
| 525 |  |  |  |  |  |  | your bug as I make changes. | 
| 526 |  |  |  |  |  |  |  | 
| 527 |  |  |  |  |  |  | =head1 SUPPORT | 
| 528 |  |  |  |  |  |  |  | 
| 529 |  |  |  |  |  |  | You can find general documentation for this module with the perldoc command: | 
| 530 |  |  |  |  |  |  |  | 
| 531 |  |  |  |  |  |  | perldoc ProgressMonitor | 
| 532 |  |  |  |  |  |  |  | 
| 533 |  |  |  |  |  |  | =head1 ACKNOWLEDGEMENTS | 
| 534 |  |  |  |  |  |  |  | 
| 535 |  |  |  |  |  |  | Thanks to my family. I'm deeply grateful for you! | 
| 536 |  |  |  |  |  |  |  | 
| 537 |  |  |  |  |  |  | =head1 COPYRIGHT & LICENSE | 
| 538 |  |  |  |  |  |  |  | 
| 539 |  |  |  |  |  |  | Copyright 2006,2007 Kenneth Olwing, all rights reserved. | 
| 540 |  |  |  |  |  |  |  | 
| 541 |  |  |  |  |  |  | This program is free software; you can redistribute it and/or modify it | 
| 542 |  |  |  |  |  |  | under the same terms as Perl itself. | 
| 543 |  |  |  |  |  |  |  | 
| 544 |  |  |  |  |  |  | =cut | 
| 545 |  |  |  |  |  |  |  | 
| 546 |  |  |  |  |  |  | 1;    # End of ProgressMonitor::Stringify::AbstractMonitor |