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

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

Feature 1650 added : ability to create square thumbnails.

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