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

Revision 5184, 60.0 KB checked in by ronosman, 10 years ago (diff)

Feature 1520 added : ability to set photo default caption after the photo is added.

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