File Coverage

blib/lib/Circle/WindowItem.pm
Criterion Covered Total %
statement 66 126 52.3
branch 12 34 35.2
condition 3 11 27.2
subroutine 17 25 68.0
pod 0 15 0.0
total 98 211 46.4


line stmt bran cond sub pod time code
1             # You may distribute under the terms of the GNU General Public License
2             #
3             # (C) Paul Evans, 2008-2014 -- leonerd@leonerd.org.uk
4              
5             package Circle::WindowItem;
6              
7             # An abstract role used by objects that should be placed in FE windows or tabs
8             # Combines the behaviours of:
9             # having display events
10             # responding to typed lines of text
11              
12 4     4   28 use strict;
  4         8  
  4         104  
13 4     4   17 use warnings;
  4         5  
  4         110  
14 4     4   18 use base qw( Circle::Commandable Circle::Configurable Circle::Loggable );
  4         5  
  4         1548  
15              
16 4     4   25 use Carp;
  4         6  
  4         289  
17              
18             our $VERSION = '0.173320';
19              
20 4     4   1551 use Circle::TaggedString;
  4         11  
  4         98  
21              
22 4     4   1341 use Circle::Widget::Box;
  4         7  
  4         108  
23 4     4   1418 use Circle::Widget::Scroller;
  4         8  
  4         3122  
24              
25             sub init_prop_level
26             {
27 5     5 0 1265 return 0;
28             }
29              
30             sub bump_level
31             {
32 3     3 0 12 my $self = shift;
33 3         13 my ( $newlevel ) = @_;
34              
35 3 100       30 return if $self->get_prop_level >= $newlevel;
36              
37 2         67 $self->set_prop_level( $newlevel );
38             }
39              
40             sub method_reset_level
41             {
42 0     0 0 0 my $self = shift;
43              
44 0         0 $self->set_prop_level( 0 );
45             }
46              
47             sub push_displayevent
48             {
49 8     8 0 20 my $self = shift;
50 8         39 my ( $event, $args, %opts ) = @_;
51              
52 8         29 foreach ( values %$args ) {
53 8 100       26 if( !ref $_ ) {
    50          
54 5         11 next;
55             }
56 3         30 elsif( eval { $_->isa( "Circle::TaggedString" ) } ) {
57 3         28 $_ = $_->squash;
58             }
59             else {
60 0         0 $_ = "[[TODO: Not sure how to handle $_]]";
61             }
62             }
63              
64 8   33     49 my $time = $opts{time} // time();
65              
66 8         38 my $scroller = $self->get_widget_scroller;
67 8         39 $scroller->push_event( $event, $time, $args );
68              
69 8         3188 $self->push_log( $event, $time, $args );
70             }
71              
72             sub respond
73             {
74 5     5 0 11 my $self = shift;
75 5         24 my ( $text, %opts ) = @_;
76              
77 5         67 $self->push_displayevent( "response", { text => $text } );
78 5 100       40 $self->bump_level( $opts{level} ) if $opts{level};
79              
80 5         1186 return;
81             }
82              
83             sub respondwarn
84             {
85 0     0 0 0 my $self = shift;
86 0         0 my ( $text, %opts ) = @_;
87              
88 0         0 $self->push_displayevent( "warning", { text => $text } );
89 0 0       0 $self->bump_level( $opts{level} ) if $opts{level};
90              
91 0         0 return;
92             }
93              
94             sub responderr
95             {
96 0     0 0 0 my $self = shift;
97 0         0 my ( $text, %opts ) = @_;
98              
99 0         0 $self->push_displayevent( "error", { text => $text } );
100 0 0       0 $self->bump_level( $opts{level} ) if $opts{level};
101              
102 0         0 return;
103             }
104              
105             sub respond_table
106             {
107 0     0 0 0 my $self = shift;
108 0         0 my ( $tableref, %opts ) = @_;
109              
110             # We need to avoid using join() or sprintf() here, because any of the table
111             # cell arguments might be TaggedString objects. The CORE functions won't
112             # respect this taggnig.
113              
114 0 0       0 my $colsep = exists $opts{colsep} ? delete $opts{colsep} : " ";
115              
116 0         0 my $headings = delete $opts{headings};
117              
118 0         0 my @table = @$tableref;
119              
120 0         0 my @width;
121              
122 0         0 foreach my $r ( $headings, @table ) {
123 0 0       0 next unless defined $r;
124              
125 0         0 foreach my $c ( 0 .. $#$r ) {
126 0         0 my $d = $r->[$c];
127 0 0 0     0 $width[$c] = length $d if !defined $width[$c] or length $d > $width[$c];
128             }
129             }
130              
131 0 0       0 if( $headings ) {
132 0         0 my $text = Circle::TaggedString->new();
133 0         0 foreach my $c ( 0 .. $#$headings ) {
134 0 0       0 $text->append( $colsep ) if $c > 0;
135              
136 0         0 my $col = $headings->[$c];
137 0         0 $text->append_tagged( $col . ( " " x ( $width[$c] - length $col ) ),
138             u => 1 );
139             }
140 0         0 $self->respond( $text, %opts );
141             }
142              
143 0         0 foreach my $tr ( @table ) {
144 0         0 my $text = Circle::TaggedString->new();
145 0         0 foreach my $c ( 0 .. $#width ) {
146 0 0       0 $text->append( $colsep ) if $c > 0;
147              
148 0         0 my $col = $tr->[$c];
149 0         0 $text->append( $col . ( " " x ( $width[$c] - length $col ) ) );
150             }
151 0         0 $self->respond( $text, %opts );
152             }
153             }
154              
155             sub command_clear
156             : Command_description("Clear the scrollback buffer")
157             : Command_opt('keeplines=$', desc => "keep this number of lines")
158             {
159 0     0 0 0 my $self = shift;
160 0         0 my ( $opts, $cinv ) = @_;
161              
162 0   0     0 my $keeplines = $opts->{keeplines} || 0;
163              
164 0         0 my $scroller = $self->get_widget_scroller;
165              
166 0         0 my $to_delete = scalar @{ $scroller->get_prop_displayevents } - $keeplines;
  0         0  
167              
168 0 0       0 $scroller->shift_prop_displayevents( $to_delete ) if $to_delete > 0;
169              
170 0         0 return;
171 4     4   31 }
  4         6  
  4         27  
172              
173             sub command_dumpevents
174             : Command_description("Dump a log of the raw event buffer")
175             : Command_arg('filename')
176             {
177 0     0 0 0 my $self = shift;
178 0         0 my ( $filename, $cinv ) = @_;
179              
180 0         0 my $scroller = $self->get_widget_scroller;
181 0         0 YAML::DumpFile( $filename, $scroller->get_prop_displayevents );
182              
183 0         0 $cinv->respond( "Dumped event log to $filename" );
184 0         0 return;
185 4     4   778 }
  4         7  
  4         13  
186              
187             ###
188             # Widget
189             ###
190              
191             sub method_get_widget
192             {
193 3     3 0 56642 my $self = shift;
194              
195 3   66     28 return $self->{widget} ||= $self->make_widget();
196             }
197              
198             # Useful for debugging and live-development
199             sub command_rewidget
200             : Command_description("Destroy the cached widget tree so it will be recreated")
201             {
202 0     0 0 0 my $self = shift;
203              
204 0         0 delete $self->{widget};
205 0         0 $self->respond( "Destroyed existing widget tree. You will have to restart the frontend now" );
206              
207 0         0 return;
208 4     4   696 }
  4         7  
  4         14  
209              
210             # Subclasses might override this, but we'll provide a default
211             sub make_widget
212             {
213 2     2 0 4 my $self = shift;
214              
215 2         4 my $registry = $self->{registry};
216              
217 2         10 my $box = $registry->construct(
218             "Circle::Widget::Box",
219             orientation => "vertical",
220             );
221              
222 2 50       156 $self->make_widget_pre_scroller( $box ) if $self->can( "make_widget_pre_scroller" );
223              
224 2         28 $box->add( $self->get_widget_scroller, expand => 1 );
225              
226 2 100       50 $box->add( $self->get_widget_statusbar ) if $self->can( "get_widget_statusbar" );
227              
228 2         27 $box->add( $self->get_widget_commandentry );
229              
230 2         35 return $box;
231             }
232              
233             sub get_widget_scroller
234             {
235 11     11 0 4662 my $self = shift;
236              
237 11 100       57 return $self->{widget_displayevents} if defined $self->{widget_displayevents};
238              
239 4         9 my $registry = $self->{registry};
240              
241 4         14 my $widget = $registry->construct(
242             "Circle::Widget::Scroller",
243             scrollback => 1000, # TODO
244             );
245              
246 4         133 return $self->{widget_displayevents} = $widget;
247             }
248              
249             sub enumerable_path
250             {
251 0     0 0   my $self = shift;
252              
253 0 0         if( my $parent = $self->parent ) {
254 0           return $parent->enumerable_path . "/" . $self->enumerable_name;
255             }
256             else {
257 0           return $self->enumerable_name;
258             }
259             }
260              
261             0x55AA;