source: extensions/pLoader/trunk/src/Uploader/GUI/App.pm @ 6538

Last change on this file since 6538 was 6538, checked in by ronosman, 14 years ago

Ability to clear progress list. Only available when no batch is running. The cancel processing is available when a batch is running.

File size: 34.1 KB
Line 
1package Uploader::GUI::App;
2use threads;
3use threads::shared;
4use Thread::Queue;
5use strict;
6use base qw/Wx::App Class::Accessor::Fast/;
7use Wx qw/
8    wxBITMAP_TYPE_GIF
9    wxBITMAP_TYPE_ICO
10    wxBITMAP_TYPE_BMP
11    wxBITMAP_TYPE_PNG
12    wxBITMAP_TYPE_JPEG
13    wxIMAGE_QUALITY_HIGH
14    wxSPLASH_CENTRE_ON_SCREEN
15    wxSPLASH_TIMEOUT
16    wxDefaultPosition
17    wxDefaultSize
18    wxSIMPLE_BORDER
19    wxFRAME_TOOL_WINDOW
20    wxFRAME_NO_TASKBAR wxSTAY_ON_TOP
21    wxWHITE
22    wxICON_EXCLAMATION
23    wxICON_QUESTION
24    wxOK
25    wxYES
26    wxYES_NO
27    wxNO_DEFAULT
28    wxICON_ERROR
29    wxLANGUAGE_CHINESE_SIMPLIFIED
30    wxLANGUAGE_CZECH
31    wxLANGUAGE_DANISH
32    wxLANGUAGE_DUTCH
33    wxLANGUAGE_ENGLISH
34    wxLANGUAGE_FRENCH
35    wxLANGUAGE_GERMAN
36    wxLANGUAGE_HUNGARIAN
37    wxLANGUAGE_ITALIAN
38    wxLANGUAGE_JAPANESE
39    wxLANGUAGE_POLISH
40    wxLANGUAGE_PORTUGUESE
41    wxLANGUAGE_PORTUGUESE_BRAZILIAN
42    wxLANGUAGE_RUSSIAN
43    wxLANGUAGE_SLOVAK
44    wxLANGUAGE_SPANISH
45/;
46use Wx::Locale qw/:default/;
47use File::HomeDir;
48use Uploader::PWG;
49use Uploader::Images;
50use Uploader::Connection;
51use Uploader::Preferences;
52use Uploader::ResizeManager;
53use Uploader::TransferManager;
54use Uploader::GUI::LoginDlg;
55use Storable;
56use utf8;
57use Data::Dumper;
58use IO::Socket;
59use Wx::Socket;
60
61my $received_filename_event : shared = Wx::NewEventType;
62my $transfer_progress_event : shared = Wx::NewEventType;
63my $transfer_done_event : shared = Wx::NewEventType;
64my $transfer_batch_end_event : shared = Wx::NewEventType;
65my $resize_done_event : shared = Wx::NewEventType;
66my $resize_progress_event : shared = Wx::NewEventType;
67my $resize_batch_end_event : shared = Wx::NewEventType;
68
69my $image_progress_event = Wx::NewEventType;
70
71$|=1;
72
73
74my @app_properties = qw/
75    version
76    frame
77    argv
78    images
79    images_version
80    preferences
81    preferences_version
82    user_def_preferences
83    privacy_level
84    upload_hd
85    resize_manager
86    transfer_manager
87/;
88
89
90my @connection_properties = qw/
91    connection_version
92    connection
93    login_dlg
94    branding
95    use_offline
96    use_connected
97    pwg
98/;
99
100
101my @file_properties = qw/
102    bin_dir
103    resource_dir
104    thumb_dir
105    resized_dir
106    wx_thumb_dir
107    userdata_dir
108    root_dir
109    locale_dir
110    preferences_file
111    connection_file
112    images_file
113    app_file
114    instance_checker_file
115/;
116
117
118my @localized_properties = qw/
119    colors
120    positions
121    upload_hd
122    caption_patterns
123/;
124
125
126my @language_properties = qw/
127    current_language
128    locale
129    languages
130    available_languages
131    eng_colors
132    eng_positions
133    eng_upload_hd
134    eng_caption_patterns
135/;
136
137
138my @custom_events = qw/
139    resize_start_event
140    batch_end_event
141    image_progress_event
142/;
143
144__PACKAGE__->mk_accessors(@app_properties);
145__PACKAGE__->mk_accessors(@file_properties);
146__PACKAGE__->mk_accessors(@connection_properties);
147__PACKAGE__->mk_accessors(@localized_properties);
148__PACKAGE__->mk_accessors(@language_properties);
149__PACKAGE__->mk_accessors(@custom_events);
150
151my $_params;
152
153sub new {
154    my ( $self, $params ) = @_;
155
156    $_params = $params;
157
158    $self->SUPER::new();
159
160}
161
162
163sub OnInit {
164    my( $self ) = @_;
165
166    $self->init_properties_from_params;
167    $self->init_application_properties;
168    $self->init_single_instance_checker;
169    $self->init_file_properties;
170    $self->init_locale;
171    $self->init_localized_properties;
172    $self->init_preferences;
173    $self->init_resize_manager;
174    $self->init_images;
175
176    return 0 unless $self->is_single_instance_server;
177
178    $self->connect_or_exit;
179
180}
181
182
183sub OnExit {
184    my( $self ) = @_;
185
186    unlink $self->instance_checker_file
187        if -e $self->instance_checker_file;
188    $self->store_all;
189
190}
191
192
193sub store_all {
194    my( $self ) = @_;
195
196    $self->connection->Store;;
197    $self->images->Store;
198    $self->preferences->Store;
199
200}
201
202
203sub reset_add_rank {
204    my ( $self ) = @_;
205
206    $self->images->reset_add_rank;
207}
208
209
210sub cancel_all {
211    my ( $self ) = @_;
212
213    $self->cancel_transfer if $self->cancel_resize;
214}
215
216
217sub stop_all {
218    my( $self ) = @_;
219
220    $self->resize_manager->stop;
221    $self->transfer_manager->stop;
222    $self->stop_single_instance_server;
223    $self->login_dlg->Destroy;   
224
225
226
227}
228
229
230sub init_properties_from_params {
231    my ( $self ) = @_;
232
233    map {
234        $self->$_(
235            $_params->{$_}
236        )
237    } keys %$_params;
238
239}
240
241
242sub init_application_properties {
243    my ( $self ) = @_;
244
245    $self->version(
246        '1.7'
247    );
248   
249
250    Wx::InitAllImageHandlers();
251
252    $self->{IMGTYPE} = {
253        'jpg' => wxBITMAP_TYPE_JPEG,
254        'gif' => wxBITMAP_TYPE_GIF,
255        'png' => wxBITMAP_TYPE_PNG,
256    };
257
258    my $applicationName = "pLoader" ;
259    $self->SetAppName( $applicationName );
260    $self->SetVendorName( "Piwigo Team" );
261
262
263}
264
265
266sub init_single_instance_checker {
267    my ( $self ) = @_;
268
269
270    my $id_user=$ENV{USERNAME} || $ENV{USER} || $ENV{LOGNAME};
271    # must save the object
272    $self->{_instance_checker} = Wx::SingleInstanceChecker->new;
273    my $pid = sprintf(
274        "%s-%s",
275        $self->GetAppName,
276        $id_user,
277    );
278    $self->{_instance_checker}->Create(
279        $pid
280    );
281
282    $self->instance_checker_file(
283        File::Spec->canonpath(
284            File::Spec->catfile(
285                File::HomeDir->my_home(),
286                $pid
287            )
288        )
289    );
290
291}
292
293
294sub init_file_properties {
295    my ( $self ) = @_;
296   
297    my $applicationName = $self->GetAppName ;
298    my $userdatadir = File::Spec->canonpath(
299        File::Spec->catfile(
300            File::HomeDir->my_data(), 
301            $applicationName
302        )
303    );
304
305    if(! -d $userdatadir){
306        if(! mkdir $userdatadir){
307            Wx::MessageBox( 
308                sprintf(
309                    "%s directory creation failed",
310                    $userdatadir,
311                ),
312                "pLoader working directory creation error",
313                wxOK | wxICON_EXCLAMATION, 
314            );
315
316            $userdatadir = File::Spec->canonpath(
317                File::Spec->catfile(
318                    File::Spec->tmpdir(), 
319                    $applicationName
320                )
321            );
322            mkdir $userdatadir;
323        }   
324    }
325
326    $self->userdata_dir($userdatadir);
327
328    $self->app_file(
329        $self->userdata_filepath("$applicationName.dat")
330    );
331
332    $self->preferences_file(
333        $self->userdata_filepath("preferences.dat")
334    );
335
336    $self->connection_file(
337        $self->userdata_filepath("connection.dat")
338    );
339
340    $self->images_file(
341        $self->userdata_filepath("images.dat")
342    );
343   
344    my $thumbdir = $self->userdata_filepath('thumbnails');
345    mkdir $thumbdir unless -d $thumbdir ;
346    $self->thumb_dir($thumbdir);
347
348    my $wxthumbdir = $self->userdata_filepath('wxthumbnails');
349    mkdir $wxthumbdir unless -d $wxthumbdir ;
350    $self->wx_thumb_dir($wxthumbdir);
351
352
353    my $resizedir = $self->userdata_filepath('resize');
354    mkdir $resizedir unless -d $resizedir ;
355    $self->resized_dir($resizedir);
356}
357
358
359sub userdata_filepath {
360    my ( $self, $filename ) = @_;
361
362    File::Spec->catfile(
363        $self->userdata_dir,
364        $filename
365    );
366}
367
368
369sub read_params {
370    my( $self, $file ) = @_ ;
371
372 
373    my $expr_params ;
374    eval { $expr_params = read_file( $file ); } ;
375   
376    my $paramValues = [] ;
377    if($expr_params){
378        my $expr = '$paramValues = ' ;
379        $expr .=  "$expr_params ; " ;
380        eval $expr ;
381    }
382   
383    return unless 'ARRAY' eq ref $paramValues ;
384   
385    if(scalar(@$paramValues )){
386        my $params = $paramValues->[0] ;
387        $self->set_key_values($params);
388    }
389
390}
391
392
393sub set_key_values {
394    my ( $self, $params )= @_;   
395
396    foreach( keys %$params ) {
397        $self->{$_} = $params->{$_} ;
398    }
399}
400
401
402sub init_connection {
403    my ( $self ) = @_;
404
405    $self->connection_version('0.1');
406
407    my $stored = $self->retrieve_from_file(
408        $self->connection_file,
409        $self->connection_version
410    );
411
412    $self->connection(
413        $stored ?
414        Uploader::Connection->new(
415            $stored
416        ):
417        Uploader::Connection->new(
418            $self->default_connection
419        )
420    );
421
422}
423
424
425sub default_connection {
426    my ( $self ) = @_;
427
428    my $connection = {
429        version          => $self->connection_version,
430        storable_file    => $self->connection_file,
431    };
432
433    return $connection;
434}
435
436my $locale;
437sub init_locale {
438    my ( $self, $language ) = @_;
439
440    $self->languages(
441      [
442             ["中文 (%s)", wxLANGUAGE_CHINESE_SIMPLIFIED, 'Chinese simplified'],   
443             ["Česky (%s)", wxLANGUAGE_CZECH, 'Czech'],   
444             ["Dansk (%s)", wxLANGUAGE_DANISH, 'Danish'],   
445             ["Deutsch (%s)", wxLANGUAGE_GERMAN, 'German'],   
446             ["English (%s)", wxLANGUAGE_ENGLISH, 'English'],   
447             ["Español (%s)", wxLANGUAGE_SPANISH, 'Spanish'],   
448             ["Français (%s)", wxLANGUAGE_FRENCH, 'French'],   
449             ["Italiano (%s)", wxLANGUAGE_ITALIAN, 'Italian'],   
450             ["日本語 (にほんご) (%s)", wxLANGUAGE_JAPANESE, 'Japanese'],   
451             ["Magyar (%s)", wxLANGUAGE_HUNGARIAN, 'Hungarian'],
452             ["Nederlands (%s)", wxLANGUAGE_DUTCH, 'Dutch'],   
453             ["Polski (%s)", wxLANGUAGE_POLISH, 'Polish'],   
454             ["Português Brasileiro (%s)", wxLANGUAGE_PORTUGUESE_BRAZILIAN, 'Portuguese Brazil'],   
455             ["Português Portugal (%s)", wxLANGUAGE_PORTUGUESE, 'Portuguese Portugal'],   
456             ["Русский (%s)", wxLANGUAGE_RUSSIAN, 'Russian'],
457             ["Slovenčina (%s)", wxLANGUAGE_SLOVAK, 'Slovak'],
458      ]
459    );
460    # some languages may be unavailable due to system configuration.
461    $self->filter_available_languages;
462
463    $self->current_language(
464        $language||$self->{current_language}||Wx::Locale::GetSystemLanguage()
465    );
466
467    undef $locale;
468    $locale = Wx::Locale->new(
469        $self->current_language
470    );
471    $locale->AddCatalogLookupPathPrefix(
472        File::Spec->catfile($self->root_dir, $self->locale_dir)
473    );
474    if(!$locale->AddCatalog( 'pLoader.mo' )){
475        Wx::LogMessage gettext("Cannot find translation catalog files for %s. Use default language"), $locale->GetCanonicalName();
476    }
477    $self->locale($locale);   
478}
479
480
481sub filter_available_languages {
482    my ( $self ) = @_;
483
484    # check if the locale can be set and the translation catalog available
485    $self->available_languages(
486        [
487            grep {$_} 
488            map{
489                #  a locale may be unavailable due to system limitations ( ex: chinese, japanese when language pack are not installed )
490                if(Wx::Locale::IsAvailable($_->[1])){
491                    my $locale = Wx::Locale->new($_->[1]);
492                    $locale->AddCatalogLookupPathPrefix(
493                        File::Spec->catfile($self->root_dir, $self->locale_dir)
494                    );
495                    $_ if $locale->AddCatalog('pLoader');
496                }
497            }
498            @{$self->languages}
499        ]
500    );
501}
502
503
504sub init_localized_properties {
505    my ( $self ) = @_;
506
507    $self->colors(
508        ['Black', 'White']
509    );
510
511    # We need to translate back to english when we store properties
512    $self->eng_colors(
513        {
514            map { gettext($_) => $_ } @{$self->colors} 
515        }
516    );
517
518    $self->positions(
519        [
520            'Top',
521            'Left',
522            'Right',
523            'Bottom',
524            'Top left',
525            'Top right',
526            'Bottom left',
527            'Bottom right',
528            'Center',
529        ]
530    );
531
532    $self->eng_positions(
533        { 
534             map { gettext($_) => $_ } @{$self->positions} 
535        }
536    );
537
538    $self->upload_hd(
539        [
540            'No',
541            'Yes, use HD resized of the original photo',
542            'Yes, use a copy of the original photo',
543        ]
544    );
545
546    $self->eng_upload_hd(
547        {
548             map { gettext($_) => $_ } @{$self->upload_hd} 
549        }
550    );
551   
552
553    $self->caption_patterns(
554        [
555             'None',
556             'File name',
557             'File path and name',
558             'Caption',
559             'Caption + rank number',
560             'Rank number + caption',
561             'Caption + create date chrono',
562             'Create date chrono + caption',
563             'Create date chrono + rank',
564             'Rank + create date chrono',
565        ]
566    );
567
568    $self->eng_caption_patterns(
569        {
570             map { gettext($_) => $_ } @{$self->caption_patterns} 
571        }
572    );
573   
574    # hard coded because the piwigo api to read custom privacy level is not yet available
575    $self->privacy_level(
576        [
577            'everybody',
578            'contacts',
579            'friends',
580            'family',
581            'admins'
582        ]
583    );
584
585}
586
587
588# display privacy level list in a pyramid way :
589# ['everybody', 'contacts', friends, family, admins] -> [everybody, 'contacts, friends, family, admins', 'friends, family, admins', 'family, admins', 'admins only' ]
590sub privacy_level_choices{
591    my ( $self ) = @_;
592
593    my $pl = $self->privacy_level;   
594    my $n = scalar @$pl - 1;
595    my $list = [ gettext($pl->[0]) ];
596    my $i=0;
597    while(++$i<$n){   
598        push @$list, join(
599            ', ', 
600            map{ gettext($_) }
601            @$pl[$i..$n] 
602        );
603    }
604    push @$list, gettext($pl->[$n]);
605   
606    $list;
607}
608
609
610sub init_preferences {
611    my ( $self ) = @_;   
612
613    $self->preferences_version('0.1');
614
615    my $stored = $self->retrieve_from_file(
616        $self->preferences_file,
617        $self->preferences_version
618    );
619
620    $self->preferences(
621        $stored ?
622        Uploader::Preferences->new(
623            $stored
624        ):
625        Uploader::Preferences->new(
626            $self->default_preferences
627        )
628    );
629}
630
631
632sub retrieve_from_file {
633    my ( $self, $file, $version ) = @_;
634
635
636    my $stored;
637   
638    if( -e $file ){
639        eval {
640            $stored = retrieve $file;
641        };
642        if($@){
643            warn(
644                "An error has occured. Can not read %s\n%s",
645                $file, 
646                $@
647            );
648            undef $stored;
649        }
650        # should have a valid images
651        else{
652            undef $stored unless $version eq $stored->{version};
653        }
654    }
655
656    $stored;
657}
658
659
660sub default_preferences {
661    my ( $self ) = @_ ;
662
663    # must be read in a ini file
664    $self->user_def_preferences(
665        {}
666    );
667
668    my $preferences = {
669        version => $self->preferences_version,
670        storable_file    => $self->preferences_file,
671        hd_filter        => $self->user_def_preferences->{hd_filter}||'Lanczos',
672        hd_blur          => $self->user_def_preferences->{hd_blur}||0.9,
673        hd_quality       => $self->user_def_preferences->{hd_quality}||95,
674        hd_w             => $self->user_def_preferences->{hd_w}||1600,
675        hd_h             => $self->user_def_preferences->{hd_h}||1200,
676        hd_interlace     => $self->user_def_preferences->{hd_interlace}||'Line',
677        thumb_size       => $self->user_def_preferences->{thumbnail_size}||120,
678        wx_thumb_size    => $self->user_def_preferences->{wx_thumbnail_size}||100,
679        resize_w         => $self->user_def_preferences->{resize_w}||800,
680        resize_h         => $self->user_def_preferences->{resize_h}||600,
681        type             => 'jpg',
682        filter           => $self->user_def_preferences->{resize_filter}||'Lanczos',
683        blur             => $self->user_def_preferences->{resize_blur}||0.9,
684        quality          => $self->user_def_preferences->{resize_quality}||95,
685        wx_quality       => $self->user_def_preferences->{wx_thumbnail_quality}||90,
686        th_quality       => $self->user_def_preferences->{thumbnail_quality}||90,
687        auto_rotate      => $self->user_def_preferences->{auto_rotate}||1,
688        upload_hd        => $self->user_def_preferences->{upload_hd}||'No',
689        remove_uploaded_from_selection => $self->user_def_preferences->{remove_uploaded_from_selection}||1,
690        interlace        => $self->user_def_preferences->{resize_interlace}||'Line',
691        create_resized   => $self->user_def_preferences->{create_resized}||1,
692        prefix           => 'TN',
693        default_caption_pattern => $self->user_def_preferences->{default_caption_pattern}||'File name',
694        default_caption  => $self->user_def_preferences->{default_caption}||gettext('Photo '),
695        watermark_text => $self->user_def_preferences->{watermark_text}||gettext("my watermark"),
696        watermark_text_size => $self->user_def_preferences->{watermark_text_size}||12,
697        watermark_position => $self->user_def_preferences->{watermark_position}||'Center',
698        watermark_y => $self->user_def_preferences->{watermark_y}||10,
699        watermark_x => $self->user_def_preferences->{watermark_x}||10,
700        watermark_color => $self->user_def_preferences->{watermark_color}||'White',
701        reupload_action_files => 1,
702        reupload_action_properties => 2,
703        reupload_action_properties_m => 1,
704        display_mode => $self->user_def_preferences->{display_mode}||'Thumbnail and caption',
705        chunk_size   => $self->user_def_preferences->{chunk_size}||500000,
706    };
707
708    return $preferences;
709}
710
711
712sub init_resize_manager {
713    my ( $self ) = @_;
714
715    $self->resize_start_event(
716        Wx::NewEventType
717    );
718
719    $self->resize_manager(
720        Uploader::ResizeManager->new({
721            thumb_dir       => $self->thumb_dir,
722            wx_thumb_dir    => $self->wx_thumb_dir,
723            resized_dir     => $self->resized_dir,
724            preferences     => sub { $self->preferences(@_) },
725            progress_event  => $resize_progress_event,
726            done_event      => $resize_done_event,
727            batch_end_event => $resize_batch_end_event,
728            event_handler   => $self,
729        })
730    );
731
732    $self->init_resize_batch_end_event_handler;
733    $self->init_resize_done_event_handler;
734    $self->init_resize_progress_event_handler;
735}
736
737
738sub init_resize_batch_end_event_handler {
739    my ( $self ) = @_;
740
741    Wx::Event::EVT_COMMAND(
742        $self,
743        -1,
744        $resize_batch_end_event,
745        sub {
746            my ( $handler, $event ) = @_;
747            my $msg : shared = shared_clone($event->GetData);
748            # add the batch end message to the queue
749            $self->transfer_manager->add_images([ $msg ]);
750        } 
751    );
752
753}
754
755
756sub init_resize_done_event_handler {
757    my ( $self ) = @_;
758
759    Wx::Event::EVT_COMMAND(
760        $self,
761        -1,
762        $resize_done_event,
763        sub {
764            my ( $handler, $event ) = @_;
765            my $image : shared = shared_clone($event->GetData);
766            $handler->on_image_progress($image);
767            # image is prepared, send to transfer queue
768            $self->transfer_manager->add_images([ $image ]);
769        } 
770    );
771
772}
773
774
775sub init_resize_progress_event_handler {
776    my ( $self ) = @_;
777
778    Wx::Event::EVT_COMMAND(
779        $self,
780        -1,
781        $resize_progress_event,
782        sub {
783            my ( $handler, $event ) = @_;
784            my $data : shared = shared_clone($event->GetData);
785            $handler->on_image_progress($data);
786        } 
787    );
788
789}
790
791
792sub on_batch_end {
793    my ( $self, $image ) = @_;
794
795    Wx::PostEvent(
796        $self->frame,
797        Wx::PlThreadEvent->new(
798            -1,
799            $self->batch_end_event,
800            $image
801        )
802    );
803}
804
805
806sub on_image_progress {
807    my ( $self, $image ) = @_;
808
809    Wx::PostEvent(
810        $self->frame,
811        Wx::PlThreadEvent->new(
812            -1,
813            $self->image_progress_event,
814            $image
815        )
816    );
817}
818
819
820sub init_images {
821    my ( $self ) = @_;
822
823    $self->images_version('0.1');
824
825    my $stored = $self->retrieve_from_file(
826        $self->images_file,
827        $self->images_version,
828    );
829
830    $self->images(
831        $stored ?
832        Uploader::Images->new(
833            $stored
834        ):
835        Uploader::Images->new(
836            {
837                storable_file => $self->images_file,
838                version       => $self->images_version,
839            }
840        )
841    );
842
843    $self->images->eng_caption_patterns(
844        $self->eng_caption_patterns
845    );
846
847    $self->images->create_wx_thumbnail_cbk(
848        sub { $self->resize_manager->create_wx_thumbnail(@_) }
849    );
850
851    $self->images->default_caption_cbk(
852        sub { $self->preferences->default_caption(@_) }
853    );
854
855    $self->images->default_caption_pattern_cbk(
856        sub { $self->preferences->default_caption_pattern(@_) }
857    );
858
859    $self->images->set_current_image(-1);
860}
861
862
863sub is_single_instance_server {
864    my ( $self ) = @_;
865
866    if($self->is_single_instance_running){
867        printf("connect_to_single_instance_server\n");
868        $self->connect_to_single_instance_server;
869        printf("connected to single_instance_server\n");
870        return 0;
871    }
872    else{
873        printf("start_single_instance_server\n");
874        $self->start_single_instance_server;
875        printf("single_instance_server started\n");
876        return 1;
877    }
878}
879
880
881sub is_single_instance_running {
882    my ( $self ) = @_;
883
884    $self->{_instance_checker}->IsAnotherRunning;
885} 
886
887
888my $single_instance_port = 9101;
889
890
891sub connect_to_single_instance_server {
892    my ( $self ) = @_;
893
894    my $socket = IO::Socket::INET->new(
895        PeerAddr => '127.0.0.1',
896        PeerPort => $single_instance_port,
897        Proto    => 'tcp',
898        Type     => IO::Socket::SOCK_STREAM(),
899    );
900
901    # if connection successful, server sends pid
902    if ($socket) {
903        my $pid = '';
904        my $read = $socket->sysread( $pid, 10 );
905        if ( defined $read and $read == 10 ) {
906            my $files = join(',', @{$self->argv});
907            printf("send to server %s\n", $files);
908            $socket->print("open $files\n");
909            #$socket->print("focus\n");
910            $socket->close;
911            return 0;
912        }
913    }
914}
915
916
917sub start_single_instance_server {
918    my ( $self ) =@_;
919
920    $self->{_single_instance_server} = Wx::SocketServer->new(
921        '127.0.0.1' => $single_instance_port,
922        Wx::wxSOCKET_NOWAIT Wx::wxSOCKET_REUSEADDR,
923    );
924
925    if( $self->{_single_instance_server}->Ok ) {
926        Wx::Event::EVT_SOCKET_CONNECTION(
927            $self,
928            $self->{_single_instance_server},
929            sub {
930                $self->single_instance_connect( $_[0] );
931            }
932        );
933    }
934    else {
935        delete $self->{_single_instance_server};
936        warn( Wx::gettext("Failed to create single instance server") );
937    }
938
939    return 1;
940
941}
942
943
944sub single_instance_connect {
945    my $self   = shift;
946    my $server = shift;
947    my $client = $server->Accept(0);
948
949    # Before we start accepting input,
950    # send the client our process ID.
951    $client->Write( sprintf( '% 10s', $$ ), 10 );
952
953    # Set up the socket hooks
954    Wx::Event::EVT_SOCKET_INPUT(
955        $self, $client,
956        sub {
957
958            # Accept the data and stream commands
959            my $command = '';
960            my $buffer  = '';
961            while ( $_[0]->Read( $buffer, 128 ) ) {
962                $command .= $buffer;
963                while ( $command =~ s/^(.*?)[\012\015]+//s ) {
964                    $_[1]->single_instance_command( "$1", $_[0] );
965                }
966            }
967            return 1;
968        }
969    );
970    Wx::Event::EVT_SOCKET_LOST(
971        $self, $client,
972        sub {
973            $_[0]->Destroy;
974        }
975    );
976
977    return 1;
978}
979
980sub single_instance_command {
981    my( $self, $line, $socket ) = @_;
982
983    return 1 unless defined $line && length $line;
984
985    # ignore the line if command isn't plain ascii
986    return 1 unless $line =~ s/^(\S+)\s*//s;
987
988    if ( $1 eq 'open' ) {
989        if ( -f $line ) {
990            printf("received from incoming connection %s\n", $line);
991            $self->images->add_images(
992                [
993                    grep { -f $_} split(/,/, $line)
994                ]
995            );
996        }
997    } 
998    else {
999        warn("Unsupported command '$1'");
1000    }
1001
1002    return 1;
1003}
1004
1005
1006sub stop_single_instance_server {
1007    my ( $self ) =@_;
1008
1009    if(exists $self->{_single_instance_server}){
1010        $self->{_single_instance_server}->Destroy;
1011        delete $self->{_single_instance_server};
1012    }
1013}
1014
1015
1016sub default_app {
1017    my ( $self ) = @_ ;
1018
1019    my $app = {
1020        thumb_dir   => $self->thumb_dir,
1021        wx_thumb_dir     => $self->wx_thumb_dir,
1022        resized_dir => $self->resized_dir,
1023        userdata_dir     => $self->userdata_dir,
1024        version          => $self->version,
1025        storable_file    => $self->app_file,
1026
1027    };
1028
1029    $app;
1030}
1031
1032
1033sub connect_or_exit {
1034    my ( $self ) = @_;
1035
1036
1037    my $not_exit = $self->login();
1038    $self->connection->Store;
1039    # user pressed OK
1040    if($not_exit){
1041        if( $self->use_connected ){
1042            while( $not_exit and $self->not_connected ){
1043                $not_exit = $self->login;
1044                last if $self->use_offline;
1045            }
1046            $self->init_transfer_manager;
1047        }
1048    }
1049    else {
1050        $self->resize_manager->stop;
1051        $self->stop_single_instance_server;
1052    }
1053
1054    $not_exit;
1055}
1056
1057
1058sub login {
1059    my ( $self ) = @_;   
1060
1061    $self->init_connection;
1062
1063    $self->login_dlg( 
1064        Uploader::GUI::LoginDlg->new(
1065            {
1066                title         => gettext("Piwigo login"),
1067                site_url      => sub { $self->connection->site_url(@_) },
1068                site_username => sub { $self->connection->site_username(@_) },   
1069                site_password => sub { $self->connection->site_password(@_) },
1070                use_offline   => sub { $self->connection->use_offline(@_) },   
1071            }
1072        )
1073    ) unless $self->login_dlg;
1074
1075    my $icon = Wx::Icon->new();
1076    $icon->LoadFile(
1077        $self->resource_path('favicon.ico'), 
1078        wxBITMAP_TYPE_ICO
1079    );
1080
1081    $self->login_dlg->SetIcon($icon);
1082
1083   
1084    my $rval = $self->login_dlg->ShowModal();
1085    $self->login_dlg->Show(0);
1086
1087    $self->init_branding;
1088   
1089    if ($self->connection->site_url !~ /^http:/){
1090        $self->connection->site_url(
1091            sprintf(
1092                "http://%s",
1093                $self->connection->site_url
1094            )
1095        );   
1096    }
1097
1098    $self->pwg(
1099        # get these parameters from dialog or from file
1100        Uploader::PWG->new(
1101            {
1102                site_url       => $self->connection->site_url,
1103                site_username  => $self->connection->site_username,
1104                site_password  => $self->connection->site_password,
1105                http_username  => $self->connection->http_username,
1106                http_password  => $self->connection->http_password,
1107                branding       => $self->branding,
1108                use_offline    => $self->use_offline,
1109                version        => $self->version,
1110            }
1111        )
1112    );
1113
1114    $rval;
1115}
1116
1117
1118# helper method to get the full path for a resource
1119sub resource_path{
1120    my ( $self, $file ) = @_;
1121
1122    File::Spec->catfile($self->root_dir, $self->resource_dir, $file);
1123}
1124
1125sub bin_path{
1126    my ( $self, $file ) = @_;
1127
1128    File::Spec->catfile($self->root_dir, $self->bin_dir, $file);
1129}
1130
1131sub locale_path{
1132    my ( $self, $file ) = @_;
1133
1134    File::Spec->catfile($self->root_dir, $self->locale_dir, $file);
1135}
1136
1137sub locale_catalog_path{
1138    my ( $self, $file ) = @_;
1139
1140    File::Spec->catfile($self->root_dir, $self->locale_dir, $self->locale->GetCanonicalName, $file);
1141}
1142
1143
1144# some labels differ with branding ( piwigo.com or piwigo.org )
1145sub init_branding {
1146    my ( $self ) =@_;
1147   
1148    if( $self->connection->site_url =~ /\.piwigo\.com/ ){
1149        $self->branding(
1150            {
1151                category  => gettext("album"),
1152                Category  => gettext("Album"),
1153                categories => gettext("albums"),
1154                Categories => gettext("Albums"),
1155                'Add new category' => gettext("Add new album"),
1156                'Category name' => gettext("Album name :"),
1157                'New category' => gettext("New album"),
1158                'What is the destination category?' => gettext("What is the destination album?")
1159            }
1160        );
1161    }
1162    else{
1163        $self->branding(
1164            {
1165                category  => gettext("categorie"),   
1166                Category  => gettext("Categorie"),   
1167                categories => gettext("categories"),   
1168                Categories => gettext("Categories"),   
1169                'Add new category' => gettext("Add new category"),
1170                'Category name' => gettext("Category name :"),
1171                'New category' => gettext("New category"),
1172                'What is the destination category?' => gettext("What is the destination category?")
1173            }
1174        );
1175    }   
1176}
1177
1178
1179sub use_connected {
1180    my ( $self ) = @_;
1181
1182    !$self->use_offline
1183}
1184
1185
1186sub not_connected {
1187    my ( $self ) = @_;
1188
1189    !$self->is_connected;
1190}
1191
1192
1193sub is_connected {
1194    my ( $self ) = @_;
1195
1196    my $_is_connected;
1197
1198    if($self->pwg->login_result->{stat} eq 'ok'){
1199        $_is_connected = 1;
1200    }
1201    else{
1202        Wx::MessageBox( 
1203            sprintf(
1204                "%s\n\n%s %s %s",
1205                $self->pwg->login_result->{message},
1206                gettext("Connection to"),
1207                $self->connection->site_url,
1208                gettext("failed"),
1209            ),
1210            gettext("Piwigo login error"),
1211            wxOK | wxICON_EXCLAMATION, 
1212        );
1213    }
1214   
1215    $_is_connected;
1216}
1217
1218
1219sub init_transfer_manager {
1220    my ( $self ) = @_;
1221
1222    $self->check_upload;
1223
1224    $self->transfer_manager(
1225        Uploader::TransferManager->new({
1226            pwg             => $self->pwg,
1227            progress_event  => $transfer_progress_event,
1228            done_event      => $transfer_done_event,
1229            event_handler   => $self,
1230            batch_end_event => $transfer_batch_end_event,
1231        })
1232    );
1233
1234    $self->image_progress_event(
1235        Wx::NewEventType
1236    );
1237
1238    $self->batch_end_event(
1239        Wx::NewEventType
1240    );
1241
1242    $self->init_transfer_batch_end_event_handler;
1243    $self->init_transfer_done_event_handler;
1244    $self->init_transfer_progress_event_handler;
1245
1246}
1247
1248
1249sub check_upload {
1250    my ( $self ) = @_;
1251
1252    my $err_msg = $self->pwg->check_upload;
1253
1254    $err_msg = gettext("Your user account is not granted to upload photos") if
1255        'Access denied' eq $err_msg;
1256
1257    #Wx::LogMessage("%s", $err_msg) if $err_msg;
1258    Wx::MessageBox($err_msg, "", wxOK | wxICON_ERROR) if $err_msg;
1259
1260    $err_msg;
1261}
1262
1263
1264sub init_transfer_batch_end_event_handler {
1265    my ( $self ) = @_;
1266
1267    Wx::Event::EVT_COMMAND(
1268        $self,
1269        -1,
1270        $transfer_batch_end_event,
1271        sub {
1272            my ( $handler, $event ) = @_;
1273            my $data = $event->GetData;
1274            $handler->on_batch_end($data);
1275        } 
1276    );
1277
1278}
1279
1280
1281sub init_transfer_done_event_handler {
1282    my ( $self ) = @_;
1283
1284    Wx::Event::EVT_COMMAND(
1285        $self,
1286        -1,
1287        $transfer_done_event,
1288        sub {
1289            my ( $handler, $event ) = @_;
1290            my $data = $event->GetData;
1291            $handler->on_image_progress($data);
1292        } 
1293    );
1294
1295}
1296
1297
1298sub init_transfer_progress_event_handler {
1299    my ( $self ) = @_;
1300
1301    Wx::Event::EVT_COMMAND(
1302        $self,
1303        -1,
1304        $transfer_progress_event,
1305        sub {
1306            my ( $handler, $event ) = @_;
1307            my $data : shared = shared_clone($event->GetData);
1308            $handler->on_image_progress($data);
1309        } 
1310    );
1311
1312}
1313
1314
1315sub start_resize {
1316    my( $self, $all_images ) = @_;
1317
1318    # we need to copy data from object to use another thread
1319    my $images = $self->images->get_images(
1320        $self->preferences->get_data,
1321        $self->transfer_manager->destination_category,
1322        $all_images
1323    );
1324
1325    push @$images, { event => "BATCH_END" };
1326
1327    $self->resize_manager->add_images($images);
1328
1329    Wx::PostEvent(
1330        $self->frame,
1331        Wx::PlThreadEvent->new(
1332            -1,
1333            $self->resize_start_event,
1334            shared_clone($images)
1335        )
1336    );
1337
1338    $images;
1339}
1340
1341
1342sub cancel_resize {
1343    my( $self ) = @_;
1344
1345    my $cancelled;
1346
1347    if( $self->resize_manager->pending and wxYES == Wx::MessageBox( 
1348        sprintf(
1349            "Cancel %s resize pending job(s) ?",
1350            $self->resize_manager->pending,
1351        ),
1352        "pLoader job processing",
1353        wxYES_NO|wxNO_DEFAULT| wxICON_QUESTION, ) 
1354    ){
1355        $cancelled = 1;
1356        $self->resize_manager->cancel;
1357    }
1358
1359    $cancelled;
1360}
1361
1362
1363sub cancel_transfer {
1364    my( $self ) = @_;
1365
1366    my $cancelled = 1;
1367    if( $self->transfer_manager->pending ){
1368        if( wxYES == Wx::MessageBox( 
1369            sprintf(
1370                "Cancel %s transfer pending job(s) ?",
1371                $self->transfer_manager->pending,
1372            ),
1373            "pLoader job processing",
1374            wxYES_NO|wxNO_DEFAULT| wxICON_QUESTION, ) 
1375            )
1376        {
1377            $self->transfer_manager->cancel;
1378        }
1379        else{
1380            $cancelled = 0;
1381        }
1382    }
1383
1384    $cancelled;
1385}
1386
1387
1388sub SetFrame {
1389    my ( $self, $frame ) = @_;   
1390
1391    my $url = $self->connection->site_url;
1392   
1393    if($self->use_offline){
1394        $url = gettext("Work Offline");
1395    }
1396
1397    $self->frame($frame);
1398
1399    my $icon = Wx::Icon->new();
1400    $icon->LoadFile(
1401        File::Spec->catfile(
1402            $self->root_dir, $self->resource_dir, 'favicon.ico'
1403        ), 
1404        wxBITMAP_TYPE_ICO
1405    );
1406    $self->frame->SetIcon($icon);
1407}
1408
1409
1410sub GetWxBitmapType {
1411    my ( $self, $type ) = @_;
1412   
1413    $self->{IMGTYPE}->{$type};
1414}
1415
14161;
Note: See TracBrowser for help on using the repository browser.