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

Last change on this file since 5114 was 5114, checked in by ronosman, 11 years ago

Bug 1500 fixed : properties in the listctrl widget are not properly refreshed in batch mode.

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