1
package Padre::Wx::VCS;
6
use Padre::Role::Task ();
7
use Padre::Wx::Role::View ();
9
use Padre::Wx::FBP::VCS ();
10
use Padre::Task::VCS ();
13
our $VERSION = '0.92';
21
RED => Wx::Colour->new('red'),
22
DARK_GREEN => Wx::Colour->new( 0x00, 0x90, 0x00 ),
23
BLUE => Wx::Colour->new('blue'),
24
GRAY => Wx::Colour->new('gray'),
25
BLACK => Wx::Colour->new('black'),
32
my $panel = shift || $main->right;
33
my $self = $class->SUPER::new($panel);
35
# Set the bitmap button icons
36
$self->{add}->SetBitmapLabel( Padre::Wx::Icon::find('actions/list-add') );
37
$self->{delete}->SetBitmapLabel( Padre::Wx::Icon::find('actions/list-remove') );
38
$self->{update}->SetBitmapLabel( Padre::Wx::Icon::find('actions/stock_update-data') );
39
$self->{commit}->SetBitmapLabel( Padre::Wx::Icon::find('actions/document-save') );
40
$self->{revert}->SetBitmapLabel( Padre::Wx::Icon::find('actions/edit-undo') );
41
$self->{refresh}->SetBitmapLabel( Padre::Wx::Icon::find('actions/view-refresh') );
43
# Set up column sorting
44
$self->{sort_column} = 0;
45
$self->{sort_desc} = 1;
48
my @column_headers = (
49
Wx::gettext('Status'),
51
Wx::gettext('Author'),
52
Wx::gettext('Revision'),
55
for my $column_header (@column_headers) {
56
$self->{list}->InsertColumn( $index++, $column_header );
59
# Column ascending/descending image
60
my $images = Wx::ImageList->new( 16, 16 );
63
Wx::ArtProvider::GetBitmap(
70
Wx::ArtProvider::GetBitmap(
77
$self->{list}->AssignImageList( $images, Wx::IMAGE_LIST_SMALL );
80
Padre::Util::tidy_list( $self->{list} );
82
# Update the checkboxes with their corresponding values in the
84
my $config = $main->config;
85
$self->{show_normal}->SetValue( $config->vcs_normal_shown );
86
$self->{show_unversioned}->SetValue( $config->vcs_unversioned_shown );
87
$self->{show_ignored}->SetValue( $config->vcs_ignored_shown );
89
# Hide vcs command buttons at startup
90
$self->{commit}->Hide;
92
$self->{delete}->Hide;
93
$self->{revert}->Hide;
94
$self->{update}->Hide;
103
######################################################################
104
# Padre::Wx::Role::View Methods
111
shift->gettext_label(@_);
115
$_[0]->main->show_vcs(0);
124
# Clear out any state and tasks
131
#####################################################################
134
sub on_refresh_click {
135
$_[0]->main->vcs->refresh( $_[0]->current );
138
#####################################################################
142
Wx::gettext('Version Control');
145
# Clear everything...
149
$self->{list}->DeleteAllItems;
150
$self->_show_command_bar(0);
155
# Nothing to implement here
162
my $current = shift or return;
163
my $command = shift || Padre::Task::VCS::VCS_STATUS;
165
my $document = $current->document;
167
# Abort any in-flight checks
173
# Do not display anything where there is no open documents
174
return unless $document;
176
# Shortcut if there is nothing in the document to do
177
if ( $document->is_unused ) {
178
$self->{status}->SetValue( Wx::gettext('Current file is not saved in a version control system') );
182
# Retrieve project version control system
183
my $vcs = $document->project->vcs;
185
# No version control system?
187
$self->{status}->SetValue( Wx::gettext('Current file is not in a version control system') );
191
# Not supported VCS check
192
if ( $vcs ne Padre::Constant::SUBVERSION and $vcs ne Padre::Constant::GIT ) {
193
$self->{status}->SetValue( sprintf( Wx::gettext('%s version control is not currently available'), $vcs ) );
198
# Start a background VCS status task
200
task => 'Padre::Task::VCS',
202
document => $document,
211
$self->{model} = Params::Util::_ARRAY0( $task->{model} ) or return;
212
$self->{vcs} = $task->{vcs} or return;
220
# Clear if needed. Please note that this is needed
224
return unless $self->{model};
226
# Subversion status codes
228
' ' => { name => Wx::gettext('Normal') },
229
'A' => { name => Wx::gettext('Added') },
230
'D' => { name => Wx::gettext('Deleted') },
231
'M' => { name => Wx::gettext('Modified') },
232
'C' => { name => Wx::gettext('Conflicted') },
233
'I' => { name => Wx::gettext('Ignored') },
234
'?' => { name => Wx::gettext('Unversioned') },
235
'!' => { name => Wx::gettext('Missing') },
236
'~' => { name => Wx::gettext('Obstructed') }
241
' ' => { name => Wx::gettext('Unmodified') },
242
'M' => { name => Wx::gettext('Modified') },
243
'A' => { name => Wx::gettext('Added') },
244
'D' => { name => Wx::gettext('Deleted') },
245
'R' => { name => Wx::gettext('Renamed') },
246
'C' => { name => Wx::gettext('Copied') },
247
'U' => { name => Wx::gettext('Updated but unmerged') },
248
'?' => { name => Wx::gettext('Unversioned') },
251
my %vcs_status = $self->{vcs} eq Padre::Constant::SUBVERSION ? %SVN_STATUS : %GIT_STATUS;
253
# Add a zero count key for VCS status hash
254
$vcs_status{$_}->{count} = 0 for keys %vcs_status;
256
# Retrieve the state of the checkboxes
257
my $show_normal = $self->{show_normal}->IsChecked ? 1 : 0;
258
my $show_unversioned = $self->{show_unversioned}->IsChecked ? 1 : 0;
259
my $show_ignored = $self->{show_ignored}->IsChecked ? 1 : 0;
262
my $list = $self->{list};
264
$self->_sort_model(%vcs_status);
265
my $model = $self->{model};
268
for my $rec (@$model) {
269
my $status = $rec->{status};
270
my $path_status = $vcs_status{$status};
271
if ( defined $path_status ) {
273
if ( $show_normal or $status ne ' ' ) {
275
if ( $show_unversioned or $status ne '?' ) {
276
if ( $show_ignored or $status ne 'I' ) {
278
# Add a version control path to the list
279
$list->InsertImageStringItem( $index, $path_status->{name}, -1 );
280
$list->SetItemData( $index, $model_index );
281
$list->SetItem( $index, 1, $rec->{path} );
283
if ( $status eq ' ' ) {
285
} elsif ( $status eq 'A' or $status eq 'D' ) {
287
} elsif ( $status eq 'M' ) {
289
} elsif ( $status eq 'I' ) {
294
$list->SetItemTextColour( $index, $color );
296
$list->SetItem( $index, 2, $rec->{author} );
297
$list->SetItem( $index++, 3, $rec->{revision} );
303
$path_status->{count}++;
307
# Select the first item
308
if ( $list->GetItemCount > 0 ) {
309
$list->SetItemState( 0, Wx::LIST_STATE_SELECTED, Wx::LIST_STATE_SELECTED );
312
# Show Subversion statistics
314
for my $status ( sort keys %vcs_status ) {
315
my $vcs_status_obj = $vcs_status{$status};
316
next if $vcs_status_obj->{count} == 0;
317
if ( length($message) > 0 ) {
318
$message .= Wx::gettext(', ');
320
$message .= sprintf( '%s=%d', $vcs_status_obj->{name}, $vcs_status_obj->{count} );
322
$self->{status}->SetValue($message);
324
$self->_show_command_bar( $list->GetItemCount > 0 )
325
if $self->main->config->vcs_enable_command_bar;
327
# Update the list sort image
328
$self->set_icon_image( $self->{sort_column}, $self->{sort_desc} );
331
Padre::Util::tidy_list($list);
336
sub _show_command_bar {
337
my ( $self, $shown ) = @_;
339
$self->{commit}->Show($shown);
340
$self->{add}->Show($shown);
341
$self->{delete}->Show($shown);
342
$self->{revert}->Show($shown);
343
$self->{update}->Show($shown);
348
my ( $self, %vcs_status ) = @_;
350
my @model = @{ $self->{model} };
351
if ( $self->{sort_column} == 0 ) {
354
@model = sort { $vcs_status{ $a->{status} }{name} cmp $vcs_status{ $b->{status} }{name} } @model;
356
} elsif ( $self->{sort_column} == 1 ) {
359
@model = sort { $a->{path} cmp $b->{path} } @model;
360
} elsif ( $self->{sort_column} == 2 ) {
363
@model = sort { $a->{author} cmp $b->{author} } @model;
364
} elsif ( $self->{sort_column} == 3 ) {
367
@model = sort { $a->{revision} cmp $b->{revision} } @model;
371
if ( $self->{sort_desc} ) {
373
# reverse the sorting
374
@model = reverse @model;
377
$self->{model} = \@model;
380
# Called when a version control list column is clicked
381
sub on_list_column_click {
382
my ( $self, $event ) = @_;
384
my $column = $event->GetColumn;
385
my $prevcol = $self->{sort_column};
386
my $reversed = $self->{sort_desc};
387
$reversed = $column == $prevcol ? !$reversed : 0;
388
$self->{sort_column} = $column;
389
$self->{sort_desc} = $reversed;
391
# Reset the previous column sort image
392
$self->set_icon_image( $prevcol, -1 );
400
my ( $self, $column, $image_index ) = @_;
402
my $item = Wx::ListItem->new;
403
$item->SetMask(Wx::LIST_MASK_IMAGE);
404
$item->SetImage($image_index);
405
$self->{list}->SetColumn( $column, $item );
410
sub on_list_item_activated {
411
my ( $self, $event ) = @_;
413
my $main = $self->main;
414
my $rec = $self->{model}->[ $self->{list}->GetItemData( $event->GetIndex ) ] or return;
415
my $filename = $rec->{fullpath};
418
# Try to open the file now
419
if ( my $id = $main->editor_of_file($filename) ) {
420
my $page = $main->notebook->GetPage($id);
423
$main->setup_editor($filename);
426
# Select the next difference after opening the file
430
$main->{diff}->select_next_difference;
431
Wx::Event::EVT_IDLE( $main, undef );
433
) if $main->config->feature_document_diffs;
436
$main->error( Wx::gettext('Error while trying to perform Padre action') ) if $@;
439
# Called when "Show normal" checkbox is clicked
440
sub on_show_normal_click {
441
my ( $self, $event ) = @_;
443
# Save to configuration
444
my $config = $self->main->config;
445
$config->apply( vcs_normal_shown => $event->IsChecked ? 1 : 0 );
452
# Called when "Show unversioned" checkbox is clicked
453
sub on_show_unversioned_click {
454
my ( $self, $event ) = @_;
456
# Save to configuration
457
my $config = $self->main->config;
458
$config->apply( vcs_unversioned_shown => $event->IsChecked ? 1 : 0 );
465
# Called when "Show ignored" checkbox is clicked
466
sub on_show_ignored_click {
467
my ( $self, $event ) = @_;
469
# Save to configuration
470
my $config = $self->main->config;
471
$config->apply( vcs_ignored_shown => $event->IsChecked ? 1 : 0 );
478
# Called when "Commit" button is clicked
479
sub on_commit_click {
481
my $main = $self->main;
484
unless $main->yes_no(
485
Wx::gettext("Do you want to commit?"),
486
Wx::gettext('Commit file/directory to repository?')
489
$main->vcs->refresh( $self->current, Padre::Task::VCS::VCS_COMMIT );
492
# Called when "Add" button is clicked
496
my $main = $self->main;
497
my $list = $self->{list};
498
my $selected_index = $list->GetNextItem( -1, Wx::LIST_NEXT_ALL, Wx::LIST_STATE_SELECTED );
499
return if $selected_index == -1;
500
my $rec = $self->{model}->[ $list->GetItemData($selected_index) ] or return;
501
my $filename = $rec->{fullpath};
504
unless $main->yes_no(
505
sprintf( Wx::gettext("Do you want to add '%s' to your repository"), $filename ),
506
Wx::gettext('Add file to repository?')
509
$main->vcs->refresh( $self->current, Padre::Task::VCS::VCS_ADD );
512
# Called when "Delete" checkbox is clicked
513
sub on_delete_click {
515
my $main = $self->main;
516
my $list = $self->{list};
517
my $selected_index = $list->GetNextItem( -1, Wx::LIST_NEXT_ALL, Wx::LIST_STATE_SELECTED );
518
return if $selected_index == -1;
519
my $rec = $self->{model}->[ $list->GetItemData($selected_index) ] or return;
520
my $filename = $rec->{fullpath};
523
unless $main->yes_no(
524
sprintf( Wx::gettext("Do you want to delete '%s' from your repository"), $filename ),
525
Wx::gettext('Delete file from repository??')
528
$main->vcs->refresh( $self->current, Padre::Task::VCS::VCS_DELETE );
531
# Called when "Update" button is clicked
532
sub on_update_click {
534
my $main = $self->main;
536
$main->vcs->refresh( $main->current, Padre::Task::VCS::VCS_UPDATE );
539
# Called when "Revert" button is clicked
540
sub on_revert_click {
542
my $main = $self->main;
543
my $list = $self->{list};
544
my $selected_index = $list->GetNextItem( -1, Wx::LIST_NEXT_ALL, Wx::LIST_STATE_SELECTED );
545
return if $selected_index == -1;
546
my $rec = $self->{model}->[ $list->GetItemData($selected_index) ] or return;
547
my $filename = $rec->{fullpath};
550
unless $main->yes_no(
551
sprintf( Wx::gettext("Do you want to revert changes to '%s'"), $filename ),
552
Wx::gettext('Revert changes?')
555
$main->vcs->refresh( $self->current, Padre::Task::VCS::VCS_REVERT );
560
# Copyright 2008-2011 The Padre development team as listed in Padre.pm.
562
# This program is free software; you can redistribute it and/or
563
# modify it under the same terms as Perl 5 itself.