source: extensions/pLoader/trunk/src/Uploader/GUI/Frame.pm @ 5104

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

Feature 1496 added : display a message in the photo selection when it is empty.

File size: 59.5 KB
Line 
1# +-----------------------------------------------------------------------+
2# | pLoader - a Perl photo uploader for Piwigo                            |
3# +-----------------------------------------------------------------------+
4# | Copyright(C) 2008-2010 Piwigo Team                  http://piwigo.org |
5# +-----------------------------------------------------------------------+
6# | This program is free software; you can redistribute it and/or modify  |
7# | it under the terms of the GNU General Public License as published by  |
8# | the Free Software Foundation                                          |
9# |                                                                       |
10# | This program is distributed in the hope that it will be useful, but   |
11# | WITHOUT ANY WARRANTY; without even the implied warranty of            |
12# | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
13# | General Public License for more details.                              |
14# |                                                                       |
15# | You should have received a copy of the GNU General Public License     |
16# | along with this program; if not, write to the Free Software           |
17# | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
18# | USA.                                                                  |
19# +-----------------------------------------------------------------------+
20package Uploader::GUI::Frame;
21use strict;
22use Carp;
23use Wx;
24use Wx::DND;
25use Wx qw/
26             wxSP_3DBORDER
27             wxSP_3D
28             wxNO_FULL_REPAINT_ON_RESIZE
29             wxCLIP_CHILDREN
30             wxYES_NO
31             wxYES
32             wxICON_QUESTION
33             wxITEM_NORMAL
34             wxNullBitmap
35             wxID_OK
36             wxDEFAULT_FRAME_STYLE
37             wxVERTICAL
38             wxGROW
39             wxSHAPED
40             wxBITMAP_TYPE_JPEG
41             wxBITMAP_TYPE_GIF
42             wxBITMAP_TYPE_PNG
43             wxBITMAP_TYPE_ANY
44             wxTB_FLAT
45             wxTB_TEXT
46             wxSIZE
47             wxWHITE
48             wxBLACK
49             wxID_CANCEL
50             wxFD_OPEN
51             wxFD_MULTIPLE
52             wxLI_HORIZONTAL
53             wxALIGN_CENTER_VERTICAL
54             wxALIGN_CENTER_HORIZONTAL
55             wxALL
56             wxGROW
57             wxDefaultPosition
58             wxDefaultSize
59             wxTheApp
60             wxIMAGE_LIST_NORMAL
61             wxAUI_NB_TAB_MOVE
62             wxAUI_NB_TAB_SPLIT
63             wxNO_BORDER
64             wxTE_MULTILINE
65             wxTE_READONLY
66             wxITEM_NORMAL
67             wxCLIP_CHILDREN
68             wxBORDER_NONE
69             wxNullBitmap
70             wxTR_MULTIPLE
71             wxTR_EXTENDED
72             wxTR_HIDE_ROOT
73             wxTR_HAS_BUTTONS
74             wxTR_EDIT_LABELS
75             wxMAXIMIZE
76             wxOK
77             wxICON_EXCLAMATION
78             wxICON_INFORMATION
79             WXK_DELETE
80             wxHORIZONTAL
81             wxVERTICAL
82             wxEXPAND
83         /;
84use base qw/Wx::Frame Class::Accessor::Fast/;
85use File::Spec;
86use Wx::Locale qw/:default/;
87use POSIX qw(ceil floor);
88
89require Win32 if($^O =~ /MSWin32/);
90
91
92my @properties = 
93    qw/
94          progressdlg
95          upload_progressdlg
96          imageviewer
97          imageviewer_img
98          tree
99          tree_root
100          treeimglist
101          tree_item_default
102          pwg
103          logwnd
104          oldlogwnd
105          categories
106          imagelist
107          image_preview
108          image_prop_piwigo
109          image_prop_exif
110          image_prop_tags
111          global_settings_panel
112          piwigo_property_list
113          exif_properties
114          global_settings
115          toolbar
116          branding
117          current_imageviewer_index
118          imageviewer_mnu
119          tree_mnu
120          imageviewer_select_multi
121          frameLayout
122          piwigo_tags
123          image_tags
124          piwigo_photo_properties
125          dlg_piwigo_photo_properties
126          piwigo_photo_properties_tags
127          image_preview_refresh
128          imageviewer_refresh
129          imageviewer_item_refresh
130          horizontal_splitter
131      /;
132__PACKAGE__->mk_accessors( @properties );
133
134use Wx::Perl::TextValidator;
135use Uploader::GUI::wxImageListCtrl;
136use Uploader::GUI::wxPropertyListDlg;
137use Uploader::GUI::wxHtmlWindow;
138use Uploader::GUI::wxGlobalSettings;
139use Uploader::GUI::wxImagePreview;
140use Uploader::GUI::wxPhotoProperties;
141use Uploader::GUI::wxImageReuploadDlg;
142use Uploader::GUI::wxImageProcessingProgressDlg;
143use Uploader::GUI::wxChoiceFilteredPanel;
144use utf8;
145$|=1;
146
147my $ID_TREE_CTX_MENU = 20000 ;
148my $ID_IMAGEVIEWER_CTX_MENU = 20100 ;
149
150sub new {
151    my( $class, $params ) = @_;
152    my $self  = $class->SUPER::new( 
153        undef, 
154        -1, 
155        $params->{title},
156        wxDefaultPosition,
157        wxDefaultSize, 
158        wxDEFAULT_FRAME_STYLE
159    );
160
161
162    $self->pwg( $params->{pwg} );
163    $self->imagelist( $params->{imagelist} );
164
165    # callback for GUI refresh : add thumbnail images to the imageviewer control
166    $self->imagelist->SetNewFilesViewerRefreshCallback(
167        sub { $self->SetNewFilesViewerRefresh(@_) }
168    );
169
170    # callback for GUI refresh : progress dialog display of thumbnail image being created
171    $self->imagelist->SetNewFilesProgressCallback(
172        sub { $self->SetNewFilesProgress(@_) }
173    );
174
175    $self->imagelist->SetNewFilesDisplayEndInfoCallback(
176        sub { $self->SetNewFilesDisplayEndInfo(@_) }
177    );
178
179    # callback for GUI refresh : remove thumbnail images from imageviewer control
180    $self->imagelist->UploadImagesViewerCallback(
181        sub { $self->UploadImagesViewerRefresh(@_) }
182    );
183   
184    $self->imagelist->ReuploadCallback(
185    sub 
186    {
187        Uploader::GUI::wxImageReuploadDlg->new(
188        { 
189            title => gettext("Photo update management"),
190            properties => 
191            {
192                $main::ID_REUPLOAD_ACTION_FILES => 
193                {
194                    selection=>sub {$self->imagelist->reupload_action_files(@_)},
195                    label=>gettext("What shall we do with files? (thumbnail, resized, high resolution)"),
196                    labels=>[
197                        gettext("nothing"),
198                        gettext("replace"),
199                    ],
200                },
201                $main::ID_REUPLOAD_ACTION_PROPERTIES => 
202                { 
203                    selection=>sub{$self->imagelist->reupload_action_properties(@_)},
204                    label=>gettext("What shall we do with single value properties?(caption, comment, author, create date)"),
205                    labels=>[
206                        gettext("nothing"),
207                        gettext("fill if empty (only replace properties currently empty in Piwigo)"),
208                        gettext("replace"),
209                    ],
210                },
211                $main::ID_REUPLOAD_ACTION_PROPERTIES_M =>
212                { 
213                    selection=>sub{$self->imagelist->reupload_action_properties_m(@_)},
214                    label=>gettext("What shall we do with multiple values properties? (categories, tags)"),
215                    labels=>[
216                        gettext("nothing"),
217                        gettext("append (keep existing and add new)"),
218                        gettext("replace"),
219                    ],
220                },
221                $main::ID_REUPLOAD_NOT_ASK => 
222                { 
223                    value=>sub{$self->imagelist->reupload_not_ask(@_)}, 
224                    label=>gettext("Do not ask me again"),
225                },
226                $main::ID_REUPLOAD_TEXT => 
227                { 
228                    label=>gettext("A least one photo has already been added in the past."),
229                },
230            },
231        } )->ShowModal();}
232    );
233
234
235    # callback for GUI refresh : progress dialog display current uploaded image
236    $self->imagelist->progress_thumbnail_refresh(
237        sub { $self->UploadProgressThumbnailRefresh(@_) }
238    );
239
240    $self->imagelist->progress_msg_refresh(
241        sub { $self->UploadProgressMessageRefresh(@_) }
242    );
243
244    $self->imagelist->progress_msg_details_refresh(
245        sub { $self->UploadProgressMessageDetailsRefresh(@_) }
246    );
247
248    $self->imagelist->progressbar_refresh(
249        sub { $self->UploadProgressBarRefresh(@_) }
250    );
251   
252    $self->imagelist->progress_endinfo_refresh(
253        sub { $self->UploadDisplayEndInfo(@_) }
254    );
255
256
257    $self->imagelist->pwg(
258        $self->pwg
259    );
260
261    $self->imagelist->categories(
262        []
263    );
264
265
266    $self->_set_setting_properties;
267    $self->_initFrame;
268    $self->_initMenus;
269    $self->_initEventHandlers;
270    $self->_initImgTypes;   
271
272    # only refresh when calling event is finished
273    Wx::Event::EVT_IDLE(
274        $self,
275        sub {
276            my ( $self, $event ) = @_;
277            if ( $self->image_preview_refresh and $self->image_preview->IsShown ){
278                $self->set_preview_image; 
279                $self->image_preview->Refresh;
280                $self->image_preview_refresh(0);
281            }
282
283            if($self->imageviewer_refresh){
284                $self->imageviewer->Refresh;
285                $self->imageviewer_refresh(0);
286            }
287
288            if($self->imageviewer_item_refresh){
289                $self->imageviewer->ItemRefresh(
290                    $self->current_imageviewer_index
291                );
292                $self->imageviewer_item_refresh(0);
293            }
294
295            $self->OnUpdateToolbar;
296            $event->Skip;
297        }
298    );
299
300    $self->imageviewer->SelectItem(
301        $self->current_imageviewer_index
302    ) if $self->imageviewer->GetItemCount;
303   
304    # if file in command line parameters, try to load
305    my $files = wxTheApp->argv;
306    $self->SetNewFiles($files) if scalar @$files;
307
308    $self->Show;
309    $self;
310}
311
312
313sub _initImgTypes {
314    my ( $self ) = @_;
315
316    $self->{IMGTYPE} = {
317        'jpg' => wxBITMAP_TYPE_JPEG,
318        'gif' => wxBITMAP_TYPE_GIF,
319        'png' => wxBITMAP_TYPE_PNG,
320    };
321}
322
323
324sub GetWxBitmapType {
325    my ( $self, $type ) = @_;
326   
327    $self->{IMGTYPE}->{$type};
328}
329
330
331
332sub _set_setting_properties {
333    my ( $self ) = @_;
334
335    $self->piwigo_photo_properties(
336        {
337            $main::CAPTION => { label=>gettext("Caption")},
338            $main::PHOTO_PROPERTIES_CAPTION => { 
339                value => sub {
340                    $self->multi_selection_mode ?
341                    $self->imagelist->SetImageSelectionName(@_):
342                    $self->imagelist->current_image->site_name(@_) 
343                },
344                frame_callback => sub { $self->imageviewer_item_refresh(1); },
345            },
346            $main::COMMENT => { label=>gettext("Comment")},
347            $main::PHOTO_PROPERTIES_COMMENT => {
348                value => sub { 
349                    $self->multi_selection_mode ?
350                    $self->imagelist->SetImageSelectionComment(@_):
351                    $self->imagelist->current_image->site_comment(@_) 
352                },
353                frame_callback => sub { $self->imageviewer_item_refresh(1); },
354            },
355            $main::AUTHOR => { label=>gettext("Author")},
356            $main::PHOTO_PROPERTIES_AUTHOR => { 
357                value => sub { 
358                    $self->multi_selection_mode ?
359                    $self->imagelist->SetImageSelectionAuthor(@_):
360                    $self->imagelist->current_image->site_author(@_) 
361                },
362                frame_callback => sub { $self->imageviewer_item_refresh(1); },
363            },
364            $main::TAGS => { label=>gettext("Tags")},
365            $main::CREATE_DATE => { label=>gettext("Create date")},
366            $main::PHOTO_PROPERTIES_CREATE_DATE => { 
367                value => sub { 
368                    $self->multi_selection_mode ?
369                    $self->imagelist->SetImageSelectionCreateDate(@_):
370                    $self->imagelist->current_image->create_date(@_) 
371                },
372                frame_callback => sub { $self->imageviewer_item_refresh(1); },
373            },
374            $main::PRIVACY_LEVEL => { label=>gettext("Who can see?")},
375            $main::PHOTO_PROPERTIES_PRIVACY_LEVEL => {
376                selection => sub {
377                    $self->multi_selection_mode ? 
378                    $self->imagelist->SetImageSelectionPrivacyLevel(@_):
379                    $self->imagelist->current_image->privacy_level(@_)
380                },
381                choices => wxTheApp->privacy_level_choices,
382            },
383            $main::PHOTO_PROPERTIES_NB => {
384                texts => [
385                    gettext("Properties"),
386                    gettext("Tags")
387                ], 
388            },
389            $main::PHOTO_PROPERTIES_UPLOAD => { label=>gettext("Upload to Piwigo") },
390        }
391    );   
392
393    $self->global_settings(
394        {
395            $main::DEFAULT_PHOTO_CAPTION => { label => gettext("Default photo caption") },
396            $main::CPANE_RESIZE_ADVANCED => { label => gettext("Advanced") },
397            $main::CPANE_HD_ADVANCED => { label => gettext("Advanced") },
398            $main::CPANE_TRANSFERT_ADVANCED => { label => gettext("Advanced") },
399            $main::GS_THUMBNAIL => { label => gettext("Thumbnail") },
400            $main::GS_SITE_IMG => { label => gettext("Web sized") },
401            $main::GS_HD => { label => gettext("High definition") },
402            $main::GS_CLOSE => { label => gettext("Close")},
403            $main::GS_DEFAULT_PHOTO_CAPTION => {
404                string_selection => sub { $self->imagelist->default_photo_name(@_) },
405                choices =>
406                [
407                    map { gettext $_ } @{wxTheApp->default_photo_names}
408                ],
409                pre_process => sub { my ( $value ) = @_; wxTheApp->eng_default_photo_names->{$value} },
410                frame_callback => sub { 
411                    my( $self, $ctrl, $event ) = @_; 
412                    $self->OnDefaultPhotoCaption($event);
413                },
414            },
415            $main::PHOTO_CAPTION_PREFIX => { label => gettext("Photo caption  prefix") },
416            $main::GS_PHOTO_CAPTION_PREFIX => {
417                value => sub { $self->imagelist->default_name_prefix(@_) },
418            },
419            $main::GS_AUTO_ROTATE => {
420                label => gettext("Auto rotate image"),
421                value => sub { $self->imagelist->auto_rotate(@_) }
422           },
423            $main::DEFAULT_AUTHOR => { label => gettext("Default author")},
424            $main::GS_DEFAULT_AUTHOR => { value => sub { $self->imagelist->author(@_) } },
425            $main::THUMBNAIL_SIZE => { label => gettext("Site thumbnail size") },
426            $main::GS_THUMBNAIL_SIZE => {
427                value => sub { $self->imagelist->thumb_size(@_) },
428                validator => Wx::Perl::TextValidator->new( '\d' ) 
429            },
430            $main::THUMBNAIL_JPEG_QUALITY => { label => gettext("Site thumbnail jpeg quality") },
431            $main::GS_THUMBNAIL_JPEG_QUALITY => {
432                value => sub { $self->imagelist->th_quality(@_) },
433                validator => Wx::Perl::TextValidator->new( '\d' ) 
434            },
435            $main::GS_CREATE_RESIZED => {
436                selection => sub { $self->imagelist->create_resized(@_) },
437                choices =>
438                [
439                    map { gettext $_ } ( "Use original", "Use resized original" ) 
440                ],
441                frame_callback => sub { 
442                    my( $dlg, $ctrl, $event ) = @_;
443                    $dlg->OnCreateResized($event);
444                },
445            },
446            $main::SITE_IMG_WIDTH => { label => gettext("Maximum width") },
447            $main::GS_SITE_IMG_WIDTH => {
448                value => sub { $self->imagelist->resize_w(@_) },
449                validator => Wx::Perl::TextValidator->new( '\d' ) 
450            },
451            $main::SITE_IMG_HEIGHT => { label => gettext("Maximum height") },
452            $main::GS_SITE_IMG_HEIGHT => {
453                value => sub { $self->imagelist->resize_h(@_) },
454                validator => Wx::Perl::TextValidator->new( '\d' ) 
455            },
456            $main::SITE_IMG_JPEG_QUALITY => { label => gettext("Site image jpeg quality") },
457            $main::GS_SITE_IMG_JPEG_QUALITY => {
458                value => sub { $self->imagelist->quality(@_) },
459                validator => Wx::Perl::TextValidator->new( '\d' ) 
460            },
461            $main::SITE_IMG_FILTER => { label => gettext("Site image filter") },
462            $main::GS_SITE_IMG_FILTER => {
463                string_selection =>  sub { $self->imagelist->filter(@_) },
464                choices =>
465                [
466                    qw/Point Box Triangle Hermite Hanning Hamming Blackman Gaussian Quadratic Cubic Catrom Mitchell Lanczos Bessel Sinc/ 
467                ],
468            },
469            $main::SITE_IMG_BLUR => { label => gettext("Site image blur") },
470            $main::GS_SITE_IMG_BLUR => {
471                value => sub { $self->imagelist->blur(@_) },
472                validator => Wx::Perl::TextValidator->new( '\d' ) 
473            },
474            $main::SITE_IMG_INTERLACE => { label => gettext("Site image interlace") },
475            $main::GS_SITE_IMG_INTERLACE => {
476                string_selection => sub { $self->imagelist->interlace(@_) },
477                choices =>
478                [
479                    qw/None Line Plane Partition JPEG GIF PNG/ 
480                ],
481            },
482            $main::GS_REMOVE_UPLOADED_FROM_SELECTION => {
483                label => gettext("Remove uploaded photo from selection"),
484                value => sub { $self->imagelist->remove_uploaded_from_selection(@_) },
485            },
486            $main::GS_HD_UPLOAD => {
487                choices  =>
488                [
489                    map { gettext $_ } @{wxTheApp->upload_hd}
490                ],
491                pre_process => sub { my ( $value ) = @_; wxTheApp->eng_upload_hd->{$value} },
492                string_selection => sub { $self->imagelist->upload_hd(@_) },
493                frame_callback => sub { 
494                    my( $self, $ctrl, $event ) = @_; 
495                    $self->OnHDUpload($event);
496                },
497            },
498            $main::HD_IMG_WIDTH => { label => gettext("Maximum width") },
499            $main::GS_HD_IMG_WIDTH => {
500                label => gettext("HD image width"),
501                value => sub { $self->imagelist->hd_w(@_) },
502                validator => Wx::Perl::TextValidator->new( '\d' ) 
503            },
504            $main::HD_IMG_HEIGHT => { label => gettext("Maximum height") },
505            $main::GS_HD_IMG_HEIGHT => {
506                label => gettext("HD image height"),
507                value => sub { $self->imagelist->hd_h(@_) },
508                validator => Wx::Perl::TextValidator->new( '\d' ) 
509            },
510            $main::HD_IMG_JPEG_QUALITY => { label => gettext("HD image jpeg quality") },
511            $main::GS_HD_IMG_JPEG_QUALITY => {
512                value => sub { $self->imagelist->hd_quality(@_) },
513                validator => Wx::Perl::TextValidator->new( '\d' ) 
514            },
515            $main::HD_IMG_FILTER => { label => gettext("HD image filter") },
516            $main::GS_HD_IMG_FILTER => {
517                string_selection =>  sub { $self->imagelist->hd_filter(@_) },
518                choices =>
519                [
520                    qw/Point Box Triangle Hermite Hanning Hamming Blackman Gaussian Quadratic Cubic Catrom Mitchell Lanczos Bessel Sinc/ 
521                ],
522            },
523            $main::HD_IMG_BLUR => { label => gettext("HD image blur") },
524            $main::GS_HD_IMG_BLUR => {
525                value => sub { $self->imagelist->hd_blur(@_) },
526                validator => Wx::Perl::TextValidator->new( '\d' ) 
527            },
528            $main::HD_IMG_INTERLACE => { label => gettext("HD image interlace") },
529            $main::GS_HD_IMG_INTERLACE => {
530                string_selection => sub { $self->imagelist->hd_interlace(@_) },
531                choices =>
532                [
533                    qw/None Line Plane Partition JPEG GIF PNG/ 
534                ],
535            },
536            $main::GS_WMARK_ACTIVATE => {
537              label  => gettext("Activate watermark"),
538              value  => sub { $self->imagelist->watermark_activate(@_) },
539              frame_callback => sub { 
540                  my( $self, $ctrl, $event ) = @_; 
541                  $self->OnWatermark($event);
542              },
543            },
544            $main::GS_WMARK_ACTIVATE_HD => {
545              label => gettext("Activate watermark on high definition"),
546              value => sub { $self->imagelist->watermark_activate_pwg_high(@_) },
547              frame_callback => sub { 
548                  my( $self, $ctrl, $event ) = @_; 
549                  $self->OnWatermark($event);
550              },
551            },
552            $main::WMARK_TEXT => { label  => gettext("Text") },
553            $main::GS_WMARK_TEXT => { 
554              value  => sub { $self->imagelist->watermark_text(@_) },
555            },
556            $main::WMARK_TEXT_SIZE => { label     => gettext("Text size") },
557            $main::GS_WMARK_TEXT_SIZE => {
558                value   => sub { $self->imagelist->watermark_text_size(@_) },
559            },
560            $main::WMARK_COLOR => { label     => gettext("Color") },
561            $main::GS_WMARK_COLOR => {
562                string_selection => sub { $self->imagelist->watermark_color(@_) },
563                choices   => [
564                               map { gettext $_ } @{wxTheApp->colors}
565                             ],
566                pre_process => sub { my ( $value ) = @_; wxTheApp->eng_colors->{$value} },
567            },
568            $main::WMARK_POSITION => { label     => gettext("Position") },
569            $main::GS_WMARK_POSITION => {
570                string_selection => sub { $self->imagelist->watermark_position(@_) },
571                choices  => [
572                               map { gettext $_ } @{wxTheApp->positions}
573                           ],
574                pre_process => sub { my ( $value ) = @_; wxTheApp->eng_positions->{$value} },
575            },
576            $main::WMARK_MARGIN_TOP => { label => gettext("Top margin") },
577            $main::GS_WMARK_MARGIN_TOP => {
578                value   => sub { $self->imagelist->watermark_y(@_) },
579            },
580            $main::WMARK_MARGIN_LEFT => { label => gettext("Left margin") },
581            $main::GS_WMARK_MARGIN_LEFT => {
582                value   => sub { $self->imagelist->watermark_x(@_) },
583            },
584            $main::CHUNK_SIZE => { label => gettext("Transfert chunk size") },
585            $main::GS_CHUNK_SIZE => {
586                value   => sub { wxTheApp->chunk_size(@_) },
587            },
588        }   
589    );
590
591    $self->piwigo_property_list(
592        [
593            {
594                label => gettext("Photo caption"),
595            },
596            {
597                label => gettext("Comment"),
598            },
599            {
600                label => gettext("Author"),
601            },
602            {
603                label => gettext("File name"),
604            },
605            {
606                label => gettext("Create date"),
607            },
608        ]   
609    );
610
611    $self->exif_properties(
612        [
613            {
614                label    => gettext("Create date"),
615                value    => sub { $self->imagelist->current_image->create_date }, 
616                readonly => 1,
617            },   
618            {
619                label    => gettext("Model"),
620                value    => sub { $self->imagelist->current_image->exif_tag('Model') }, 
621                readonly => 1,
622            },   
623            {
624                label    => gettext("Width"),
625                value    => sub { $self->imagelist->current_image->exif_tag('ImageWidth') }, 
626                readonly => 1,
627            },   
628            {
629                label    => gettext("Height"),
630                value    => sub { $self->imagelist->current_image->exif_tag('ImageHeight') }, 
631                readonly => 1,
632            },   
633            {
634                label    => gettext("Orientation"),
635                value    => sub { $self->imagelist->current_image->exif_tag('Orientation') }, 
636                readonly => 1,
637            },   
638            {
639                label    => "ISO",
640                value    => sub { $self->imagelist->current_image->exif_tag('ISO') }, 
641                readonly => 1,
642            },   
643            {
644                label    => gettext("Shutter speed"),
645                value    => sub { $self->imagelist->current_image->exif_tag('ExposureTime') }, 
646                readonly => 1,
647            },   
648            {
649                label    => gettext("Aperture"),
650                value    => sub { $self->imagelist->current_image->exif_tag('ApertureValue') }, 
651                readonly => 1,
652            },   
653            {
654                label    => gettext("Focal length"),
655                value    => sub { $self->imagelist->current_image->exif_tag('FocalLength') }, 
656                readonly => 1,
657            },   
658            {
659                label    => gettext("Lens"),
660                value    => sub { $self->imagelist->current_image->exif_tag('Lens') }, 
661                readonly => 1,
662            },   
663        ]
664    );   
665
666    $self->image_tags(
667        sub { scalar @{$self->imagelist->image_selection} > 1 ? $self->imagelist->SetImageSelectionTags(@_) : $self->imagelist->current_image->site_tags(@_)||[]  }
668    );
669
670    $self->piwigo_tags(
671        sub { wxTheApp->pwg->tags }
672    );   
673}
674
675sub _create_piwigo_tag {
676    my ( $self, $name ) = @_;
677   
678    if(
679        Wx::MessageBox( 
680            sprintf(
681                "%s \"%s\" ?",
682                gettext("Do you want to create"), 
683                $name,
684            ),
685            gettext("Piwigo search information"),
686            wxYES_NO | wxICON_QUESTION, 
687        ) == wxYES
688    ){   
689        $self->pwg->AddTags($name);
690        $self->pwg->RefreshTags;
691    }
692}
693
694sub _refreshFrame {
695    my ( $self ) = @_;
696   
697    eval { $self->_set_setting_properties; };
698    $self->_refresh_settings_panels_properties;
699    map {
700        $_->Refresh;
701    }
702    (
703        $self->image_prop_exif,
704        $self->global_settings_panel,
705        $self->piwigo_photo_properties_tags
706    );
707   
708}
709
710#
711sub _initFrame {
712    my ( $self ) = @_;
713   
714    $self->create_toolbar;
715
716    my $sizer_h = Wx::BoxSizer->new( wxHORIZONTAL );
717   
718
719
720    $self->imageviewer(
721        Uploader::GUI::wxImageListCtrl->new( 
722            { 
723                parentwnd => $self,
724                imagelist => $self->imagelist,
725                image_size => $self->imagelist->wx_thumb_size,
726                columns => $self->piwigo_property_list,
727            }
728        )
729    );
730
731    # message displayed in the image listctrl when empty
732    $self->imageviewer->InitEmptyMsg;
733
734    $self->init_panels;
735
736    $self->dlg_piwigo_photo_properties (
737        Uploader::GUI::wxPhotoProperties->new(
738            {
739                parentwnd       => $self,
740                properties      => $self->piwigo_photo_properties,
741                tags            =>
742                {
743                    id => $main::PHOTO_PROPERTIES_TAG,
744                    choices => $self->piwigo_tags,
745                    selection => $self->image_tags,
746                    creation_callback => sub { $self->_create_piwigo_tag(@_) },
747               },
748            }
749        )
750    );
751
752    $self->piwigo_photo_properties_tags(
753        $self->dlg_piwigo_photo_properties->FindWindow($main::PHOTO_PROPERTIES_TAG)
754    );
755
756    $self->create_tree(
757        $self->dlg_piwigo_photo_properties->FindWindow($main::PHOTO_PROPERTIES_CATEGORIES)
758    );
759
760
761    $self->init_dnd_targets;
762
763    if( $self->imagelist->wx_thumb_imglist->GetImageCount){
764        $self->ShowImageViewer;
765       
766        $self->imageviewer->Refresh(
767            $self->imagelist->wx_thumb_imglist
768        );
769       
770        $self->OnUpdateImageviewerNotEmpty;
771    }
772    else{
773        $self->OnUpdateImageviewerEmpty;
774    }
775
776    # the imageviewer has a stretch factor of 1 : expands its size on frame resize
777    $sizer_h->Add( $self->imageviewer, 1, wxEXPAND|wxALL, 2 );
778    $sizer_h->Add( $self->dlg_piwigo_photo_properties, 0, wxEXPAND|wxALL, 2 );
779
780
781    $self->SetSizer(
782        $sizer_h
783    );
784    my $new_size = $sizer_h->Fit(
785        $self
786    );
787    $self->SetMinSize([600, 500]);
788    $self->Center;
789}
790
791sub OnUpdateImageviewerEmpty {
792    my ( $self ) = @_;
793
794    $self->dlg_piwigo_photo_properties->Enable(0);
795    $self->imageviewer->OnEmpty;
796}
797
798sub OnUpdateImageviewerNotEmpty {
799    my ( $self ) = @_;
800
801    $self->dlg_piwigo_photo_properties->Enable(1);
802    $self->imageviewer->OnNotEmpty;
803}
804
805
806sub _refresh_settings_panels_properties {
807    my ( $self ) = @_;   
808
809    $self->dlg_piwigo_photo_properties->properties(
810        $self->piwigo_photo_properties
811    );
812
813   
814    $self->image_prop_exif->properties(
815        $self->exif_properties
816    );
817
818    $self->global_settings_panel->properties(
819        $self->global_settings
820    );   
821
822}
823
824sub _init_settings_panels {
825    my ( $self ) = @_;   
826
827
828    $self->image_prop_exif(
829        Uploader::GUI::wxPropertyListDlg->new( 
830            { 
831                parentwnd       => $self,
832                properties      => $self->exif_properties,
833                caption         => sprintf("%s - EXIF", gettext("Properties")),
834            }
835        )
836    );
837    $self->image_prop_exif->Hide;
838
839    $self->global_settings_panel(
840        Uploader::GUI::wxGlobalSettings->new( 
841            { 
842                parentwnd       => $self,
843                caption         => gettext("Global settings"),
844                properties      => $self->global_settings,
845            }
846        )
847    );
848    $self->global_settings_panel->Hide;
849
850
851
852    $self->image_preview(
853        Uploader::GUI::wxImagePreview->new(
854            { 
855                parentwnd    => $self,
856                caption      => gettext("Preview"),
857            }
858        )
859    );
860
861}
862
863sub init_panels {
864    my ( $self ) = @_;
865   
866    $self->_init_settings_panels;   
867}
868
869# HTML code for getting started dialog box
870
871
872sub init_dnd_targets {
873    my ( $self ) = @_;   
874
875    $self->imageviewer->SetDropTarget( 
876        DNDImageListDropTarget->new(
877            $self->imageviewer
878        ) 
879    );
880
881    $self->tree->SetDropTarget( 
882        DNDCategoryTreeDropTarget->new(
883            $self->tree
884        )
885    );
886   
887}
888
889
890
891sub OnPhotoProperties {
892    my ( $self ) = @_;
893
894    $self->image_prop_exif->Show(1);
895}
896
897sub OnPreview {
898    my ( $self ) = @_;
899
900    $self->image_preview->Show(1);
901
902
903
904}
905
906
907sub OnGlobalSettings {
908    my ( $self ) = @_;
909
910    $self->global_settings_panel->Show(1);
911}
912
913sub OnChooseLanguage {
914    my ( $self ) = @_;   
915
916  my $languages = wxTheApp->available_languages;
917
918
919  my $dialog = new Wx::SingleChoiceDialog( 
920    undef, 
921    gettext( "Choose a language" ), 
922    gettext( "Choose a language" ),
923    [ map { sprintf($_->[0], gettext($_->[2])) } @$languages ] 
924  );
925
926  if( $dialog->ShowModal() == wxID_OK ) {
927    wxTheApp->current_language(
928        $languages->[$dialog->GetSelection][1]
929    );
930
931    Wx::LogMessage(
932        sprintf(
933            "%s : %s", 
934            gettext("pLoader needs to be restarted to display the new selected language"),
935            gettext($languages->[$dialog->GetSelection][2])
936        )
937    );
938    wxTheApp->layout_clean(1);
939  }
940
941  $dialog->Destroy;
942
943}
944
945sub OnDefaultPhotoNameChanged {
946    my ( $self ) = @_;
947   
948    Wx::LogMessage("New default_photo_name %s", $self->imagelist->default_photo_name);   
949}
950
951sub OnGeneralSettingsClose {
952    my ( $self, $event ) = @_;
953
954    $self->global_settings_panel->Hide;
955}
956
957sub OnImageExifPropClose {
958    my ( $self, $event ) = @_;
959
960    $self->image_exif_prop->Hide;
961}
962
963sub create_tree {
964    my ( $self, $tree ) = @_;
965
966    my $images = [
967        map {
968            Wx::Bitmap->new( $_, wxBITMAP_TYPE_PNG )
969           
970        }
971        (
972          wxTheApp->resource_path('tree_pwg.png'),
973          wxTheApp->resource_path('tree_folder.png'),
974        )   
975    ];
976
977    $self->treeimglist( Wx::ImageList->new( 16, 16, 1 ) );
978    map {
979        $self->treeimglist->Add($_);
980    }
981    @$images;
982   
983    $self->tree( 
984        $tree || Wx::TreeCtrl->new( 
985           $self->horizontal_splitter, 
986           -1, 
987           wxDefaultPosition, 
988           wxDefaultSize, 
989           wxCLIP_CHILDREN|
990           wxTR_HAS_BUTTONS|
991           wxTR_EDIT_LABELS
992        ) 
993    );
994
995    $self->tree->SetImageList( $self->treeimglist );
996    $self->populate_tree_categories if !wxTheApp->use_offline;
997    $self->tree ;
998}
999
1000
1001sub populate_tree_categories {
1002    my ( $self ) = @_;
1003
1004    $self->populate_tree(
1005        $self->tree,
1006        wxTheApp->pwg->categories,
1007    ) if defined wxTheApp->pwg ;
1008   
1009
1010}
1011
1012
1013# returns a valid itemData
1014sub itemData { Wx::TreeItemData->new( $_[0] ) }
1015
1016sub populate_tree {
1017    my ( $self, $tree, $tree_items ) = @_;
1018    my $root = shift @{$tree_items};
1019
1020    $self->tree_root(
1021        $tree->AddRoot( 
1022            $root->[0], 
1023            $root->[3], 
1024            $root->[4], 
1025            itemData( $root->[2] ) 
1026        )
1027    );
1028
1029  $self->populate_tree_helper( $tree, $self->tree_root, $tree_items );
1030 
1031  $tree->SelectItem( $self->tree_root );
1032  $tree->Expand( $self->tree_root );
1033}
1034
1035sub populate_tree_helper {
1036  my ( $self, $tree, $parent_id, $tree_items ) = @_;
1037
1038  my $id;
1039
1040  map {
1041      my $name = $_->[0];
1042
1043      $id = $tree->AppendItem( 
1044                                   $parent_id, 
1045                                   $name,
1046                                   defined($_->[3]) ? $_->[3] : 0, 
1047                                   defined($_->[4]) ? $_->[4] : 0, 
1048                                   itemData( $_->[2]) 
1049                              );
1050      $self->tree_item_default($id) if ! defined $self->tree_item_default;
1051      # current item has children
1052      if( ref( $_->[1] ) eq 'ARRAY' ) {
1053          $self->populate_tree_helper( $tree, $id, $_->[1] );
1054      } 
1055  }
1056  @{$tree_items};
1057
1058}
1059
1060sub _initMenus {
1061    my ( $self ) = @_ ;
1062
1063    $self->_tree_mnu;
1064    $self->_imageviewer_mnu;   
1065}
1066
1067
1068sub _tree_mnu {
1069    my ( $self ) = @_;   
1070
1071    my $ctx_mnu = Wx::Menu->new;
1072   
1073    map {
1074        $ctx_mnu->Append(
1075            @$_[0..2], wxITEM_NORMAL
1076        );
1077    }
1078    (
1079        # workaround : first item does not show bitmap
1080        [
1081            0, 
1082            "",
1083            "",
1084            wxTheApp->resource_path('mnu_folder_new.png'),
1085        ],
1086        [
1087            1+$ID_TREE_CTX_MENU, 
1088            wxTheApp->branding->{'Add new category'},
1089            sprintf(
1090                "%s %s %s %s", 
1091                gettext("Add a new"), 
1092                wxTheApp->branding->{category},
1093                gettext("to the currently selected"),
1094                wxTheApp->branding->{category},
1095            ),
1096            wxTheApp->resource_path('mnu_folder_new.png'),
1097        ],
1098        [
1099            2+$ID_TREE_CTX_MENU, 
1100            gettext("Refresh"),
1101            sprintf(
1102                "Refresh %s list.",
1103                wxTheApp->branding->{category},
1104            ),
1105            wxTheApp->resource_path('mnu_refresh.png'),
1106        ],
1107        [
1108            3+$ID_TREE_CTX_MENU, 
1109            gettext("Expand all"),
1110            sprintf(
1111                "Expand %s list.",
1112                wxTheApp->branding->{category},
1113            ),
1114            wxTheApp->resource_path('mnu_expandall.png'),
1115        ],
1116        [
1117            4+$ID_TREE_CTX_MENU, 
1118            gettext("Collapse all"),
1119            sprintf(
1120                "Collapse %s list.",
1121                wxTheApp->branding->{category},
1122            ),
1123            wxTheApp->resource_path('mnu_collapseall.png'),
1124        ],
1125    );
1126
1127    $ctx_mnu->Delete(0);
1128    $self->tree_mnu(
1129         $ctx_mnu
1130    );   
1131}   
1132
1133sub _imageviewer_mnu {
1134    my ( $self ) = @_;   
1135
1136    my $ctx_mnu = Wx::Menu->new;
1137   
1138    map {
1139        $ctx_mnu->Append(
1140            @$_[0..2]
1141        );
1142    }
1143    (
1144        # workaround : first item does not show bitmap
1145        [
1146            0, 
1147            "",
1148            "",
1149            wxTheApp->resource_path('mnu_properties.png'),
1150        ],
1151        [
1152            1+$ID_IMAGEVIEWER_CTX_MENU, 
1153            gettext("Properties"),
1154            gettext("Modify photo properties"),
1155            wxTheApp->resource_path('mnu_properties.png'),
1156        ],
1157        [
1158            2+$ID_IMAGEVIEWER_CTX_MENU, 
1159            gettext("Preview"),
1160            gettext("Display photo preview"),
1161            wxTheApp->resource_path('mnu_preview.png'),
1162        ],
1163    );
1164   
1165    $ctx_mnu->Delete(0);
1166    $self->imageviewer_mnu(
1167         $ctx_mnu
1168    );   
1169}
1170
1171sub _initEventHandlers {
1172    my ( $self ) = @_ ;
1173   
1174    Wx::Event::EVT_MENU( $self, 101, \&OnAddImages );
1175    Wx::Event::EVT_MENU( $self, 102, \&OnRemoveImages );
1176    Wx::Event::EVT_MENU( $self, 103, \&OnUploadImages );
1177    Wx::Event::EVT_MENU( $self, 104, \&OnGlobalSettings );
1178    Wx::Event::EVT_MENU( $self, 105, \&OnChooseLanguage );
1179    Wx::Event::EVT_CHOICE( $self, 106, \&OnPhotoSelMode );
1180    Wx::Event::EVT_TREE_SEL_CHANGED( $self, $self->tree, \&OnTreeSelChanged );
1181    Wx::Event::EVT_TREE_ITEM_RIGHT_CLICK( $self, $self->tree, \&OnTreeItemRightClick );
1182    Wx::Event::EVT_TREE_END_LABEL_EDIT( $self, $self->tree, \&OnTreeEndLabelEdit );
1183
1184    Wx::Event::EVT_LIST_END_LABEL_EDIT( $self, $self->imageviewer, \&OnImageViewerEndLabelEdit );
1185    Wx::Event::EVT_LIST_ITEM_ACTIVATED( $self, $self->imageviewer, \&OnImageViewerItemActivated );
1186    Wx::Event::EVT_LIST_ITEM_SELECTED($self, $self->imageviewer, \&OnImageViewerItemSelected) ;
1187    Wx::Event::EVT_LIST_ITEM_DESELECTED($self, $self->imageviewer, \&OnImageViewerItemDeSelected) ;
1188    Wx::Event::EVT_LIST_ITEM_RIGHT_CLICK($self, $self->imageviewer, \&OnImageViewerItemRightClick) ;
1189
1190    Wx::Event::EVT_LIST_KEY_DOWN($self, $self->imageviewer, \&OnImageViewerKeyDown) ;
1191
1192    Wx::Event::EVT_CLOSE( $self, \&OnClose );
1193
1194    Wx::Event::EVT_MENU( $self, 1+$ID_TREE_CTX_MENU, \&OnAddCategories );
1195    Wx::Event::EVT_MENU( $self, 2+$ID_TREE_CTX_MENU, \&OnRefreshCategories );
1196    Wx::Event::EVT_MENU( $self, 3+$ID_TREE_CTX_MENU, \&OnExpandCategories );
1197    Wx::Event::EVT_MENU( $self, 4+$ID_TREE_CTX_MENU, \&OnCollapseCategories );
1198
1199    Wx::Event::EVT_MENU( $self, 1+$ID_IMAGEVIEWER_CTX_MENU, \&OnPhotoProperties );
1200    Wx::Event::EVT_MENU( $self, 2+$ID_IMAGEVIEWER_CTX_MENU, \&OnPreview );
1201
1202    Wx::Event::EVT_BUTTON( $self, $main::PHOTO_PROPERTIES_UPLOAD, \&OnUploadImages );
1203    Wx::Event::EVT_BUTTON( $self, $self->imageviewer->add_button->GetId, \&OnAddImages );
1204
1205}
1206
1207{
1208  my $prevdir;
1209  my $prevfile;
1210
1211  sub OnAddImages {
1212    my( $self, $event ) = @_;
1213    my $dialog = Wx::FileDialog->new
1214      ( $self, gettext("Select photos for upload"), $prevfile, $prevdir,
1215        sprintf("%s (*.JPG)|*.JPG|(*.jpg)|*.jpg|All(*.*)|*.*", gettext("JPEG files")),
1216        wxFD_OPEN|wxFD_MULTIPLE );
1217
1218    my $file_paths = [];
1219    if( $dialog->ShowModal != wxID_CANCEL ) {
1220        @$file_paths = $dialog->GetPaths;
1221        $self->SetNewFiles($file_paths) ;
1222    }
1223    $dialog->Destroy;
1224  }
1225}
1226
1227sub OnUpdateToolbar {
1228    my( $self ) = @_;
1229   
1230    if($self->global_settings_panel->IsShown){
1231        $self->toolbar->EnableTool(104, 0);
1232    }
1233    else{   
1234        $self->toolbar->EnableTool(104, 1);
1235    }
1236
1237    if($self->global_settings_panel->IsShown){
1238        $self->toolbar->EnableTool(104, 0);
1239    }
1240    else{   
1241        $self->toolbar->EnableTool(104, 1);
1242    }
1243
1244}
1245
1246
1247sub OnRemoveImages {
1248    my( $self, $event ) = @_;
1249
1250   
1251    $self->imagelist->RemoveImageSelection;
1252    $self->imageviewer->Refresh;   
1253
1254    if (!$self->imageviewer->GetItemCount){
1255        $self->image_preview->image(
1256            0
1257        ); 
1258        # have to reset
1259        $self->dlg_piwigo_photo_properties->ClearProperties;
1260        $self->piwigo_photo_properties_tags->ClearAllSelection;
1261        $self->imagelist->SetCurrentImage(-1);
1262        $self->OnUpdateImageviewerEmpty;
1263    }
1264    else{
1265        $self->OnUpdateImageviewerNotEmpty;
1266    }
1267
1268    if(!$self->multi_selection_mode){
1269        $self->OnUpdateSingleSelectionModeUI;
1270    }
1271
1272    $self->image_preview->Refresh;
1273    $self->image_prop_exif->Refresh;
1274}
1275
1276sub SetNewFiles {
1277    my ( $self, $file_paths ) = @_;
1278
1279    $self->ShowImageViewer();
1280   
1281    $self->progressdlg->Destroy if defined $self->progressdlg;
1282    $self->progressdlg( 
1283        Uploader::GUI::wxImageProcessingProgressDlg->new(
1284            { 
1285                title => gettext("Image processing progress information"),
1286                bt_label => gettext("Cancel image processing"), 
1287                bt_close_label => gettext("Close"),
1288                stop_processing => sub { $self->imagelist->stop_processing(1); Wx::Yield(); },
1289             }
1290        )       
1291    );
1292    $self->progressdlg->Show(1);
1293    Wx::Yield();
1294
1295   
1296    my $files = [
1297        map {
1298            # to make sure that unicode chars in filenames are supported
1299            {
1300                ANSIPathName => $^O =~ /MSWin32/ ? Win32::GetANSIPathName($_) : $_,
1301                PathName => $_,
1302            },
1303        }@$file_paths   
1304    ];
1305
1306    @$files = sort { $a->{PathName} cmp $b->{PathName} } @$files;   
1307
1308    $self->imagelist->SetNewFiles(
1309        $files
1310    );
1311
1312   
1313}
1314
1315sub OnTreeSelChanged {
1316    my( $self, $event ) = @_;
1317 
1318    my @items = $self->tree->GetSelections;
1319
1320    $self->imagelist->categories(
1321        [
1322            map {
1323                my $category = $self->tree->GetPlData( $_ );
1324                $category->{id} if $category != -1;
1325            }
1326            @items
1327        ]
1328    );
1329}
1330
1331sub OnTreeItemRightClick {
1332    my( $self, $event ) = @_;
1333
1334
1335    $self->PopupMenu($self->tree_mnu, wxDefaultPosition);
1336   
1337}
1338
1339sub OnTreeEndLabelEdit {
1340    my( $self, $event ) = @_;
1341
1342    my $label = $event->GetLabel;
1343   
1344    $label =~ s/^\s+$//;
1345
1346    if(defined($label) and !( "" eq $label )){
1347        $self->_SetLabel($event)
1348    }
1349    else{
1350        $event->Veto;
1351    }
1352}
1353
1354sub _SetLabel {
1355    my( $self, $event ) = @_;
1356   
1357    my $category = $self->tree->GetPlData($event->GetItem);
1358    my $category_id;
1359   
1360    $category_id = $category->{id} if 'HASH' eq ref($category) ;
1361    my $comment;
1362    my ( $success, $status_msg, $content ) = $self->pwg->SetInfoCategories( 
1363        $event->GetLabel, 
1364        $comment, 
1365        $category_id
1366    );
1367
1368    my $ok = 1;
1369   
1370    if(!$success){
1371        $ok = 0;
1372    }
1373
1374    if('fail' eq $content->{stat}){
1375        $ok = 0;
1376    }
1377
1378    # method call failed
1379    if(!$ok){
1380        $event->Veto;
1381        Wx::MessageBox( 
1382            sprintf(
1383                "%s %s", 
1384                gettext("Update failed : "),
1385                $status_msg
1386            ),
1387            gettext("Piwigo update error"),
1388            wxOK | wxICON_EXCLAMATION, 
1389        );
1390        Wx::LogMessage("%s\n\n%s", Dumper($content), gettext("This function is not available. A Piwigo upgrade may resolve this issue."));
1391    }
1392}
1393
1394sub OnImageViewerItemRightClick {
1395    my( $self, $event ) = @_;
1396
1397   
1398    $self->PopupMenu($self->imageviewer_mnu, wxDefaultPosition);
1399   
1400   
1401}
1402
1403sub OnExpandCategories {
1404    my ( $self, $event ) = @_;
1405
1406    my $parent_item = $self->tree->GetSelection;
1407    $self->tree->ExpandAllChildren($parent_item);
1408    $self->tree->EnsureVisible($parent_item);
1409}
1410
1411sub OnCollapseCategories {
1412    my ( $self, $event ) = @_;
1413
1414    my $parent_item = $self->tree->GetSelection;
1415    $self->tree->CollapseAllChildren($parent_item);
1416    $self->tree->Expand($parent_item) if -1 == $self->tree->GetPlData($parent_item);
1417}
1418
1419sub OnAddCategories {
1420    my ( $self, $event ) = @_;
1421
1422    my $parent_item = $self->tree->GetSelection;
1423
1424    my $category = $self->tree->GetPlData($parent_item);
1425    my $category_id;
1426   
1427    $category_id = $category->{id} if 'HASH' eq ref($category) ;
1428
1429    my $dialog = Wx::TextEntryDialog->new( 
1430        $self, 
1431        wxTheApp->branding->{'Category name'}, 
1432        wxTheApp->branding->{'Add new category'},
1433        wxTheApp->branding->{'New category'}, 
1434    );
1435
1436    if( $dialog->ShowModal != wxID_CANCEL ) {
1437        my $name = $dialog->GetValue;
1438        my ( $success, $status_msg, $content ) = $self->pwg->AddCategories( $name, $category_id);
1439
1440        if($success){
1441            $self->_append_category($parent_item, $name, $content->{result}{id});
1442        }
1443    }
1444    $dialog->Destroy;
1445}
1446
1447sub OnRefreshCategories {
1448    my ( $self, $event ) = @_;
1449
1450    $self->_refresh_all_categories_helper;
1451}
1452
1453
1454sub _refresh_all_categories_helper {
1455    my ( $self ) = @_;   
1456
1457    my $busycursor = Wx::BusyCursor->new();
1458    $self->tree->CollapseAll;
1459    $self->tree->DeleteAllItems;
1460    $self->imagelist->categories([]);
1461    $self->pwg->RefreshCategories();
1462    $self->populate_tree_categories;
1463}
1464
1465sub _append_category {
1466    my ( $self, $parent_id, $name, $id ) = @_;
1467
1468    $self->tree->SelectItem(
1469        $self->tree->AppendItem(
1470            $parent_id, 
1471            $name, 
1472            1, 
1473            -1, 
1474            Wx::TreeItemData->new( { id => $id } )
1475        )
1476    );
1477}
1478
1479sub OnImageViewerEndLabelEdit {
1480    my( $self, $event ) = @_;
1481 
1482    my $image = $self->imagelist->GetImage($event->GetIndex);
1483    $image->site_name(
1484        $event->GetLabel
1485    );
1486       
1487    $self->dlg_piwigo_photo_properties->SetProperties;
1488}
1489
1490sub OnImageViewerItemActivated {
1491    my( $self, $event ) = @_;
1492   
1493    $self->current_imageviewer_index(
1494        $event->GetIndex
1495    );
1496
1497    $self->OnPhotoProperties;
1498}
1499
1500
1501sub OnImageViewerItemSelected {
1502    my( $self, $event ) = @_;
1503
1504    my $bc = Wx::BusyCursor->new;
1505    my $indx = $event->GetIndex;
1506    $self->_on_imageviewer_item_selected($indx);
1507
1508    $event->Skip;
1509
1510}
1511
1512sub OnImageViewerItemDeSelected {
1513    my( $self, $event ) = @_;
1514
1515    my $bc = Wx::BusyCursor->new;
1516    $self->_on_imageviewer_item_selection_changed;
1517
1518    $event->Skip;
1519
1520}
1521
1522sub _on_imageviewer_item_selected {
1523    my ( $self, $index ) = @_;   
1524    $self->current_imageviewer_index($index);
1525    $self->imagelist->SetCurrentImage($index);
1526   
1527    $self->_on_imageviewer_item_selection_changed;
1528}
1529
1530sub _on_imageviewer_item_selection_changed {
1531    my ( $self ) = @_;   
1532
1533    $self->imagelist->image_selection(
1534        $self->imageviewer->GetSelectedItems
1535    );
1536
1537    # for batch mode : reset the batch buffer if single selection
1538    if($self->multi_selection_mode){
1539        $self->OnUpdateMultiSelectionModeUI;
1540        $self->imagelist->SetImageSelectionTags([]);
1541        $self->imagelist->image_selection_privacy_level(-1);
1542        $self->imagelist->image_selection_name("");
1543        $self->imagelist->image_selection_author("");
1544        $self->imagelist->image_selection_comment("");
1545        $self->imagelist->image_selection_create_date(-1);
1546    }
1547    else{
1548        $self->OnUpdateSingleSelectionModeUI;
1549    }
1550    # process image_preview in idle time
1551    # and when current event is processed
1552    # see call to EVT_IDLE
1553    $self->image_preview_refresh(1);
1554
1555    $self->dlg_piwigo_photo_properties->SetProperties if defined $self->dlg_piwigo_photo_properties;
1556    $self->image_prop_exif->Refresh;
1557    $self->piwigo_photo_properties_tags->Refresh;
1558
1559}
1560
1561sub multi_selection_mode {
1562    my ( $self ) = @_;
1563
1564    scalar @{$self->imagelist->image_selection} > 1;
1565}
1566
1567sub OnUpdateMultiSelectionModeUI{
1568    my( $self ) = @_;
1569
1570
1571    $self->dlg_piwigo_photo_properties->{_multi_selection_mode_panel}{_text1}->SetLabel(
1572        sprintf(gettext("You have selected a batch of %s photos"), $self->imageviewer->GetSelectectItemsCount )
1573    );
1574
1575    $self->dlg_piwigo_photo_properties->{_multi_selection_mode_panel}{_text2}->SetLabel(
1576        gettext("Changes apply to the whole batch")
1577    );
1578
1579    $self->dlg_piwigo_photo_properties->{_multi_selection_mode_panel}->Show(1);
1580    $self->dlg_piwigo_photo_properties->Layout;
1581}
1582
1583sub OnUpdateSingleSelectionModeUI{
1584    my( $self ) = @_;
1585
1586    $self->dlg_piwigo_photo_properties->{_multi_selection_mode_panel}->Show(0);
1587    $self->dlg_piwigo_photo_properties->Layout;
1588
1589}
1590
1591
1592sub set_preview_image {
1593    my ( $self ) = @_;   
1594
1595    my $current_image = $self->imagelist->current_image;
1596    my $image = Wx::Image->new;
1597    $image->LoadFile(
1598        $current_image->file, 
1599        wxBITMAP_TYPE_ANY
1600    );
1601 
1602    if($self->imagelist->auto_rotate){
1603        # exif from original image
1604        my $orientation = $current_image->exif_metadata->{Orientation};
1605
1606        # Valid for Rotate 180, Rotate 90 CW, Rotate 270 CW
1607        if( $orientation =~ m/Rotate (\d+)/ ){
1608            for(my $i=0; $i < floor($1/90) ; $i++){
1609                $image = $image->Rotate90;
1610            }               
1611        }
1612    }
1613
1614    $self->image_preview->image_size(
1615        [$image->GetWidth, $image->GetHeight, ]
1616    );       
1617
1618    $self->image_preview->image(
1619        $image
1620    );       
1621}
1622
1623sub OnImageViewerKeyDown {
1624    my( $self, $event ) = @_;
1625
1626    if(WXK_DELETE == $event->GetKeyCode){
1627        $self->OnRemoveImages();
1628       
1629        my $index = $self->current_imageviewer_index < $self->imageviewer->GetItemCount ?
1630            $self->current_imageviewer_index : $self->imageviewer->GetItemCount -1 ;
1631        $self->imageviewer->SelectItem(
1632            $index
1633        );
1634        $self->imageviewer->EnsureVisible(
1635            $index
1636        );
1637    }   
1638
1639}
1640
1641sub OnUploadImages {
1642    my( $self, $event ) = @_;
1643
1644    eval {
1645        $self->ProcessImageSelection();   
1646    };
1647}
1648
1649# remove image from imagelist when uploaded
1650sub UploadImagesViewerRefresh {
1651    my ( $self ) = @_;   
1652
1653
1654    $self->imageviewer->Refresh;
1655
1656    if(!$self->imageviewer->GetItemCount){
1657        $self->image_preview->image(0);
1658        $self->OnUpdateImageviewerEmpty;
1659    }
1660    # reset previous selection
1661    $self->imagelist->image_selection(
1662        []
1663    );
1664
1665    if(!$self->multi_selection_mode){
1666        $self->OnUpdateSingleSelectionModeUI;
1667    }
1668
1669    $self->image_preview->Refresh;
1670    Wx::Yield();
1671}
1672
1673sub UploadProgressMessageRefresh {
1674    my ( $self, $msg ) = @_;   
1675
1676    Wx::Yield();
1677
1678    $self->upload_progressdlg->processing(
1679        $msg   
1680    );   
1681    $self->upload_progressdlg->LogProgress();
1682
1683    Wx::Yield();
1684}
1685
1686sub UploadProgressMessageDetailsRefresh {
1687    my ( $self, $msg ) = @_;   
1688
1689    Wx::Yield();
1690
1691    $self->upload_progressdlg->processing_details(
1692        $msg   
1693    );   
1694    $self->upload_progressdlg->LogProgress();
1695
1696    Wx::Yield();
1697}
1698
1699
1700sub UploadProgressThumbnailRefresh {
1701    my ( $self ) = @_;   
1702
1703    my $imagelist = $self->imagelist ;
1704
1705 
1706    $self->upload_progressdlg->image->SetBitmap(wxNullBitmap);
1707    $self->upload_progressdlg->image->SetBitmap(
1708        Wx::Bitmap->new( 
1709            $self->imagelist->current_image->wx_thumb_file, 
1710            $self->GetWxBitmapType($self->imagelist->type), 
1711        )
1712    );
1713
1714    Wx::Yield();
1715}
1716
1717sub UploadProgressBarRefresh {
1718    my ( $self, $value ) = @_;   
1719
1720    eval {
1721        $self->upload_progressdlg->progress(
1722            $value
1723        );
1724        $self->upload_progressdlg->LogProgress();
1725    };
1726    #croak gettext("Upload cancelled") if $@;
1727
1728    Wx::Yield();
1729}
1730
1731sub SetNewFilesDisplayEndInfo {
1732    my ( $self, $msg ) = @_;   
1733   
1734    $self->progressdlg->DisplayEndInfo($msg);
1735}
1736
1737sub UploadDisplayEndInfo {
1738    my ( $self, $msg ) = @_;   
1739   
1740    my $imagelist = $self->imagelist ;
1741   
1742    $self->upload_progressdlg->DisplayEndInfo($msg);
1743}
1744
1745sub ShowImageViewer {
1746    my ( $self ) = @_;   
1747
1748    if(!$self->imageviewer->IsShown){
1749        $self->imageviewer->Show(1);
1750    }
1751}
1752
1753
1754sub ActivateImageViewer {
1755    my ( $self ) = @_;   
1756   
1757}
1758
1759
1760sub SetNewFilesViewerRefresh {
1761
1762    my ( $self ) = @_;   
1763
1764    my $wximagelist = $self->imagelist->wx_thumb_imglist;
1765    #print Dumper "SetNewFilesViewerRefresh", $self->imagelist->current_image;
1766    my $indx = $wximagelist->Add(
1767        Wx::Bitmap->new( 
1768            $self->imagelist->current_image->wx_thumb_file, 
1769            $self->GetWxBitmapType($self->imagelist->type), 
1770        )
1771    ) if defined $self->imagelist->current_image->wx_thumb_file;
1772    #print $self->imagelist->current_image->wx_thumb_file, " added with index ", $indx, "\n";   
1773   
1774    $self->imageviewer->Refresh(
1775        $wximagelist
1776    );
1777
1778    $self->OnUpdateImageviewerNotEmpty if $self->imageviewer->GetItemCount;
1779
1780    Wx::Yield();
1781}
1782
1783
1784
1785# prepare and upload image_selection
1786sub ProcessImageSelection {
1787    my ( $self ) = @_;
1788
1789    return if !scalar @{$self->imagelist->sums};
1790
1791    if( scalar @{$self->imagelist->categories} ){
1792        # all selected is implicit
1793        if(!scalar @{$self->imageviewer->GetSelectedItems}){
1794       
1795            $self->imagelist->image_selection(
1796                $self->imageviewer->GetAllItems
1797            );
1798        }
1799       
1800        return if( !defined $self->imagelist->image_selection );
1801        return if( !scalar @{$self->imagelist->image_selection} );
1802       
1803        $self->upload_progressdlg->Destroy if defined $self->upload_progressdlg;
1804        $self->upload_progressdlg(
1805            Uploader::GUI::wxImageProcessingProgressDlg->new(
1806                { 
1807                    title    => gettext("Image upload progress information"),
1808                    bt_label => gettext("Cancel upload"),
1809                    bt_close_label => gettext("Close"), 
1810                    stop_processing => sub { $self->imagelist->stop_processing(1); Wx::Yield(); }, 
1811                 }
1812            )       
1813        );
1814        # modeless dialog
1815        $self->upload_progressdlg->Show(1);
1816        Wx::Yield();
1817        eval {
1818            $self->imagelist->UploadSelection;
1819        };
1820        if($@){
1821            Wx::MessageBox( 
1822                sprintf(
1823                    gettext("Upload cancelled"),
1824                ),
1825                gettext("Piwigo upload information"),
1826                wxOK | wxICON_INFORMATION, 
1827            );
1828        }
1829    }
1830    else {
1831        Wx::MessageBox( 
1832            sprintf(
1833                "%s", 
1834                wxTheApp->branding->{'What is the destination category?'}
1835            ),
1836            gettext("Piwigo upload error"),
1837            wxOK | wxICON_EXCLAMATION, 
1838        );
1839    }
1840}
1841
1842
1843sub SetNewFilesProgress {
1844    my ( $self ) = @_;
1845
1846    my $imagelist = $self->imagelist;
1847
1848    $self->progressdlg->processing(
1849        sprintf(
1850            $imagelist->progress_msg, 
1851            $imagelist->current_image->file,
1852        )
1853    );
1854
1855    eval {
1856        $self->progressdlg->image->SetSize([ $imagelist->wx_thumb_size, $imagelist->wx_thumb_size]);
1857        $self->progressdlg->image->SetBitmap(wxNullBitmap);
1858        $self->progressdlg->image->SetBitmap(
1859            Wx::Bitmap->new( 
1860                $imagelist->current_image->wx_thumb_file,
1861                $self->GetWxBitmapType( $imagelist->type )
1862            )
1863        );
1864        $self->progressdlg->progress(
1865            $imagelist->count * ( 100/scalar @{$imagelist->new_files} )
1866        );
1867        $self->progressdlg->LogProgress();
1868    };
1869    Wx::Yield();
1870}
1871
1872sub OnClose {
1873  my $self = shift;
1874
1875
1876    # Restaure previous log wnd
1877    Wx::Log::SetActiveTarget( $self->oldlogwnd );
1878
1879    # allways store
1880 
1881    wxTheApp->StoreConnectionProperties;
1882   
1883    $self->imagelist->Store;
1884    wxTheApp->login_dlg->Destroy;   
1885
1886   
1887    wxTheApp->imageviewerIndex(
1888        $self->current_imageviewer_index
1889    );
1890   
1891    my $frameLayout = {};
1892   
1893    ( $frameLayout->{pX}, $frameLayout->{pY}, $frameLayout->{W}, $frameLayout->{H} ) = ( $self->GetPositionXY, $self->GetSizeWH ) ; 
1894   
1895    wxTheApp->frameLayout(
1896        $frameLayout
1897    );
1898
1899    wxTheApp->StoreLayoutProperties;
1900
1901    #destroy hidden dialogs
1902    $self->global_settings_panel->Destroy;
1903    $self->image_preview->Destroy;
1904    $self->image_prop_exif->Destroy;
1905
1906    $self->progressdlg->Destroy if defined $self->progressdlg;
1907    $self->upload_progressdlg->Destroy if defined $self->upload_progressdlg;
1908
1909    $self->Destroy;
1910}
1911
1912
1913sub create_toolbar {
1914    my( $self ) = @_;
1915
1916    my $tb = Wx::ToolBar->new( $self, -1, wxDefaultPosition, [600, -1], wxTB_FLAT );
1917    $tb->SetToolBitmapSize( wxSIZE( 32, 32 ) );
1918    map {
1919        my $icon1 = Wx::Icon->new();
1920        eval {
1921            $icon1->LoadFile($_->[2], $_->[3]);
1922        };
1923        my $tb_icon1 = Wx::Bitmap->new( $icon1 );
1924
1925        my $icon2 = Wx::Icon->new();
1926        eval {
1927            $icon2->LoadFile($_->[5], $_->[3]);
1928        };
1929        my $tb_icon2 = Wx::Bitmap->new( $icon2 );
1930
1931
1932        $tb->AddTool( $_->[0], $_->[1], $tb_icon1, $tb_icon2, wxITEM_NORMAL, $_->[1] );
1933        $tb->EnableTool( $_->[0], $_->[4]);
1934    }
1935    (
1936        [
1937            101, 
1938            gettext("Add photo to selection"), 
1939            wxTheApp->resource_path('tb_add.png'), 
1940            wxBITMAP_TYPE_PNG, 
1941            1, 
1942            wxTheApp->resource_path('tb_add.png'), 
1943            gettext("Add photo to selection for resizing and uploading")
1944        ],
1945        [
1946            102, 
1947            gettext("Remove photo from selection"), 
1948            wxTheApp->resource_path('tb_remove.png'), 
1949            wxBITMAP_TYPE_PNG, 
1950            1, 
1951            wxTheApp->resource_path('tb_remove.png'),
1952            gettext("Remove photo from selection. Files are not deleted ")
1953        ],
1954        [
1955            103, 
1956            gettext("Upload to Piwigo"), 
1957            wxTheApp->resource_path('tb_upload.png'), 
1958            wxBITMAP_TYPE_PNG, 
1959            wxTheApp->use_offline ? 0 : 1, 
1960            wxTheApp->resource_path('tb_upload.png'),
1961            gettext("Upload photos to Piwigo.")
1962        ],
1963        [
1964            104, 
1965            gettext("Global settings"), 
1966            wxTheApp->resource_path('tb_settings.png'), 
1967            wxBITMAP_TYPE_PNG, 
1968            0, 
1969            wxTheApp->resource_path('tb_settings.png'),
1970            gettext("Change global settings.")
1971        ],
1972        [
1973            105, 
1974            gettext("Language choice"), 
1975            wxTheApp->resource_path('tb_i18n.png'), 
1976            wxBITMAP_TYPE_PNG, 
1977            1, 
1978            wxTheApp->resource_path('tb_i18n.png'),
1979            gettext("Language choice")
1980        ],
1981   
1982    );
1983   
1984    $tb->AddSeparator;
1985   
1986    $tb->AddControl(
1987        Wx::Choice->new(
1988        $tb,
1989            106,
1990            wxDefaultPosition,
1991            [300, -1],
1992            [],
1993        )
1994    );
1995    my $ch = $tb->FindWindow(106);
1996    $ch->SetToolTip(gettext("How photo selection is displayed"));
1997    map {
1998        $ch->Append(gettext($_), $_);
1999    }(
2000        "Thumbnail and caption",
2001        "Thumbnail",
2002        "Property list"
2003    );
2004   
2005    $ch->SetStringSelection(gettext($self->imagelist->display_mode));
2006    $tb->Realize;
2007
2008    $self->toolbar(
2009        $tb
2010    );
2011    $self->SetToolBar($tb);
2012
2013    return $tb;
2014}
2015
2016sub OnPhotoSelMode {
2017    my ( $self, $event )= @_;
2018   
2019    $self->imagelist->display_mode(
2020        $event->GetClientData
2021    );
2022
2023    $self->imageviewer->change_display_mode(1);
2024}
2025
2026sub _create_textctrl {
2027    my( $self, $parent, $text, $size ) = @_;
2028
2029    return Wx::TextCtrl->new( $parent, -1, $text, [0, 0], $size,
2030                              wxNO_BORDER | wxTE_MULTILINE | wxTE_READONLY  );
2031}
2032
2033sub create_textctrl {
2034    my( $self, $text, $size ) = @_;
2035
2036    return $self->_create_textctrl( $self, $text, $size );
2037}
2038
2039sub DESTROY {
2040    my( $self ) = @_;
2041
2042}
2043
2044
2045
20461;
2047
2048
2049
2050
2051
2052package DNDImageListDropTarget;
2053use Wx qw/wxTheApp/;
2054use base qw(Wx::FileDropTarget Class::Accessor::Fast);
2055
2056__PACKAGE__->mk_accessors( 
2057    qw/
2058          imageviewer
2059      /
2060);
2061
2062sub new {
2063  my $class = shift;
2064  my $imageviewer = shift;
2065  my $self = $class->SUPER::new( @_ );
2066
2067  $self->imageviewer($imageviewer);
2068
2069  return $self;
2070}
2071
2072sub OnDropFiles {
2073  my( $self, $x, $y, $files ) = @_;
2074
2075  wxTheApp->frame->SetNewFiles($files) ;
2076}
2077
2078
2079
2080
20811;
2082
2083
2084package DNDCategoryTreeDropTarget;
2085
2086use base qw(Wx::TextDropTarget Class::Accessor::Fast);
2087use Data::Dumper;
2088use Wx qw/
2089              wxDragNone
2090              wxDragCopy
2091              wxDragMove
2092              wxTheApp
2093         /;
2094
2095__PACKAGE__->mk_accessors( 
2096    qw/
2097          tree
2098      /
2099);
2100
2101sub new {
2102  my ( $class, $tree ) = @_;
2103  my $self = $class->SUPER::new();
2104
2105  $self->tree($tree);
2106
2107  return $self;
2108}
2109
2110
2111
2112sub OnDropText {
2113  my( $self, $x, $y, $textdata ) = @_;
2114
2115  # must be $VAR1 because $textdata is the result of Data::Dumper
2116  my $VAR1;
2117  eval $textdata;
2118  eval {
2119      if(scalar @$VAR1){
2120             my @items;
2121             if(scalar @items < 2) {
2122               my ($dropItem, $flag) = $self->tree->HitTest([$x, $y]);
2123                 push @items, $dropItem;
2124             }
2125             else {
2126                 @items = $self->tree->GetSelections;
2127             }
2128             
2129             # remove root item which is not a valid category
2130             @items = grep { $self->tree->GetPlData( $_ ) != -1 } @items;
2131             
2132             wxTheApp->frame->imagelist->categories(
2133                 [
2134                     map {
2135                         $self->tree->GetPlData( $_ )->{id};
2136                     }
2137                     @items
2138                 ]
2139             );
2140           
2141             wxTheApp->frame->imagelist->image_selection($VAR1);
2142             wxTheApp->frame->ProcessImageSelection ;
2143      }   
2144  };
2145}
2146
2147
21481;
Note: See TracBrowser for help on using the repository browser.