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

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

Various GUI improvements : Frame MinSize, only disable properties and tags when no selected photo.

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