package Uploader::GUI::App; use threads; use threads::shared; use Thread::Queue; use strict; use base qw/Wx::App Class::Accessor::Fast/; use Wx qw/ wxBITMAP_TYPE_GIF wxBITMAP_TYPE_ICO wxBITMAP_TYPE_BMP wxBITMAP_TYPE_PNG wxBITMAP_TYPE_JPEG wxIMAGE_QUALITY_HIGH wxSPLASH_CENTRE_ON_SCREEN wxSPLASH_TIMEOUT wxDefaultPosition wxDefaultSize wxSIMPLE_BORDER wxFRAME_TOOL_WINDOW wxFRAME_NO_TASKBAR wxSTAY_ON_TOP wxWHITE wxICON_EXCLAMATION wxICON_QUESTION wxOK wxYES wxYES_NO wxNO_DEFAULT wxICON_ERROR wxLANGUAGE_CHINESE_SIMPLIFIED wxLANGUAGE_CZECH wxLANGUAGE_DANISH wxLANGUAGE_DUTCH wxLANGUAGE_ENGLISH wxLANGUAGE_FRENCH wxLANGUAGE_GERMAN wxLANGUAGE_HUNGARIAN wxLANGUAGE_ITALIAN wxLANGUAGE_JAPANESE wxLANGUAGE_POLISH wxLANGUAGE_PORTUGUESE wxLANGUAGE_PORTUGUESE_BRAZILIAN wxLANGUAGE_RUSSIAN wxLANGUAGE_SLOVAK wxLANGUAGE_SPANISH /; use Wx::Locale qw/:default/; use File::HomeDir; use Uploader::PWG; use Uploader::Images; use Uploader::Connection; use Uploader::Preferences; use Uploader::ResizeManager; use Uploader::TransferManager; use Uploader::GUI::LoginDlg; use Storable; use utf8; use Data::Dumper; use IO::Socket; use Wx::Socket; my $received_filename_event : shared = Wx::NewEventType; my $transfer_progress_event : shared = Wx::NewEventType; my $transfer_done_event : shared = Wx::NewEventType; my $transfer_batch_end_event : shared = Wx::NewEventType; my $resize_done_event : shared = Wx::NewEventType; my $resize_progress_event : shared = Wx::NewEventType; my $resize_batch_end_event : shared = Wx::NewEventType; my $image_progress_event = Wx::NewEventType; $|=1; my @app_properties = qw/ localized_msg version frame argv images images_version preferences preferences_version user_def_preferences privacy_level upload_hd resize_manager transfer_manager /; my @connection_properties = qw/ connection_version connection login_dlg branding use_offline use_connected pwg /; my @file_properties = qw/ bin_dir resource_dir thumb_dir resized_dir wx_thumb_dir userdata_dir root_dir locale_dir preferences_file connection_file images_file app_file instance_checker_file /; my @localized_properties = qw/ colors positions upload_hd caption_patterns /; my @language_properties = qw/ current_language locale languages available_languages eng_colors eng_positions eng_upload_hd eng_caption_patterns /; my @custom_events = qw/ resize_start_event batch_end_event image_progress_event image_done_event /; __PACKAGE__->mk_accessors(@app_properties); __PACKAGE__->mk_accessors(@file_properties); __PACKAGE__->mk_accessors(@connection_properties); __PACKAGE__->mk_accessors(@localized_properties); __PACKAGE__->mk_accessors(@language_properties); __PACKAGE__->mk_accessors(@custom_events); my $_params; sub new { my ( $self, $params ) = @_; $_params = $params; $self->SUPER::new(); } sub OnInit { my( $self ) = @_; $self->init_properties_from_params; $self->init_application_properties; $self->init_single_instance_checker; $self->init_file_properties; $self->init_locale; $self->init_localized_properties; $self->init_preferences; $self->init_resize_manager; $self->init_images; return 0 unless $self->is_single_instance_server; $self->connect_or_exit; } sub OnExit { my( $self ) = @_; unlink $self->instance_checker_file if -e $self->instance_checker_file; $self->store_all; } sub store_all { my( $self ) = @_; $self->connection->Store;; $self->images->Store; $self->preferences->Store; } sub reset_add_rank { my ( $self ) = @_; $self->images->reset_add_rank; } sub cancel_all { my ( $self ) = @_; $self->cancel_transfer if $self->cancel_resize; } sub stop_all { my( $self ) = @_; $self->resize_manager->stop; $self->transfer_manager->stop; $self->stop_single_instance_server; $self->login_dlg->Destroy; } sub init_properties_from_params { my ( $self ) = @_; map { $self->$_( $_params->{$_} ) } keys %$_params; } sub init_application_properties { my ( $self ) = @_; $self->version( '1.7' ); Wx::InitAllImageHandlers(); $self->{IMGTYPE} = { 'jpg' => wxBITMAP_TYPE_JPEG, 'gif' => wxBITMAP_TYPE_GIF, 'png' => wxBITMAP_TYPE_PNG, }; my $applicationName = "pLoader" ; $self->SetAppName( $applicationName ); $self->SetVendorName( "Piwigo Team" ); } sub init_single_instance_checker { my ( $self ) = @_; my $id_user=$ENV{USERNAME} || $ENV{USER} || $ENV{LOGNAME}; # must save the object $self->{_instance_checker} = Wx::SingleInstanceChecker->new; my $pid = sprintf( "%s-%s", $self->GetAppName, $id_user, ); $self->{_instance_checker}->Create( $pid ); $self->instance_checker_file( File::Spec->canonpath( File::Spec->catfile( File::HomeDir->my_home(), $pid ) ) ); } sub init_file_properties { my ( $self ) = @_; my $applicationName = $self->GetAppName ; my $userdatadir = File::Spec->canonpath( File::Spec->catfile( File::HomeDir->my_data(), $applicationName ) ); if(! -d $userdatadir){ if(! mkdir $userdatadir){ Wx::MessageBox( sprintf( "%s directory creation failed", $userdatadir, ), "pLoader working directory creation error", wxOK | wxICON_EXCLAMATION, ); $userdatadir = File::Spec->canonpath( File::Spec->catfile( File::Spec->tmpdir(), $applicationName ) ); mkdir $userdatadir; } } $self->userdata_dir($userdatadir); $self->app_file( $self->userdata_filepath("$applicationName.dat") ); $self->preferences_file( $self->userdata_filepath("preferences.dat") ); $self->connection_file( $self->userdata_filepath("connection.dat") ); $self->images_file( $self->userdata_filepath("images.dat") ); my $thumbdir = $self->userdata_filepath('thumbnails'); mkdir $thumbdir unless -d $thumbdir ; $self->thumb_dir($thumbdir); my $wxthumbdir = $self->userdata_filepath('wxthumbnails'); mkdir $wxthumbdir unless -d $wxthumbdir ; $self->wx_thumb_dir($wxthumbdir); my $resizedir = $self->userdata_filepath('resize'); mkdir $resizedir unless -d $resizedir ; $self->resized_dir($resizedir); } sub userdata_filepath { my ( $self, $filename ) = @_; File::Spec->catfile( $self->userdata_dir, $filename ); } sub read_params { my( $self, $file ) = @_ ; my $expr_params ; eval { $expr_params = read_file( $file ); } ; my $paramValues = [] ; if($expr_params){ my $expr = '$paramValues = ' ; $expr .= "$expr_params ; " ; eval $expr ; } return unless 'ARRAY' eq ref $paramValues ; if(scalar(@$paramValues )){ my $params = $paramValues->[0] ; $self->set_key_values($params); } } sub set_key_values { my ( $self, $params )= @_; foreach( keys %$params ) { $self->{$_} = $params->{$_} ; } } sub init_connection { my ( $self ) = @_; $self->connection_version('0.1'); my $stored = $self->retrieve_from_file( $self->connection_file, $self->connection_version ); $self->connection( $stored ? Uploader::Connection->new( $stored ): Uploader::Connection->new( $self->default_connection ) ); } sub default_connection { my ( $self ) = @_; my $connection = { version => $self->connection_version, storable_file => $self->connection_file, }; return $connection; } my $locale; sub init_locale { my ( $self, $language ) = @_; $self->languages( [ ["中文 (%s)", wxLANGUAGE_CHINESE_SIMPLIFIED, 'Chinese simplified'], ["Česky (%s)", wxLANGUAGE_CZECH, 'Czech'], ["Dansk (%s)", wxLANGUAGE_DANISH, 'Danish'], ["Deutsch (%s)", wxLANGUAGE_GERMAN, 'German'], ["English (%s)", wxLANGUAGE_ENGLISH, 'English'], ["Español (%s)", wxLANGUAGE_SPANISH, 'Spanish'], ["Français (%s)", wxLANGUAGE_FRENCH, 'French'], ["Italiano (%s)", wxLANGUAGE_ITALIAN, 'Italian'], ["日本語 (にほんご) (%s)", wxLANGUAGE_JAPANESE, 'Japanese'], ["Magyar (%s)", wxLANGUAGE_HUNGARIAN, 'Hungarian'], ["Nederlands (%s)", wxLANGUAGE_DUTCH, 'Dutch'], ["Polski (%s)", wxLANGUAGE_POLISH, 'Polish'], ["Português Brasileiro (%s)", wxLANGUAGE_PORTUGUESE_BRAZILIAN, 'Portuguese Brazil'], ["Português Portugal (%s)", wxLANGUAGE_PORTUGUESE, 'Portuguese Portugal'], ["Русский (%s)", wxLANGUAGE_RUSSIAN, 'Russian'], ["Slovenčina (%s)", wxLANGUAGE_SLOVAK, 'Slovak'], ] ); # some languages may be unavailable due to system configuration. $self->filter_available_languages; $self->current_language( $language||$self->{current_language}||Wx::Locale::GetSystemLanguage() ); undef $locale; $locale = Wx::Locale->new( $self->current_language ); $locale->AddCatalogLookupPathPrefix( File::Spec->catfile($self->root_dir, $self->locale_dir) ); if(!$locale->AddCatalog( 'pLoader.mo' )){ Wx::LogMessage gettext("Cannot find translation catalog files for %s. Use default language"), $locale->GetCanonicalName(); } $self->locale($locale); } sub filter_available_languages { my ( $self ) = @_; # check if the locale can be set and the translation catalog available $self->available_languages( [ grep {$_} map{ # a locale may be unavailable due to system limitations ( ex: chinese, japanese when language pack are not installed ) if(Wx::Locale::IsAvailable($_->[1])){ my $locale = Wx::Locale->new($_->[1]); $locale->AddCatalogLookupPathPrefix( File::Spec->catfile($self->root_dir, $self->locale_dir) ); $_ if $locale->AddCatalog('pLoader'); } } @{$self->languages} ] ); } sub init_localized_properties { my ( $self ) = @_; $self->colors( ['Black', 'White'] ); # We need to translate back to english when we store properties $self->eng_colors( { map { gettext($_) => $_ } @{$self->colors} } ); $self->positions( [ 'Top', 'Left', 'Right', 'Bottom', 'Top left', 'Top right', 'Bottom left', 'Bottom right', 'Center', ] ); $self->eng_positions( { map { gettext($_) => $_ } @{$self->positions} } ); $self->upload_hd( [ 'No', 'Yes, use HD resized of the original photo', 'Yes, use a copy of the original photo', ] ); $self->eng_upload_hd( { map { gettext($_) => $_ } @{$self->upload_hd} } ); $self->caption_patterns( [ 'None', 'File name', 'File path and name', 'Caption', 'Caption + rank number', 'Rank number + caption', 'Caption + create date chrono', 'Create date chrono + caption', 'Create date chrono + rank', 'Rank + create date chrono', ] ); $self->eng_caption_patterns( { map { gettext($_) => $_ } @{$self->caption_patterns} } ); # hard coded because the piwigo api to read custom privacy level is not yet available $self->privacy_level( [ 'everybody', 'contacts', 'friends', 'family', 'admins' ] ); $self->localized_msg( { map { $_ => gettext($_) } ( 'cancelled', 'sending files', 'checking files', 'files checked', 'transfered', 'updating', 'updating files', 'files updated', 'updating properties', 'properties updated', 'prepared, waiting for transfer', 'preparing web size', 'web size prepared', 'preparing high', 'high prepared', 'start sending', 'sending', ) } ); print Dumper $self->localized_msg; } # display privacy level list in a pyramid way : # ['everybody', 'contacts', friends, family, admins] -> [everybody, 'contacts, friends, family, admins', 'friends, family, admins', 'family, admins', 'admins only' ] sub privacy_level_choices{ my ( $self ) = @_; my $pl = $self->privacy_level; my $n = scalar @$pl - 1; my $list = [ gettext($pl->[0]) ]; my $i=0; while(++$i<$n){ push @$list, join( ', ', map{ gettext($_) } @$pl[$i..$n] ); } push @$list, gettext($pl->[$n]); $list; } sub init_preferences { my ( $self ) = @_; $self->preferences_version('0.1'); my $stored = $self->retrieve_from_file( $self->preferences_file, $self->preferences_version ); $self->preferences( $stored ? Uploader::Preferences->new( $stored ): Uploader::Preferences->new( $self->default_preferences ) ); } sub retrieve_from_file { my ( $self, $file, $version ) = @_; my $stored; if( -e $file ){ eval { $stored = retrieve $file; }; if($@){ warn( "An error has occured. Can not read %s\n%s", $file, $@ ); undef $stored; } # should have a valid images else{ undef $stored unless $version eq $stored->{version}; } } $stored; } sub default_preferences { my ( $self ) = @_ ; # must be read in a ini file $self->user_def_preferences( {} ); my $preferences = { version => $self->preferences_version, storable_file => $self->preferences_file, hd_filter => $self->user_def_preferences->{hd_filter}||'Lanczos', hd_blur => $self->user_def_preferences->{hd_blur}||0.9, hd_quality => $self->user_def_preferences->{hd_quality}||95, hd_w => $self->user_def_preferences->{hd_w}||1600, hd_h => $self->user_def_preferences->{hd_h}||1200, hd_interlace => $self->user_def_preferences->{hd_interlace}||'Line', thumb_size => $self->user_def_preferences->{thumbnail_size}||120, wx_thumb_size => $self->user_def_preferences->{wx_thumbnail_size}||100, resize_w => $self->user_def_preferences->{resize_w}||800, resize_h => $self->user_def_preferences->{resize_h}||600, type => 'jpg', filter => $self->user_def_preferences->{resize_filter}||'Lanczos', blur => $self->user_def_preferences->{resize_blur}||0.9, quality => $self->user_def_preferences->{resize_quality}||95, wx_quality => $self->user_def_preferences->{wx_thumbnail_quality}||90, th_quality => $self->user_def_preferences->{thumbnail_quality}||90, auto_rotate => $self->user_def_preferences->{auto_rotate}||1, upload_hd => $self->user_def_preferences->{upload_hd}||'No', remove_uploaded_from_selection => $self->user_def_preferences->{remove_uploaded_from_selection}||1, interlace => $self->user_def_preferences->{resize_interlace}||'Line', create_resized => $self->user_def_preferences->{create_resized}||1, prefix => 'TN', default_caption_pattern => $self->user_def_preferences->{default_caption_pattern}||'File name', default_caption => $self->user_def_preferences->{default_caption}||gettext('Photo '), watermark_text => $self->user_def_preferences->{watermark_text}||gettext("my watermark"), watermark_text_size => $self->user_def_preferences->{watermark_text_size}||12, watermark_position => $self->user_def_preferences->{watermark_position}||'Center', watermark_y => $self->user_def_preferences->{watermark_y}||10, watermark_x => $self->user_def_preferences->{watermark_x}||10, watermark_color => $self->user_def_preferences->{watermark_color}||'White', reupload_action_files => 1, reupload_action_properties => 2, reupload_action_properties_m => 1, display_mode => $self->user_def_preferences->{display_mode}||'Thumbnail and caption', chunk_size => $self->user_def_preferences->{chunk_size}||500000, }; return $preferences; } sub init_resize_manager { my ( $self ) = @_; $self->resize_start_event( Wx::NewEventType ); $self->resize_manager( Uploader::ResizeManager->new({ thumb_dir => $self->thumb_dir, wx_thumb_dir => $self->wx_thumb_dir, resized_dir => $self->resized_dir, preferences => sub { $self->preferences(@_) }, progress_event => $resize_progress_event, done_event => $resize_done_event, batch_end_event => $resize_batch_end_event, event_handler => $self, localized_msg => $self->localized_msg, }) ); $self->init_resize_batch_end_event_handler; $self->init_resize_done_event_handler; $self->init_resize_progress_event_handler; } sub init_resize_batch_end_event_handler { my ( $self ) = @_; Wx::Event::EVT_COMMAND( $self, -1, $resize_batch_end_event, sub { my ( $handler, $event ) = @_; my $msg : shared = shared_clone($event->GetData); # add the batch end message to the queue $self->transfer_manager->add_images([ $msg ]); } ); } sub init_resize_done_event_handler { my ( $self ) = @_; Wx::Event::EVT_COMMAND( $self, -1, $resize_done_event, sub { my ( $handler, $event ) = @_; my $image : shared = shared_clone($event->GetData); $handler->on_image_progress($image); # image is prepared, send to transfer queue $self->transfer_manager->add_images([ $image ]); } ); } sub init_resize_progress_event_handler { my ( $self ) = @_; Wx::Event::EVT_COMMAND( $self, -1, $resize_progress_event, sub { my ( $handler, $event ) = @_; my $data : shared = shared_clone($event->GetData); $handler->on_image_progress($data); } ); } sub on_batch_end { my ( $self, $image ) = @_; Wx::PostEvent( $self->frame, Wx::PlThreadEvent->new( -1, $self->batch_end_event, $image ) ); } sub on_image_progress { my ( $self, $image ) = @_; Wx::PostEvent( $self->frame, Wx::PlThreadEvent->new( -1, $self->image_progress_event, $image ) ); } sub on_image_done { my ( $self, $image ) = @_; Wx::PostEvent( $self->frame, Wx::PlThreadEvent->new( -1, $self->image_done_event, $image ) ); } sub init_images { my ( $self ) = @_; $self->images_version('0.1'); my $stored = $self->retrieve_from_file( $self->images_file, $self->images_version, ); $self->images( $stored ? Uploader::Images->new( $stored ): Uploader::Images->new( { storable_file => $self->images_file, version => $self->images_version, } ) ); $self->images->eng_caption_patterns( $self->eng_caption_patterns ); $self->images->create_wx_thumbnail_cbk( sub { $self->resize_manager->create_wx_thumbnail(@_) } ); $self->images->default_caption_cbk( sub { $self->preferences->default_caption(@_) } ); $self->images->default_caption_pattern_cbk( sub { $self->preferences->default_caption_pattern(@_) } ); $self->images->set_current_image(-1); } sub is_single_instance_server { my ( $self ) = @_; if($self->is_single_instance_running){ printf("connect_to_single_instance_server\n"); $self->connect_to_single_instance_server; printf("connected to single_instance_server\n"); return 0; } else{ printf("start_single_instance_server\n"); $self->start_single_instance_server; printf("single_instance_server started\n"); return 1; } } sub is_single_instance_running { my ( $self ) = @_; $self->{_instance_checker}->IsAnotherRunning; } my $single_instance_port = 9101; sub connect_to_single_instance_server { my ( $self ) = @_; my $socket = IO::Socket::INET->new( PeerAddr => '127.0.0.1', PeerPort => $single_instance_port, Proto => 'tcp', Type => IO::Socket::SOCK_STREAM(), ); # if connection successful, server sends pid if ($socket) { my $pid = ''; my $read = $socket->sysread( $pid, 10 ); if ( defined $read and $read == 10 ) { my $files = join(',', @{$self->argv}); printf("send to server %s\n", $files); $socket->print("open $files\n"); #$socket->print("focus\n"); $socket->close; return 0; } } } sub start_single_instance_server { my ( $self ) =@_; $self->{_single_instance_server} = Wx::SocketServer->new( '127.0.0.1' => $single_instance_port, Wx::wxSOCKET_NOWAIT Wx::wxSOCKET_REUSEADDR, ); if( $self->{_single_instance_server}->Ok ) { Wx::Event::EVT_SOCKET_CONNECTION( $self, $self->{_single_instance_server}, sub { $self->single_instance_connect( $_[0] ); } ); } else { delete $self->{_single_instance_server}; warn( Wx::gettext("Failed to create single instance server") ); } return 1; } sub single_instance_connect { my $self = shift; my $server = shift; my $client = $server->Accept(0); # Before we start accepting input, # send the client our process ID. $client->Write( sprintf( '% 10s', $$ ), 10 ); # Set up the socket hooks Wx::Event::EVT_SOCKET_INPUT( $self, $client, sub { # Accept the data and stream commands my $command = ''; my $buffer = ''; while ( $_[0]->Read( $buffer, 128 ) ) { $command .= $buffer; while ( $command =~ s/^(.*?)[\012\015]+//s ) { $_[1]->single_instance_command( "$1", $_[0] ); } } return 1; } ); Wx::Event::EVT_SOCKET_LOST( $self, $client, sub { $_[0]->Destroy; } ); return 1; } sub single_instance_command { my( $self, $line, $socket ) = @_; return 1 unless defined $line && length $line; # ignore the line if command isn't plain ascii return 1 unless $line =~ s/^(\S+)\s*//s; if ( $1 eq 'open' ) { if ( -f $line ) { printf("received from incoming connection %s\n", $line); $self->images->add_images( [ grep { -f $_} split(/,/, $line) ] ); } } else { warn("Unsupported command '$1'"); } return 1; } sub stop_single_instance_server { my ( $self ) =@_; if(exists $self->{_single_instance_server}){ $self->{_single_instance_server}->Destroy; delete $self->{_single_instance_server}; } } sub default_app { my ( $self ) = @_ ; my $app = { thumb_dir => $self->thumb_dir, wx_thumb_dir => $self->wx_thumb_dir, resized_dir => $self->resized_dir, userdata_dir => $self->userdata_dir, version => $self->version, storable_file => $self->app_file, }; $app; } sub connect_or_exit { my ( $self ) = @_; my $not_exit = $self->login(); $self->connection->Store; # user pressed OK if($not_exit){ if( $self->use_connected ){ while( $not_exit and $self->not_connected ){ $not_exit = $self->login; last if $self->use_offline; } $self->init_transfer_manager; } } else { $self->resize_manager->stop; $self->stop_single_instance_server; } $not_exit; } sub login { my ( $self ) = @_; $self->init_connection; $self->login_dlg( Uploader::GUI::LoginDlg->new( { title => gettext("Piwigo login"), site_url => sub { $self->connection->site_url(@_) }, site_username => sub { $self->connection->site_username(@_) }, site_password => sub { $self->connection->site_password(@_) }, use_offline => sub { $self->connection->use_offline(@_) }, } ) ) unless $self->login_dlg; my $icon = Wx::Icon->new(); $icon->LoadFile( $self->resource_path('favicon.ico'), wxBITMAP_TYPE_ICO ); $self->login_dlg->SetIcon($icon); my $rval = $self->login_dlg->ShowModal(); $self->login_dlg->Show(0); $self->init_branding; if ($self->connection->site_url !~ /^http:/){ $self->connection->site_url( sprintf( "http://%s", $self->connection->site_url ) ); } $self->pwg( # get these parameters from dialog or from file Uploader::PWG->new( { site_url => $self->connection->site_url, site_username => $self->connection->site_username, site_password => $self->connection->site_password, http_username => $self->connection->http_username, http_password => $self->connection->http_password, branding => $self->branding, use_offline => $self->use_offline, version => $self->version, localized_msg => $self->localized_msg, } ) ); $rval; } # helper method to get the full path for a resource sub resource_path{ my ( $self, $file ) = @_; File::Spec->catfile($self->root_dir, $self->resource_dir, $file); } sub bin_path{ my ( $self, $file ) = @_; File::Spec->catfile($self->root_dir, $self->bin_dir, $file); } sub locale_path{ my ( $self, $file ) = @_; File::Spec->catfile($self->root_dir, $self->locale_dir, $file); } sub locale_catalog_path{ my ( $self, $file ) = @_; File::Spec->catfile($self->root_dir, $self->locale_dir, $self->locale->GetCanonicalName, $file); } # some labels differ with branding ( piwigo.com or piwigo.org ) sub init_branding { my ( $self ) =@_; if( $self->connection->site_url =~ /\.piwigo\.com/ ){ $self->branding( { category => gettext("album"), Category => gettext("Album"), categories => gettext("albums"), Categories => gettext("Albums"), 'Add new category' => gettext("Add new album"), 'Category name' => gettext("Album name :"), 'New category' => gettext("New album"), 'What is the destination category?' => gettext("What is the destination album?") } ); } else{ $self->branding( { category => gettext("categorie"), Category => gettext("Categorie"), categories => gettext("categories"), Categories => gettext("Categories"), 'Add new category' => gettext("Add new category"), 'Category name' => gettext("Category name :"), 'New category' => gettext("New category"), 'What is the destination category?' => gettext("What is the destination category?") } ); } } sub use_connected { my ( $self ) = @_; !$self->use_offline } sub not_connected { my ( $self ) = @_; !$self->is_connected; } sub is_connected { my ( $self ) = @_; my $_is_connected; if($self->pwg->login_result->{stat} eq 'ok'){ $_is_connected = 1; } else{ Wx::MessageBox( sprintf( "%s\n\n%s %s %s", $self->pwg->login_result->{message}, gettext("Connection to"), $self->connection->site_url, gettext("failed"), ), gettext("Piwigo login error"), wxOK | wxICON_EXCLAMATION, ); } $_is_connected; } sub init_transfer_manager { my ( $self ) = @_; $self->check_upload; $self->transfer_manager( Uploader::TransferManager->new({ pwg => $self->pwg, progress_event => $transfer_progress_event, done_event => $transfer_done_event, event_handler => $self, batch_end_event => $transfer_batch_end_event, localized_msg => $self->localized_msg, }) ); $self->image_progress_event( Wx::NewEventType ); $self->image_done_event( Wx::NewEventType ); $self->batch_end_event( Wx::NewEventType ); $self->init_transfer_batch_end_event_handler; $self->init_transfer_done_event_handler; $self->init_transfer_progress_event_handler; } sub check_upload { my ( $self ) = @_; my $err_msg = $self->pwg->check_upload; $err_msg = gettext("Your user account is not granted to upload photos") if 'Access denied' eq $err_msg; #Wx::LogMessage("%s", $err_msg) if $err_msg; Wx::MessageBox($err_msg, "", wxOK | wxICON_ERROR) if $err_msg; $err_msg; } sub init_transfer_batch_end_event_handler { my ( $self ) = @_; Wx::Event::EVT_COMMAND( $self, -1, $transfer_batch_end_event, sub { my ( $handler, $event ) = @_; my $data = $event->GetData; $handler->on_batch_end($data); } ); } sub init_transfer_done_event_handler { my ( $self ) = @_; Wx::Event::EVT_COMMAND( $self, -1, $transfer_done_event, sub { my ( $handler, $event ) = @_; my $data = $event->GetData; $handler->on_image_done($data); } ); } sub init_transfer_progress_event_handler { my ( $self ) = @_; Wx::Event::EVT_COMMAND( $self, -1, $transfer_progress_event, sub { my ( $handler, $event ) = @_; my $data : shared = shared_clone($event->GetData); $handler->on_image_progress($data); } ); } sub start_resize { my( $self, $all_images ) = @_; # we need to copy data from object to use another thread my $images = $self->images->get_images( $self->preferences->get_data, $self->transfer_manager->destination_category, $all_images ); push @$images, { event => "BATCH_END" }; $self->resize_manager->add_images($images); Wx::PostEvent( $self->frame, Wx::PlThreadEvent->new( -1, $self->resize_start_event, shared_clone($images) ) ); $images; } sub cancel_resize { my( $self ) = @_; my $cancelled; if( $self->resize_manager->pending and wxYES == Wx::MessageBox( sprintf( "Cancel %s resize pending job(s) ?", $self->resize_manager->pending, ), "pLoader job processing", wxYES_NO|wxNO_DEFAULT| wxICON_QUESTION, ) ){ $cancelled = 1; $self->resize_manager->cancel; } $cancelled; } sub cancel_transfer { my( $self ) = @_; my $cancelled = 1; if( $self->transfer_manager->pending ){ if( wxYES == Wx::MessageBox( sprintf( "Cancel %s transfer pending job(s) ?", $self->transfer_manager->pending, ), "pLoader job processing", wxYES_NO|wxNO_DEFAULT| wxICON_QUESTION, ) ) { $self->transfer_manager->cancel; } else{ $cancelled = 0; } } $cancelled; } sub SetFrame { my ( $self, $frame ) = @_; my $url = $self->connection->site_url; if($self->use_offline){ $url = gettext("Work Offline"); } $self->frame($frame); my $icon = Wx::Icon->new(); $icon->LoadFile( File::Spec->catfile( $self->root_dir, $self->resource_dir, 'favicon.ico' ), wxBITMAP_TYPE_ICO ); $self->frame->SetIcon($icon); } sub GetWxBitmapType { my ( $self, $type ) = @_; $self->{IMGTYPE}->{$type}; } 1;