1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
1 |
package Padre::Wx::Outline; |
2 |
||
3 |
use 5.008; |
|
4 |
use strict; |
|
5 |
use warnings; |
|
1.1.8
by Damyan Ivanov
Import upstream version 0.59.ds1 |
6 |
use Params::Util (); |
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
7 |
use Padre::Wx (); |
8 |
use Padre::Current (); |
|
1.1.8
by Damyan Ivanov
Import upstream version 0.59.ds1 |
9 |
use Padre::Logger; |
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
10 |
|
1.2.3
by Damyan Ivanov
Import upstream version 0.63.ds1 |
11 |
our $VERSION = '0.63'; |
1.1.4
by Damyan Ivanov
Import upstream version 0.36 |
12 |
our @ISA = 'Wx::TreeCtrl'; |
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
13 |
|
1.1.8
by Damyan Ivanov
Import upstream version 0.59.ds1 |
14 |
use Class::XSAccessor { |
15 |
accessors => { |
|
16 |
force_next => 'force_next', |
|
17 |
}
|
|
1.1.3
by Damyan Ivanov
Import upstream version 0.35 |
18 |
};
|
19 |
||
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
20 |
sub new { |
21 |
my $class = shift; |
|
22 |
my $main = shift; |
|
23 |
my $self = $class->SUPER::new( |
|
24 |
$main->right, |
|
25 |
-1, |
|
26 |
Wx::wxDefaultPosition, |
|
27 |
Wx::wxDefaultSize, |
|
1.1.2
by Damyan Ivanov
Import upstream version 0.34 |
28 |
Wx::wxTR_HIDE_ROOT | Wx::wxTR_SINGLE | Wx::wxTR_HAS_BUTTONS | Wx::wxTR_LINES_AT_ROOT |
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
29 |
);
|
30 |
$self->SetIndent(10); |
|
31 |
$self->{force_next} = 0; |
|
32 |
||
1.1.2
by Damyan Ivanov
Import upstream version 0.34 |
33 |
Wx::Event::EVT_COMMAND_SET_FOCUS( |
34 |
$self, $self, |
|
35 |
sub { |
|
36 |
$self->on_tree_item_set_focus( $_[1] ); |
|
37 |
},
|
|
38 |
);
|
|
39 |
||
1.1.5
by Damyan Ivanov
Import upstream version 0.42 |
40 |
# Double-click a function name
|
41 |
Wx::Event::EVT_TREE_ITEM_ACTIVATED( |
|
1.1.2
by Damyan Ivanov
Import upstream version 0.34 |
42 |
$self, $self, |
43 |
sub { |
|
1.1.5
by Damyan Ivanov
Import upstream version 0.42 |
44 |
$self->on_tree_item_activated( $_[1] ); |
45 |
}
|
|
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
46 |
);
|
47 |
||
48 |
$self->Hide; |
|
49 |
||
1.2.2
by Damyan Ivanov
Import upstream version 0.61.ds1 |
50 |
$self->{cache} = {}; |
51 |
||
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
52 |
return $self; |
53 |
}
|
|
54 |
||
55 |
sub right { |
|
56 |
$_[0]->GetParent; |
|
57 |
}
|
|
58 |
||
59 |
sub main { |
|
60 |
$_[0]->GetGrandParent; |
|
61 |
}
|
|
62 |
||
63 |
sub gettext_label { |
|
64 |
Wx::gettext('Outline'); |
|
65 |
}
|
|
66 |
||
67 |
sub clear { |
|
1.2.2
by Damyan Ivanov
Import upstream version 0.61.ds1 |
68 |
my ($self) = @_; |
69 |
$self->DeleteAllItems; |
|
70 |
return; |
|
71 |
}
|
|
72 |
||
73 |
################################################################
|
|
74 |
# Cache routines
|
|
75 |
||
76 |
sub store_in_cache { |
|
77 |
my ( $self, $cache_key, $content ) = @_; |
|
78 |
||
79 |
if ( defined $cache_key ) { |
|
80 |
$self->{cache}->{$cache_key} = $content; |
|
81 |
}
|
|
82 |
return; |
|
83 |
}
|
|
84 |
||
85 |
sub get_from_cache { |
|
86 |
my ( $self, $cache_key ) = @_; |
|
87 |
||
88 |
if ( defined $cache_key and exists $self->{cache}->{$cache_key} ) { |
|
89 |
return $self->{cache}->{$cache_key}; |
|
90 |
}
|
|
91 |
return; |
|
92 |
}
|
|
93 |
||
94 |
#####################################################################
|
|
95 |
# GUI routines
|
|
96 |
||
97 |
sub update_data { |
|
98 |
my ( $self, $outline_data, $filename, $right_click_handler ) = @_; |
|
99 |
||
100 |
$self->Freeze; |
|
101 |
||
102 |
# Clear out the existing stuff
|
|
103 |
# TO DO extract data for keeping (sub)trees collapsed/expanded (see below)
|
|
104 |
#if ( $self->GetCount > 0 ) {
|
|
105 |
# my $r = $self->GetRootItem;
|
|
106 |
# warn ref $r;
|
|
107 |
# use Data::Dumper;
|
|
108 |
# my ( $fc, $cookie ) = $self->GetFirstChild($r);
|
|
109 |
# warn ref $fc;
|
|
110 |
# warn $self->GetItemText($fc) . ': ' . Dumper( $self->GetPlData($fc) );
|
|
111 |
#}
|
|
112 |
$self->clear; |
|
113 |
||
114 |
require Padre::Wx; |
|
115 |
||
116 |
# If there is no structure, clear the outline pane and return.
|
|
117 |
unless ($outline_data) { |
|
118 |
return; |
|
119 |
}
|
|
120 |
||
121 |
# Again, slightly differently
|
|
122 |
unless (@$outline_data) { |
|
123 |
return 1; |
|
124 |
}
|
|
125 |
||
126 |
# Add the hidden unused root
|
|
127 |
my $root = $self->AddRoot( |
|
128 |
Wx::gettext('Outline'), |
|
129 |
-1, |
|
130 |
-1, |
|
131 |
Wx::TreeItemData->new('') |
|
132 |
);
|
|
133 |
||
134 |
# Update the outline pane
|
|
135 |
_update_treectrl( $self, $outline_data, $root ); |
|
136 |
||
137 |
# Set MIME type specific event handler
|
|
138 |
if ( defined $right_click_handler ) { |
|
139 |
Wx::Event::EVT_TREE_ITEM_RIGHT_CLICK( |
|
140 |
$self, |
|
141 |
$self, |
|
142 |
$right_click_handler, |
|
143 |
);
|
|
144 |
}
|
|
145 |
||
146 |
# TO DO Expanding all is not acceptable: We need to keep the state
|
|
147 |
# (i.e., keep the pragmata subtree collapsed if it was collapsed
|
|
148 |
# by the user)
|
|
149 |
#$self->ExpandAll;
|
|
150 |
$self->GetBestSize; |
|
151 |
$self->Thaw; |
|
152 |
||
153 |
$self->store_in_cache( $filename, [ $outline_data, $right_click_handler ] ); |
|
154 |
||
155 |
return 1; |
|
156 |
}
|
|
157 |
||
158 |
sub _update_treectrl { |
|
159 |
my ( $outlinebar, $outline, $root ) = @_; |
|
160 |
||
161 |
foreach my $pkg ( @{$outline} ) { |
|
162 |
my $branch = $outlinebar->AppendItem( |
|
163 |
$root, |
|
164 |
$pkg->{name}, |
|
165 |
-1, -1, |
|
166 |
Wx::TreeItemData->new( |
|
167 |
{ line => $pkg->{line}, |
|
168 |
name => $pkg->{name}, |
|
169 |
type => 'package', |
|
170 |
}
|
|
171 |
)
|
|
172 |
);
|
|
173 |
foreach my $type (qw(pragmata modules attributes methods events)) { |
|
174 |
_add_subtree( $outlinebar, $pkg, $type, $branch ); |
|
175 |
}
|
|
176 |
$outlinebar->Expand($branch); |
|
177 |
}
|
|
178 |
||
179 |
return; |
|
180 |
}
|
|
181 |
||
182 |
sub _add_subtree { |
|
183 |
my ( $self, $pkg, $type, $root ) = @_; |
|
184 |
||
185 |
my %type_caption = ( |
|
186 |
pragmata => Wx::gettext('Pragmata'), |
|
187 |
modules => Wx::gettext('Modules'), |
|
188 |
methods => Wx::gettext('Methods'), |
|
189 |
);
|
|
190 |
||
191 |
my $type_elem = undef; |
|
192 |
if ( defined( $pkg->{$type} ) && scalar( @{ $pkg->{$type} } ) > 0 ) { |
|
193 |
my $type_caption = ucfirst($type); |
|
194 |
if ( exists $type_caption{$type} ) { |
|
195 |
$type_caption = $type_caption{$type}; |
|
196 |
} else { |
|
197 |
warn "Type not translated: $type_caption\n"; |
|
198 |
}
|
|
199 |
||
200 |
$type_elem = $self->AppendItem( |
|
201 |
$root, |
|
202 |
$type_caption, |
|
203 |
-1, |
|
204 |
-1, |
|
205 |
Wx::TreeItemData->new() |
|
206 |
);
|
|
207 |
||
208 |
my @sorted_entries = (); |
|
209 |
if ( $type eq 'methods' ) { |
|
210 |
my $config = $self->main->{ide}->config; |
|
211 |
if ( $config->main_functions_order eq 'original' ) { |
|
212 |
||
213 |
# That should be the one we got
|
|
214 |
@sorted_entries = @{ $pkg->{$type} }; |
|
215 |
} elsif ( $config->main_functions_order eq 'alphabetical_private_last' ) { |
|
216 |
||
217 |
# ~ comes after \w
|
|
218 |
my @pre = map { $_->{name} =~ s/^_/~/; $_ } @{ $pkg->{$type} }; |
|
219 |
@pre = sort { $a->{name} cmp $b->{name} } @pre; |
|
220 |
@sorted_entries = map { $_->{name} =~ s/^~/_/; $_ } @pre; |
|
221 |
} else { |
|
222 |
||
223 |
# Alphabetical (aka 'abc')
|
|
224 |
@sorted_entries = sort { $a->{name} cmp $b->{name} } @{ $pkg->{$type} }; |
|
225 |
}
|
|
226 |
} else { |
|
227 |
@sorted_entries = sort { $a->{name} cmp $b->{name} } @{ $pkg->{$type} }; |
|
228 |
}
|
|
229 |
||
230 |
foreach my $item (@sorted_entries) { |
|
231 |
$self->AppendItem( |
|
232 |
$type_elem, |
|
233 |
$item->{name}, |
|
234 |
-1, -1, |
|
235 |
Wx::TreeItemData->new( |
|
236 |
{ line => $item->{line}, |
|
237 |
name => $item->{name}, |
|
238 |
type => $type, |
|
239 |
}
|
|
240 |
)
|
|
241 |
);
|
|
242 |
}
|
|
243 |
}
|
|
244 |
if ( defined $type_elem ) { |
|
245 |
if ( $type eq 'methods' ) { |
|
246 |
$self->Expand($type_elem); |
|
247 |
} else { |
|
248 |
$self->Collapse($type_elem); |
|
249 |
}
|
|
250 |
}
|
|
251 |
||
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
252 |
return; |
253 |
}
|
|
254 |
||
255 |
#####################################################################
|
|
256 |
# Timer Control
|
|
257 |
||
258 |
sub start { |
|
1.1.5
by Damyan Ivanov
Import upstream version 0.42 |
259 |
my $self = shift; @_ = (); # Feeble attempt to kill Scalars Leaked ($self is leaking) |
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
260 |
|
1.1.8
by Damyan Ivanov
Import upstream version 0.59.ds1 |
261 |
# TO DO: GUI on-start initialisation here
|
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
262 |
|
263 |
# Set up or reinitialise the timer
|
|
1.1.8
by Damyan Ivanov
Import upstream version 0.59.ds1 |
264 |
if ( Params::Util::_INSTANCE( $self->{timer}, 'Wx::Timer' ) ) { |
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
265 |
$self->{timer}->Stop if $self->{timer}->IsRunning; |
266 |
} else { |
|
267 |
$self->{timer} = Wx::Timer->new( |
|
268 |
$self, |
|
269 |
Padre::Wx::ID_TIMER_OUTLINE |
|
270 |
);
|
|
1.1.1
by Damyan Ivanov
Import upstream version 0.33 |
271 |
Wx::Event::EVT_TIMER( |
272 |
$self, |
|
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
273 |
Padre::Wx::ID_TIMER_OUTLINE, |
274 |
sub { |
|
1.1.1
by Damyan Ivanov
Import upstream version 0.33 |
275 |
$self->on_timer( $_[1], $_[2] ); |
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
276 |
},
|
277 |
);
|
|
278 |
}
|
|
1.1.1
by Damyan Ivanov
Import upstream version 0.33 |
279 |
$self->{timer}->Start(1000); |
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
280 |
$self->on_timer( undef, 1 ); |
281 |
||
1.1.3
by Damyan Ivanov
Import upstream version 0.35 |
282 |
return (); |
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
283 |
}
|
284 |
||
285 |
sub stop { |
|
286 |
my $self = shift; |
|
287 |
||
1.1.8
by Damyan Ivanov
Import upstream version 0.59.ds1 |
288 |
TRACE("stopping Outline") if DEBUG; |
1.1.2
by Damyan Ivanov
Import upstream version 0.34 |
289 |
|
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
290 |
# Stop the timer
|
1.1.8
by Damyan Ivanov
Import upstream version 0.59.ds1 |
291 |
if ( Params::Util::_INSTANCE( $self->{timer}, 'Wx::Timer' ) ) { |
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
292 |
$self->{timer}->Stop if $self->{timer}->IsRunning; |
293 |
}
|
|
294 |
||
295 |
$self->clear; |
|
296 |
||
1.1.8
by Damyan Ivanov
Import upstream version 0.59.ds1 |
297 |
# TO DO: GUI on-stop cleanup here
|
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
298 |
|
1.1.3
by Damyan Ivanov
Import upstream version 0.35 |
299 |
return (); |
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
300 |
}
|
301 |
||
1.1.8
by Damyan Ivanov
Import upstream version 0.59.ds1 |
302 |
sub refresh { |
303 |
my $self = shift; |
|
1.2.2
by Damyan Ivanov
Import upstream version 0.61.ds1 |
304 |
|
1.1.8
by Damyan Ivanov
Import upstream version 0.59.ds1 |
305 |
$self->clear; |
1.2.2
by Damyan Ivanov
Import upstream version 0.61.ds1 |
306 |
|
307 |
my $filename = Padre::Current->filename; |
|
308 |
my $outline_data_ref = $self->get_from_cache($filename); |
|
309 |
if ( defined $outline_data_ref ) { |
|
310 |
my ( $outline_data, $right_click_handler ) = @$outline_data_ref; |
|
311 |
$self->update_data( $outline_data, $filename, $right_click_handler ); |
|
312 |
}
|
|
313 |
||
1.1.8
by Damyan Ivanov
Import upstream version 0.59.ds1 |
314 |
$self->force_next(1); |
315 |
}
|
|
316 |
||
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
317 |
sub running { |
1.1.1
by Damyan Ivanov
Import upstream version 0.33 |
318 |
!!( $_[0]->{timer} and $_[0]->{timer}->IsRunning ); |
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
319 |
}
|
320 |
||
321 |
#####################################################################
|
|
322 |
# Event Handlers
|
|
323 |
||
1.1.2
by Damyan Ivanov
Import upstream version 0.34 |
324 |
sub on_tree_item_set_focus { |
1.1.1
by Damyan Ivanov
Import upstream version 0.33 |
325 |
my ( $self, $event ) = @_; |
1.1.6
by Damyan Ivanov
Import upstream version 0.48.ds2 |
326 |
my $main = Padre::Current->main($self); |
327 |
my $page = $main->current->editor; |
|
328 |
my $selection = $self->GetSelection(); |
|
329 |
if ( $selection and $selection->IsOk ) { |
|
330 |
my $item = $self->GetPlData($selection); |
|
331 |
if ( defined $item ) { |
|
332 |
$self->select_line_in_editor( $item->{line} ); |
|
333 |
}
|
|
1.1.2
by Damyan Ivanov
Import upstream version 0.34 |
334 |
}
|
335 |
return; |
|
336 |
}
|
|
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
337 |
|
1.1.5
by Damyan Ivanov
Import upstream version 0.42 |
338 |
sub on_tree_item_activated { |
339 |
on_tree_item_set_focus(@_); |
|
1.1.2
by Damyan Ivanov
Import upstream version 0.34 |
340 |
return; |
341 |
}
|
|
342 |
||
343 |
sub select_line_in_editor { |
|
344 |
my ( $self, $line_number ) = @_; |
|
1.1.5
by Damyan Ivanov
Import upstream version 0.42 |
345 |
my $main = Padre::Current->main($self); |
346 |
my $page = $main->current->editor; |
|
1.1.2
by Damyan Ivanov
Import upstream version 0.34 |
347 |
if ( defined $line_number |
348 |
&& ( $line_number =~ /^\d+$/o ) |
|
349 |
&& ( defined $page ) |
|
350 |
&& ( $line_number <= $page->GetLineCount ) ) |
|
351 |
{
|
|
352 |
$line_number--; |
|
353 |
$page->EnsureVisible($line_number); |
|
354 |
$page->goto_pos_centerize( $page->GetLineIndentPosition($line_number) ); |
|
355 |
$page->SetFocus; |
|
356 |
}
|
|
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
357 |
return; |
358 |
}
|
|
359 |
||
360 |
sub on_timer { |
|
361 |
my ( $self, $event, $force ) = @_; |
|
362 |
||
1.1.5
by Damyan Ivanov
Import upstream version 0.42 |
363 |
### NOTE:
|
364 |
# floating windows, when undocked (err... "floating"), will
|
|
365 |
# return Wx::AuiFloatingFrame as their parent. So floating
|
|
366 |
# windows should always get their "main" from Padre::Current->main
|
|
367 |
# and -not- from $self->main.
|
|
368 |
my $main = Padre::Current->main($self); |
|
369 |
||
370 |
my $document = $main->current->document or return; |
|
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
371 |
|
372 |
unless ( $document->can('get_outline') ) { |
|
373 |
$self->clear; |
|
374 |
return; |
|
375 |
}
|
|
376 |
||
377 |
if ( $self->force_next ) { |
|
378 |
$force = 1; |
|
379 |
$self->force_next(0); |
|
380 |
}
|
|
381 |
||
1.1.1
by Damyan Ivanov
Import upstream version 0.33 |
382 |
$document->get_outline( force => $force ); |
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
383 |
|
384 |
if ( defined($event) ) { |
|
385 |
$event->Skip(0); |
|
386 |
}
|
|
387 |
||
388 |
return; |
|
389 |
}
|
|
390 |
||
391 |
1; |
|
392 |
||
1.1.8
by Damyan Ivanov
Import upstream version 0.59.ds1 |
393 |
# Copyright 2008-2010 The Padre development team as listed in Padre.pm.
|
1
by Damyan Ivanov
Import upstream version 0.27.ds1 |
394 |
# LICENSE
|
395 |
# This program is free software; you can redistribute it and/or
|
|
396 |
# modify it under the same terms as Perl 5 itself.
|