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

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

Feature 1548 added : improved photo tags panel.

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