The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Padre::Wx::Dialog::SessionManager;

# This file is part of Padre, the Perl ide.

use 5.008;
use strict;
use warnings;
use Padre::Wx       ();
use Padre::Wx::Icon ();
use Padre::Current  ();

our $VERSION = '0.96';
our @ISA     = 'Wx::Dialog';

use Class::XSAccessor {
	accessors => {
		_butdelete   => '_butdelete',   # delete button
		_butopen     => '_butopen',     # open button
		_currow      => '_currow',      # current list row number
		_curname     => '_curname',     # name of current session selected
		_list        => '_list',        # list on the left of the pane
		_sortcolumn  => '_sortcolumn',  # column used for list sorting
		_sortreverse => '_sortreverse', # list sorting is reversed
		_vbox        => '_vbox',        # the window vbox sizer
	}
};

# -- constructor

sub new {
	my ( $class, $parent ) = @_;

	# create object
	my $self = $class->SUPER::new(
		$parent,
		-1,
		Wx::gettext('Session Manager'),
		Wx::DefaultPosition,
		Wx::Size->new( 480, 300 ),
		Wx::DEFAULT_FRAME_STYLE | Wx::TAB_TRAVERSAL,
	);

	$self->SetIcon(Padre::Wx::Icon::PADRE);

	# create dialog
	$self->_create;

	return $self;
}

# -- public methods

sub show {
	my $self = shift;

	$self->_refresh_list;
	$self->_select_first_item;
	$self->_update_buttons_state;
	$self->Show;
}

# -- gui handlers

#
# $self->_on_butclose_clicked;
#
# handler called when the close button has been clicked.
#
sub _on_butclose_clicked {
	my $self = shift;
	$self->Destroy;
}

#
# $self->_on_butdelete_clicked;
#
# handler called when the delete button has been clicked.
#
sub _on_butdelete_clicked {
	my $self    = shift;
	my $current = $self->_current_session;

	# remove session: files, then session itself
	my $transaction = $self->GetParent->lock('DB');
	Padre::DB::SessionFile->delete_where( 'session = ?', $current->id );
	$current->delete;

	# update gui
	$self->_refresh_list;
	$self->_select_first_item;
	$self->_update_buttons_state;
}

#
# $self->_on_butopen_clicked;
#
# handler called when the open button has been clicked.
#
sub _on_butopen_clicked {
	my $self = shift;

	my $main = $self->GetParent;

	# prevents crash if user double-clicks on list
	# item and tries to click buttons
	$self->_butdelete->Disable;
	$self->_butopen->Disable;

	if ( !defined( $self->_current_session ) ) {
		$main->error(
			sprintf(
				Wx::gettext("Something is wrong with your Padre database:\nSession %s is listed but there is no data"),
				$self->_curname
			)
		);
		return;
	}

	# Save autosave setting
	my $config = Padre->ide->config;
	$config->set(
		'session_autosave',
		$self->{autosave}->GetValue ? 1 : 0
	);
	$config->write;

	# Open session
	$main->open_session( $self->_current_session, $self->{autosave}->GetValue ? 1 : 0 );
	$self->Destroy;
}

#
# $self->_on_list_col_click;
#
# handler called when a column has been clicked, to reorder the list.
#
sub _on_list_col_click {
	my ( $self, $event ) = @_;
	my $col = $event->GetColumn;

	my $prevcol  = $self->_sortcolumn  || 0;
	my $reversed = $self->_sortreverse || 0;
	$reversed = $col == $prevcol ? !$reversed : 0;
	$self->_sortcolumn($col);
	$self->_sortreverse($reversed);
	$self->_refresh_list( $col, $reversed );
}

#
# $self->_on_list_item_selected( $event );
#
# handler called when a list item has been selected. it will in turn update
# the buttons state.
#
# $event is a Wx::ListEvent.
#
sub _on_list_item_selected {
	my ( $self, $event ) = @_;

	my $name = $event->GetLabel;
	$self->_curname($name);             # storing selected session
	$self->_currow( $event->GetIndex ); # storing selected row

	# update buttons
	$self->_update_buttons_state;
}

#
# $self->_on_list_item_activated( $event );
#
# handler called when a list item has been double clicked. it will automatically open
# the selected session
#
# $event is a Wx::ListEvent.
#
sub _on_list_item_activated {
	my ( $self, $event ) = @_;

	$self->_on_list_item_selected($event);
	$self->_on_butopen_clicked;
}

# -- private methods

#
# $self->_create;
#
# create the dialog itself. it will have a list with all found sessions, and
# some buttons to manage them.
#
# no params, no return values.
#
sub _create {
	my $self = shift;

	# create vertical box that will host all controls
	my $vbox = Wx::BoxSizer->new(Wx::VERTICAL);
	$self->SetSizer($vbox);
	$self->CenterOnParent;

	#$self->SetMinSize( [ 640, 480 ] );
	$self->_vbox($vbox);

	$self->_create_list;
	$self->_create_options;
	$self->_create_buttons;
	$self->_list->SetFocus;
}

#
# $dialog->_create_list;
#
# create the sessions list. it will hold a list of available sessions, along
# with their description & last update.
#
# no params. no return values.
#
sub _create_list {
	my $self = shift;
	my $vbox = $self->_vbox;

	# title label
	my $label = Wx::StaticText->new(
		$self, -1,
		Wx::gettext('List of sessions')
	);
	$vbox->Add( $label, 0, Wx::ALL, 5 );

	# create list
	my $list = Wx::ListView->new(
		$self,
		-1,
		Wx::DefaultPosition,
		Wx::DefaultSize,
		Wx::LC_REPORT | Wx::LC_SINGLE_SEL,
	);
	$list->InsertColumn( 0, Wx::gettext('Name') );
	$list->InsertColumn( 1, Wx::gettext('Description') );
	$list->InsertColumn( 2, Wx::gettext('Last update') );
	$self->_list($list);

	# install event handler
	Wx::Event::EVT_LIST_ITEM_SELECTED( $self, $list, \&_on_list_item_selected );
	Wx::Event::EVT_LIST_ITEM_ACTIVATED( $self, $list, \&_on_list_item_activated );
	Wx::Event::EVT_LIST_COL_CLICK( $self, $list, \&_on_list_col_click );

	# pack the list
	$vbox->Add( $list, 1, Wx::ALL | Wx::EXPAND, 5 );
}

#
# $dialog->_create_options;
#
# create the options
#
# no params. no return values.
#
sub _create_options {
	my $self = shift;

	my $config = Padre->ide->config;

	# the hbox
	my $hbox = Wx::BoxSizer->new(Wx::HORIZONTAL);
	$self->_vbox->Add( $hbox, 0, Wx::ALL | Wx::EXPAND, 5 );

	# CheckBox
	$self->{autosave} = Wx::CheckBox->new(
		$self,
		-1,
		Wx::gettext('&Save session automatically'),
	);
	$self->{autosave}->SetValue( $config->session_autosave ? 1 : 0 );

	#		Wx::Event::EVT_CHECKBOX(
	#			$self,
	#			$self->{autosave},
	#			sub {
	#			$_[0]->{find_text}->SetFocus;
	#			}
	#		);

	$hbox->Add( $self->{autosave}, 0, Wx::ALL, 5 );
}

#
# $dialog->_create_buttons;
#
# create the buttons pane.
#
# no params. no return values.
#
sub _create_buttons {
	my $self = shift;

	# the hbox
	my $hbox = Wx::BoxSizer->new(Wx::HORIZONTAL);
	$self->_vbox->Add( $hbox, 0, Wx::ALL | Wx::EXPAND, 5 );

	# the buttons
	my $bo = Wx::Button->new( $self, -1,            Wx::gettext('&Open') );
	my $bd = Wx::Button->new( $self, -1,            Wx::gettext('&Delete') );
	my $bc = Wx::Button->new( $self, Wx::ID_CANCEL, Wx::gettext('&Close') );
	$self->_butopen($bo);
	$self->_butdelete($bd);
	Wx::Event::EVT_BUTTON( $self, $bo, \&_on_butopen_clicked );
	Wx::Event::EVT_BUTTON( $self, $bd, \&_on_butdelete_clicked );
	Wx::Event::EVT_BUTTON( $self, $bc, \&_on_butclose_clicked );
	$hbox->Add( $bo, 0, Wx::ALL, 5 );
	$hbox->Add( $bd, 0, Wx::ALL, 5 );
	$hbox->AddStretchSpacer;
	$hbox->Add( $bc, 0, Wx::ALL, 5 );
}

#
# my $session = $self->_current_session;
#
# return the padre::db::session object corresponding to currently selected line
# in the list. return undef if no object selected.
#
sub _current_session {
	my $self = shift;

	my ($current) = Padre::DB::Session->select(
		'where name = ?',
		$self->_curname
	);

	# The session name may get some spaces around it even if they are not in the database
	# This workaround removes all leading/following spaces and tries loading again
	if ( !defined($current) ) {
		my $curname = $self->_curname;
		$curname =~ s/^\s*(.+?)\s*$/$1/;

		($current) = Padre::DB::Session->select(
			'where name = ?',
			$curname
		);

	}

	return $current;
}

#
# $dialog->_refresh_list($column, $reverse);
#
# refresh list of sessions. list is sorted according to $column (default to
# first column), and may be reversed (default to no).
#
sub _refresh_list {
	my ( $self, $column, $reverse ) = @_;

	my $config = Padre::Current->config;

	if ( defined($column) and defined($reverse) ) {
		$config->set( 'sessionmanager_sortorder', join( ',', $column, $reverse ) );
		$config->write;
	} else {
		( $column, $reverse ) = split( /,/, $config->sessionmanager_sortorder );
	}

	# default sorting
	$column  ||= 0;
	$reverse ||= 0;

	my @fields = qw{ name description last_update }; # db fields of table session

	# get list of sessions, sorted.
	my $sort = "ORDER BY $fields[$column]";
	$sort .= ' DESC' if $reverse;
	my @sessions = Padre::DB::Session->select($sort);

	# clear list & fill it again
	my $list = $self->_list;
	$list->DeleteAllItems;
	foreach my $session ( reverse @sessions ) {
		my $name  = $session->name;
		my $descr = $session->description;

		# adjust name and description length (fix #1124)
		if ( length $name < 10 ) {
			$name .= ' ' x ( 10 - length $name );
		}
		if ( length $descr < 30 ) {
			$descr .= ' ' x ( 30 - length $descr );
		}

		require POSIX;
		my $update = POSIX::strftime(
			'%Y-%m-%d %H:%M:%S',
			localtime $session->last_update,
		);

		# insert the session in the list
		my $item = Wx::ListItem->new;
		$item->SetId(0);
		$item->SetColumn(0);
		$item->SetText($name);
		my $idx = $list->InsertItem($item);
		$list->SetItem( $idx, 1, $descr );
		$list->SetItem( $idx, 2, $update );
	}

	# auto-resize columns
	my $flag =
		$list->GetItemCount
		? Wx::LIST_AUTOSIZE
		: Wx::LIST_AUTOSIZE_USEHEADER;
	$list->SetColumnWidth( $_, $flag ) for 0 .. 2;

	# making sure the list can show all columns
	my $width = 15; # taking vertical scrollbar into account
	$width += $list->GetColumnWidth($_) for 0 .. 2;
	$list->SetMinSize( [ $width, -1 ] );
}

#
# $self->_select_first_item;
#
# select first item in the list, or none if there are none. in that case,
# update the current row and name selection to undef.
#
sub _select_first_item {
	my ($self) = @_;

	# select first item in the list
	my $list = $self->_list;

	if ( $list->GetItemCount ) {
		my $item = $list->GetItem(0);
		$item->SetState(Wx::LIST_STATE_SELECTED);
		$list->SetItem($item);
	} else {

		# remove current selection
		$self->_currow(undef);
		$self->_curname(undef);
	}
}

#
# $self->_update_buttons_state;
#
# update state of delete and open buttons: they should not be clickable if no
# session is selected.
#
sub _update_buttons_state {
	my ($self) = @_;

	my $method = defined( $self->_currow ) ? 'Enable' : 'Disable';
	$self->_butdelete->$method;
	$self->_butopen->$method;
}

1;

__END__


=head1 NAME

Padre::Wx::Dialog::SessionManager - Session manager dialog for Padre



=head1 DESCRIPTION

Padre supports sessions, that is, a bunch of files opened. But we need to
provide a way to manage those sessions: listing, removing them, etc. This
module implements this task as a dialog for Padre.



=head1 PUBLIC API

=head2 Constructor

=head3 C<new>

    my $dialog = PWD::SM->new( $parent )

Create and return a new Wx dialog listing all the sessions. It needs a
C<$parent> window (usually Padre's main window).

=head2 Public methods

=head3 C<show>

    $dialog->show;

Request the session manager dialog to be shown. It will be refreshed first with
a current list of sessions.


=head1 COPYRIGHT & LICENSE

Copyright 2008-2012 The Padre development team as listed in Padre.pm.

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl 5 itself.


=cut


# Copyright 2008-2012 The Padre development team as listed in Padre.pm.
# LICENSE
# This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl 5 itself.