File Coverage

blib/lib/Circle/WindowItem.pm
Criterion Covered Total %
statement 30 126 23.8
branch 0 34 0.0
condition 0 11 0.0
subroutine 10 25 40.0
pod 0 15 0.0
total 40 211 18.9


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