/usr/local/CPAN/JaM/JaM/GUI/Subjects.pm
# $Id: Subjects.pm,v 1.20 2001/11/02 12:31:02 joern Exp $
package JaM::GUI::Subjects;
@ISA = qw ( JaM::GUI::Component );
use strict;
use JaM::Func;
use JaM::GUI::Component;
my $DEBUG = 1;
# get/set currently listed mails
sub mail_ids { my $s = shift; $s->{mail_ids}
= shift if @_; $s->{mail_ids} }
# get/set currently mail id where popup opened
sub popup_mail_id { my $s = shift; $s->{popup_mail_id}
= shift if @_; $s->{popup_mail_id} }
# get/set currently selected folder
sub folder_object { my $s = shift; $s->{folder_object}
= shift if @_; $s->{folder_object} }
# get/set gtk object for subjects scrolled window
sub gtk_subjects { my $s = shift; $s->{gtk_subjects}
= shift if @_; $s->{gtk_subjects} }
# get/set gtk object for subjects clist
sub gtk_subjects_list { my $s = shift; $s->{gtk_subjects_list}
= shift if @_; $s->{gtk_subjects_list} }
# get/set currently first selected mail id
sub selected_mail_id { my $s = shift; $s->trace_in; $s->{selected_mail_id}
= shift if @_; $s->{selected_mail_id} }
sub gtk_folder_menu { my $s = shift; $s->{gtk_folder_menu}
= shift if @_; $s->{gtk_folder_menu} }
sub gtk_folder_menu_item{ my $s = shift; $s->{gtk_folder_menu_item}
= shift if @_; $s->{gtk_folder_menu_item} }
# return lref of selected mail ids
sub selected_mail_ids {
my $self = shift;
my @rows = $self->gtk_subjects_list->selection;
my @ids;
my $mail_ids = $self->mail_ids;
foreach my $row ( @rows ) {
push @ids, $mail_ids->[$row];
}
return \@ids;
}
# build subjects widget
sub build {
my $self = shift; $self->trace_in;
my %par = @_;
my ($without_quick_search, $without_resize_tracking) =
@par{'without_quick_search','without_resize_tracking'};
# Create a ScrolledWindow for the list
my $subjects = new Gtk::ScrolledWindow( undef, undef );
$subjects->set_policy( 'automatic', 'automatic' );
$subjects->set_usize(undef, $self->config('subjects_height'));
$subjects->show();
# Create list box
my @titles = qw( Status Subject Sender Date );
my $list = Gtk::CList->new_with_titles ( @titles );
$subjects->add( $list );
$list->set_column_width( 0, $self->config('subjects_column_0') );
$list->set_column_width( 1, $self->config('subjects_column_1') );
$list->set_column_width( 2, $self->config('subjects_column_2') );
$list->set_column_width( 3, $self->config('subjects_column_3') );
# $list->set_selection_mode( 'browse' );
$list->set_selection_mode( 'extended' );
$list->set_shadow_type( 'none' );
$list->set_user_data ( $self );
$list->signal_connect( "select_row", sub { $self->cb_select_mail(@_) } );
$list->signal_connect( "click_column", sub { $self->cb_column_click(@_) } );
if ( not $without_resize_tracking ) {
$list->signal_connect( "resize-column",
sub {
$self->config('subjects_column_'.$_[1], $_[2]);
}
);
$subjects->signal_connect("size-allocate",
sub { $self->config('subjects_height', $_[1]->[3]) }
);
}
$list->show();
# now build popup Menu
$list->signal_connect('button_press_event', sub { $self->cb_click_subjects(@_) } );
my $popup = $list->{popup} = Gtk::Menu->new;
my $item;
# $item = Gtk::MenuItem->new ("Mark selected mail(s) as read...");
# $popup->append($item);
# $item->signal_connect ("activate", sub { $self->cb_mark_mail_as_read ( @_ ) } );
# $item->show;
my $folder_menu_item = Gtk::MenuItem->new ("Move selected mail(s) to folder...");
$popup->append($folder_menu_item);
$folder_menu_item->show;
my $folder_menu = $self->comp('folders')->build_menu_of_folders (
callback => sub { $self->move_selected_mails ( folder_id => $_[0] ); }
);
$folder_menu_item->set_submenu($folder_menu);
$item = Gtk::MenuItem->new;
$popup->append($item);
$item->show;
$item = Gtk::MenuItem->new ("Add Input Filter...");
$popup->append($item);
$item->signal_connect ("activate", sub { $self->cb_add_input_filter ( @_ ) } );
$item->show;
if ( not $without_quick_search ) {
$item = Gtk::MenuItem->new;
$popup->append($item);
$item->show;
$item = Gtk::MenuItem->new ("Quick Search Sender...");
$popup->append($item);
$item->signal_connect ("activate", sub {
$self->comp('subjects')->quick_search(
type => 'sender'
);
});
$item->show;
$item = Gtk::MenuItem->new ("Quick Search Subject...");
$popup->append($item);
$item->signal_connect ("activate", sub {
$self->comp('subjects')->quick_search(
type => 'subject'
);
});
$item->show;
$item = Gtk::MenuItem->new ("Quick Search Body...");
$popup->append($item);
$item->signal_connect ("activate", sub {
$self->comp('subjects')->quick_search(
type => 'body'
);
});
$item->show;
$item = Gtk::MenuItem->new ("Quick Search Recipient...");
$popup->append($item);
$item->signal_connect ("activate", sub {
$self->comp('subjects')->quick_search(
type => 'recipient'
);
});
$item->show;
$item = Gtk::MenuItem->new;
$popup->append($item);
$item->show;
$item = Gtk::MenuItem->new ("Advanced Search...");
$popup->append($item);
$item->signal_connect ("activate", sub {
require JaM::GUI::Search;
my $search = JaM::GUI::Search->new (
dbh => $self->dbh
);
$search->open_window;
$search->folder_chosen ($self->folder_object->id);
});
$item->show;
}
$self->gtk_subjects ($subjects);
$self->gtk_subjects_list ($list);
$self->gtk_folder_menu ($folder_menu);
$self->gtk_folder_menu_item ($folder_menu_item);
$self->widget ($subjects);
return $self;
}
sub cb_click_subjects {
my $self = shift;
my ($widget, $event) = @_;
my ( $row, $column ) = $widget->get_selection_info( $event->{x}, $event->{y} );
if ( $self->mail_ids ) {
$self->popup_mail_id ( $self->mail_ids->[$row] );
} else {
$self->popup_mail_id (undef);
}
if ( $event->{button} == 3 and $widget->{'popup'} ) {
my $folder_menu_item = $self->gtk_folder_menu_item;
$folder_menu_item->remove_submenu;
my $folder_menu = $self->comp('folders')->build_menu_of_folders (
callback => sub { $self->move_selected_mails ( folder_id => $_[0] ); }
);
$folder_menu_item->set_submenu($folder_menu);
$widget->{'popup'}->popup(undef,undef,$event->{button},1);
}
1;
}
sub cb_add_input_filter {
my $self = shift;
my $filter;
eval { $filter = $self->comp('input_filter') };
if ( not $filter ) {
require JaM::GUI::IO_Filter;
$filter = JaM::GUI::IO_Filter->new (
dbh => $self->dbh,
);
$filter->open_window;
}
my $mail = JaM::Mail->load ( dbh => $self->dbh, mail_id => $self->popup_mail_id );
my $folder = JaM::Folder->by_id ($mail->folder_id);
$filter->add_new_filter (
folder_object => $folder,
mail_object => $mail
);
$filter->gtk_win->focus(1);
1;
}
# update subjects list with content of a selected folder
sub show {
my $self = shift; $self->trace_in;
my %par = @_;
my ($folder_object, $where, $params, $tables, $sql) =
@par{'folder_object','where','params','tables','sql'};
$folder_object ||= $self->folder_object;
my $is_sent_folder;
if ( $folder_object ) {
$self->folder_object ( $folder_object );
$is_sent_folder =
($folder_object->id == $self->config('sent_folder_id') or
$folder_object->id == $self->config('drafts_folder_id') or
$folder_object->id == $self->config('templates_folder_id') );
}
my $list = $self->gtk_subjects_list;
my $dbh = $self->dbh;
$list->clear;
$list->freeze;
my $sender_column;
if ( $is_sent_folder ) {
$list->set_column_title (2, "To");
$sender_column = "head_to";
} else {
$list->set_column_title (2, "Sender");
$sender_column = "sender";
}
my $column;
my $direction;
if ( $folder_object ) {
$column = $folder_object->sort_column;
$direction = $folder_object->sort_direction;
$direction = $direction eq 'ascending' ? "" : "desc";
} else {
$column = 5;
$direction = "desc";
}
foreach my $i (0..3) {
my $title = $list->get_column_title ($i);
$title =~ s/[\[\]<> ]//g;
if ( $i == $column ) {
$title = "[ $title > ]" if $direction eq 'desc';
$title = "[ $title < ]" if $direction eq '';
}
$list->set_column_title ($i, $title);
}
$self->debug ("sort by $column $direction");
$column += 2;
my $limit;
if ( $folder_object and not $folder_object->show_all ) {
$limit = "limit ".$folder_object->show_max;
}
$self->debug ("limit='$limit'");
if ( $where ) {
$where = "and $where";
$params ||= [];
$tables = ", $tables" if $tables;
}
if ( not $sql ) {
$sql = "select Mail.id, Mail.status, Mail.subject, Mail.$sender_column,
UNIX_TIMESTAMP(Mail.date)
from Mail $tables
where folder_id = ? $where
order by $column $direction, 5 $direction
$limit";
}
my $sth = $dbh->prepare ($sql);
if ( $folder_object ) {
$sth->execute ( $folder_object->id, @{$params} );
} else {
$sth->execute ( @{$params} );
}
my $unread_style = $list->style->copy;
$unread_style->font($self->config('font_mail_unread'));
my $read_style = $list->style->copy;
$read_style->font($self->config('font_mail_read'));
my @mail_ids;
my ($id, $status, $subject, $sender, $date);
my $selected_row = 0;
my $cnt = 0;
my $selected_mail_id;
$selected_mail_id = $folder_object->selected_mail_id if $folder_object;
$self->mail_ids (undef);
while ( ($id, $status, $subject, $sender, $date) = $sth->fetchrow_array ) {
push @mail_ids, $id;
$sender =~ s/<.*?>// if $sender !~ /^</;
$sender =~ s/"//g;
$list->append(
$status, $subject, $sender,
JaM::Func->format_date (time => $date, nice => 1)
);
$list->set_row_style(
$cnt, $status eq 'N' ?
$unread_style : $read_style
);
$selected_row = $cnt if $selected_mail_id == $id;
++$cnt;
}
$sth->finish;
$self->debug ("Mails scanned: ",scalar(@mail_ids));
$self->mail_ids (\@mail_ids);
$list->thaw;
if ( $cnt ) {
# select the correct entry
$list->select_row( $selected_row, -1 );
# scroll list to see the selected row
$list->moveto( $selected_row, 0, 0.5, 0 );
} else {
$self->comp('mail')->clear;
$self->selected_mail_id(undef);
}
1;
}
sub prepend_new_mail {
my $self = shift; $self->trace_in;
my %par = @_;
my ($mail_id) = @par{'mail_id'};
my $list = $self->gtk_subjects_list;
my $dbh = $self->dbh;
my $folder_object = $self->folder_object;
my $is_sent_folder =
($folder_object->id == $self->config('sent_folder_id') or
$folder_object->id == $self->config('drafts_folder_id') or
$folder_object->id == $self->config('templates_folder_id') );
my $sender_column;
if ( $is_sent_folder ) {
$list->set_column_title (2, "To");
$sender_column = "head_to";
} else {
$list->set_column_title (2, "Sender");
$sender_column = "sender";
}
$list->freeze;
my $sth = $dbh->prepare (
"select id, status, subject, $sender_column, UNIX_TIMESTAMP(date)
from Mail
where id = ?"
);
$sth->execute ( $mail_id );
my $unread_style = $list->style->copy;
$unread_style->font($self->config('font_mail_unread'));
my $read_style = $list->style->copy;
$read_style->font($self->config('font_mail_read'));
my $item;
my ($id, $status, $subject, $sender, $date) = $sth->fetchrow_array;
$sth->finish;
$sender =~ s/<.*?>// if $sender !~ /^</;
$sender =~ s/"//g;
$item = $list->prepend(
$status, $subject, $sender,
JaM::Func->format_date (time => $date, nice => 1)
);
$list->set_row_style(
0, $status eq 'N' ?
$unread_style : $read_style
);
$list->thaw;
my $mail_ids = $self->mail_ids;
unshift @{$mail_ids}, $mail_id;
1;
}
sub remove_selected {
my $self = shift;
my $clist = $self->gtk_subjects_list;
my @rows = $clist->selection;
$self->remove_rows (
rows => \@rows
);
1;
}
sub remove_rows {
my $self = shift;
my %par = @_;
my ($rows) = @par{'rows'};
my $clist = $self->gtk_subjects_list;
my $mail_ids = $self->mail_ids;
$clist->freeze;
@{$rows} = sort { $b <=> $a } @{$rows};
my $selected = $rows->[@{$rows}-1];
foreach my $row ( @{$rows} ) {
splice (@{$mail_ids}, $row, 1);
$clist->remove ( $row );
}
if ( @{$mail_ids} == 0 ) {
$self->comp('mail')->clear;
} else {
--$selected if $selected >= @{$mail_ids};
$clist->select_row ( $selected, 1 );
}
$clist->thaw;
1;
}
sub cb_select_mail {
my $self = shift; $self->trace_in;
my ($clist, $row, $column, $event) = @_;
return 1 if not defined $self->mail_ids;
my @sel = $self->gtk_subjects_list->selection;
return if @sel > 1;
# determine selected mail id
my $mail_id = $self->mail_ids->[$row];
$self->debug ("column=$column mail_id=$mail_id selected_id=".$self->selected_mail_id);
# nothing todo if this mail is already selected
# (and we don't have a double click)
return 1 if $self->selected_mail_id == $mail_id and $event->{type} ne '2button_press';
if ( $column == 0 ) {
# status click, only changes status of mail
$self->change_mail_status ( mail_id => $mail_id, row => $row );
return 1;
}
if ( $self->selected_mail_id != $mail_id ) {
$self->selected_mail_id ( $mail_id );
$self->debug ("mail_id=$mail_id selected_id=".$self->selected_mail_id);
$self->folder_object->selected_mail_id ( $mail_id );
$self->folder_object->save;
$self->comp('mail')->show ( mail_id => $mail_id );
$self->comp('folders')->update_folder_item;
$self->show_mail_status (
row => $row,
status => $self->comp('mail')->mail->status
);
}
if ( $event->{type} eq '2button_press' and
( $self->folder_object->id == $self->config('drafts_folder_id') or
$self->folder_object->id == $self->config('templates_folder_id') ) ) {
my $compose = $self->comp('mail')->open_compose_window;
$compose->delete_mail_after_send ($self->comp('mail')->mail)
if $self->folder_object->id == $self->config('drafts_folder_id');
return 1;
}
1;
}
sub show_mail_status{
my $self = shift; $self->trace_in;
my %par = @_;
my ($status, $row) = @par{'status','row'};
my $widget = $self->gtk_subjects_list;
my $read_style = $widget->style->copy;
my $font = $status eq 'R' ? 'font_mail_read' : 'font_mail_unread';
$read_style->font($self->config($font));
$widget->set_row_style( $row, $read_style );
$widget->set_text( $row, 0, $status );
1;
}
sub change_mail_status {
my $self = shift; $self->trace_in;
my %par = @_;
my ($mail_id, $row) = @par{'mail_id','row'};
my $mail = JaM::Mail->load ( dbh => $self->dbh, mail_id => $mail_id );
my $status = $mail->status;
$status = ( $status eq 'R' ) ? 'N' : 'R';
$mail->status ( $status );
$self->show_mail_status ( status => $status, row => $row );
$self->comp('folders')->update_folder_item;
1;
}
sub cb_column_click {
my $self = shift;
my ($clist, $clicked_column) = @_;
my $folder_object = $self->folder_object;
return 1 if not $folder_object;
my $folders = $self->comp('folders');
my $column = $folder_object->sort_column;
my $direction = $folder_object->sort_direction;
if ( $column == $clicked_column ) {
$direction = $direction eq 'ascending' ? 'descending' : 'ascending';
}
$self->debug ("set sort info: $column, $direction");
$folder_object->sort_column ($clicked_column);
$folder_object->sort_direction ($direction);
$folder_object->save;
$self->show;
1;
}
sub quick_search {
my $self = shift;
my %par = @_;
my ($type) = @par{'type'};
my $dialog = Gtk::Dialog->new;
$dialog->border_width(10);
$dialog->set_position('mouse');
$dialog->set_modal ( 1 );
$dialog->set_title ("Quicksearch: '$type'");
my $label = Gtk::Label->new ("Quicksearch: '$type'");
$dialog->vbox->pack_start ($label, 1, 1, 0);
$label->show;
my $text = Gtk::Entry->new ( 40 );
$dialog->vbox->pack_start ($text, 1, 1, 0);
$text->show;
$text->grab_focus;
my $ok = new Gtk::Button( "Ok" );
$ok->show;
$dialog->action_area->pack_start( $ok, 1, 1, 0 );
if ( $type eq 'body' ) {
$ok->signal_connect( "clicked", sub {
$self->show (
where => "Entity.data like '%".$text->get_text."%' and ".
"Entity.mail_id = Mail.id",
tables => "Entity",
);
$dialog->destroy;
} );
} else {
$type = "head_to" if $type eq 'recipient';
$ok->signal_connect( "clicked", sub {
$self->show (
where => "$type like '%".$text->get_text."%'"
);
$dialog->destroy;
} );
}
my $cancel = new Gtk::Button( "Cancel" );
$dialog->action_area->pack_start( $cancel, 1, 1, 0 );
$cancel->signal_connect( "clicked", sub { $dialog->destroy } );
$cancel->show();
$dialog->show;
return $dialog;
}
sub move_selected_mails {
my $self = shift;
my %par = @_;
my ($folder_id) = @par{'folder_id'};
my $selected_mail_ids = $self->selected_mail_ids;
return if not @{$selected_mail_ids};
my $folder_object = JaM::Folder->by_id ($folder_id);
$self->comp('mail')->move_to_folder (
folder_object => $folder_object,
mail_ids => $selected_mail_ids
);
$self->remove_selected;
1;
}
1;