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

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

use tranfer error messages in progress list. various bug fixes.

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