OSDN Git Service

PostClass.CreatedAtの型をDateTimeUtcに変更
[opentween/open-tween.git] / OpenTween / MediaSelector.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2014 spx (@5px)
3 // All rights reserved.
4 // 
5 // This file is part of OpenTween.
6 // 
7 // This program is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General Public License as published by the Free
9 // Software Foundation; either version 3 of the License, or (at your option)
10 // any later version.
11 // 
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 // for more details. 
16 // 
17 // You should have received a copy of the GNU General Public License along
18 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
19 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20 // Boston, MA 02110-1301, USA.
21
22 using System;
23 using System.Collections.Generic;
24 using System.ComponentModel;
25 using System.Drawing;
26 using System.Data;
27 using System.IO;
28 using System.Linq;
29 using System.Text;
30 using System.Threading.Tasks;
31 using System.Windows.Forms;
32 using OpenTween.Api.DataModel;
33 using OpenTween.Connection;
34
35 namespace OpenTween
36 {
37     public partial class MediaSelector : UserControl
38     {
39         public event EventHandler<EventArgs> BeginSelecting;
40         public event EventHandler<EventArgs> EndSelecting;
41
42         public event EventHandler<EventArgs> FilePickDialogOpening;
43         public event EventHandler<EventArgs> FilePickDialogClosed;
44
45         public event EventHandler<EventArgs> SelectedServiceChanged;
46
47         [Browsable(false)]
48         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
49         public OpenFileDialog FilePickDialog { get; set; }
50
51         /// <summary>
52         /// 選択されている投稿先名を取得する。
53         /// </summary>
54         [Browsable(false)]
55         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
56         public string ServiceName
57         {
58             get { return ImageServiceCombo.Text; }
59         }
60
61         /// <summary>
62         /// 選択されている投稿先を示すインデックスを取得する。
63         /// </summary>
64         [Browsable(false)]
65         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
66         public int ServiceIndex
67         {
68             get { return ImageServiceCombo.SelectedIndex; }
69         }
70
71         /// <summary>
72         /// 選択されている投稿先の IMediaUploadService を取得する。
73         /// </summary>
74         [Browsable(false)]
75         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
76         public IMediaUploadService SelectedService
77         {
78             get
79             {
80                 var serviceName = this.ServiceName;
81                 if (string.IsNullOrEmpty(serviceName))
82                     return null;
83
84                 return this.pictureService.TryGetValue(serviceName, out var service)
85                     ? service : null;
86             }
87         }
88
89         /// <summary>
90         /// 指定された投稿先名から、作成済みの IMediaUploadService インスタンスを取得する。
91         /// </summary>
92         public IMediaUploadService GetService(string serviceName)
93         {
94             this.pictureService.TryGetValue(serviceName, out var service);
95             return service;
96         }
97
98         /// <summary>
99         /// 利用可能な全ての IMediaUploadService インスタンスを取得する。
100         /// </summary>
101         public ICollection<IMediaUploadService> GetServices()
102         {
103             return this.pictureService.Values;
104         }
105
106         private class SelectedMedia
107         {
108             public IMediaItem Item { get; set; }
109             public MyCommon.UploadFileType Type { get; set; }
110             public string Text { get; set; }
111
112             public SelectedMedia(IMediaItem item, MyCommon.UploadFileType type, string text)
113             {
114                 this.Item = item;
115                 this.Type = type;
116                 this.Text = text;
117             }
118
119             public SelectedMedia(string text)
120                 : this(null, MyCommon.UploadFileType.Invalid, text)
121             {
122             }
123
124             public bool IsValid
125             {
126                 get
127                 {
128                     return this.Item != null && this.Type != MyCommon.UploadFileType.Invalid;
129                 }
130             }
131
132             public string Path
133             {
134                 get
135                 {
136                     return this.Item?.Path ?? "";
137                 }
138             }
139
140             public string AltText => this.Item?.AltText ?? "";
141
142             public override string ToString()
143             {
144                 return this.Text;
145             }
146         }
147
148         private Dictionary<string, IMediaUploadService> pictureService;
149
150         private void CreateServices(Twitter tw, TwitterConfiguration twitterConfig)
151         {
152             this.pictureService?.Clear();
153             this.pictureService = null;
154
155             this.pictureService = new Dictionary<string, IMediaUploadService> {
156                 ["Twitter"] = new TwitterPhoto(tw, twitterConfig),
157                 ["Imgur"] = new Imgur(tw, twitterConfig),
158                 ["Mobypicture"] = new Mobypicture(tw, twitterConfig),
159             };
160         }
161
162         public MediaSelector()
163         {
164             InitializeComponent();
165
166             this.ImageSelectedPicture.InitialImage = Properties.Resources.InitialImage;
167         }
168
169         /// <summary>
170         /// 投稿先サービスなどを初期化する。
171         /// </summary>
172         public void Initialize(Twitter tw, TwitterConfiguration twitterConfig, string svc, int? index = null)
173         {
174             CreateServices(tw, twitterConfig);
175
176             SetImageServiceCombo();
177             SetImagePageCombo();
178
179             SelectImageServiceComboItem(svc, index);
180         }
181
182         /// <summary>
183         /// 投稿先サービスを再作成する。
184         /// </summary>
185         public void Reset(Twitter tw, TwitterConfiguration twitterConfig)
186         {
187             CreateServices(tw, twitterConfig);
188
189             SetImageServiceCombo();
190         }
191
192         /// <summary>
193         /// 指定されたファイルの投稿に対応した投稿先があるかどうかを示す値を取得する。
194         /// </summary>
195         public bool HasUploadableService(string fileName, bool ignoreSize)
196         {
197             FileInfo fl = new FileInfo(fileName);
198             string ext = fl.Extension;
199             long? size = ignoreSize ? (long?)null : fl.Length;
200
201             if (IsUploadable(this.ServiceName, ext, size))
202                 return true;
203
204             foreach (string svc in ImageServiceCombo.Items)
205             {
206                 if (IsUploadable(svc, ext, size))
207                     return true;
208             }
209
210             return false;
211         }
212
213         /// <summary>
214         /// 指定された投稿先に投稿可能かどうかを示す値を取得する。
215         /// ファイルサイズの指定がなければ拡張子だけで判定する。
216         /// </summary>
217         private bool IsUploadable(string serviceName, string ext, long? size)
218         {
219             if (!string.IsNullOrEmpty(serviceName))
220             {
221                 var imageService = this.pictureService[serviceName];
222                 if (imageService.CheckFileExtension(ext))
223                 {
224                     if (!size.HasValue)
225                         return true;
226
227                     if (imageService.CheckFileSize(ext, size.Value))
228                         return true;
229                 }
230             }
231             return false;
232         }
233
234         /// <summary>
235         /// 投稿するファイルとその投稿先を選択するためのコントロールを表示する。
236         /// </summary>
237         private void BeginSelection(IMediaItem[] items)
238         {
239             if (items == null || items.Length == 0)
240             {
241                 BeginSelection();
242                 return;
243             }
244
245             var service = this.SelectedService;
246             if (service == null) return;
247
248             var count = Math.Min(items.Length, service.MaxMediaCount);
249             if (!this.Visible || count > 1)
250             {
251                 // 非表示時または複数のファイル指定は新規選択として扱う
252                 SetImagePageCombo();
253
254                 this.BeginSelecting?.Invoke(this, EventArgs.Empty);
255
256                 this.Visible = true;
257             }
258             this.Enabled = true;
259
260             if (count == 1)
261             {
262                 ImagefilePathText.Text = items[0].Path;
263                 AlternativeTextBox.Text = items[0].AltText;
264                 ImageFromSelectedFile(items[0], false);
265             }
266             else
267             {
268                 for (int i = 0; i < count; i++)
269                 {
270                     var index = ImagePageCombo.Items.Count - 1;
271                     if (index == 0)
272                     {
273                         ImagefilePathText.Text = items[i].Path;
274                         AlternativeTextBox.Text = items[i].AltText;
275                     }
276                     ImageFromSelectedFile(index, items[i], false);
277                 }
278             }
279         }
280
281         /// <summary>
282         /// 投稿するファイルとその投稿先を選択するためのコントロールを表示する(主にD&amp;D用)。
283         /// </summary>
284         public void BeginSelection(string[] fileNames)
285         {
286             if (fileNames == null || fileNames.Length == 0)
287             {
288                 BeginSelection();
289                 return;
290             }
291
292             var items = fileNames.Select(x => CreateFileMediaItem(x, false)).OfType<IMediaItem>().ToArray();
293             BeginSelection(items);
294         }
295
296         /// <summary>
297         /// 投稿するファイルとその投稿先を選択するためのコントロールを表示する。
298         /// </summary>
299         public void BeginSelection(Image image)
300         {
301             if (image == null)
302             {
303                 BeginSelection();
304                 return;
305             }
306
307             var items = new [] { CreateMemoryImageMediaItem(image, false) }.OfType<IMediaItem>().ToArray();
308             BeginSelection(items);
309         }
310
311         /// <summary>
312         /// 投稿するファイルとその投稿先を選択するためのコントロールを表示する。
313         /// </summary>
314         public void BeginSelection()
315         {
316             if (!this.Visible)
317             {
318                 this.BeginSelecting?.Invoke(this, EventArgs.Empty);
319
320                 this.Visible = true;
321                 this.Enabled = true;
322
323                 var media = (SelectedMedia)ImagePageCombo.SelectedItem;
324                 ImageFromSelectedFile(media.Item, true);
325                 ImagefilePathText.Focus();
326             }
327         }
328
329         /// <summary>
330         /// 選択処理を終了してコントロールを隠す。
331         /// </summary>
332         public void EndSelection()
333         {
334             if (this.Visible)
335             {
336                 ImagefilePathText.CausesValidation = false;
337
338                 this.EndSelecting?.Invoke(this, EventArgs.Empty);
339
340                 this.Visible = false;
341                 this.Enabled = false;
342                 ClearImageSelectedPicture();
343
344                 ImagefilePathText.CausesValidation = true;
345             }
346         }
347
348         /// <summary>
349         /// 選択された投稿先名と投稿する MediaItem を取得する。MediaItem は不要になったら呼び出し側にて破棄すること。
350         /// </summary>
351         public bool TryGetSelectedMedia(out string imageService, out IMediaItem[] mediaItems)
352         {
353             var validItems = ImagePageCombo.Items.Cast<SelectedMedia>()
354                              .Where(x => x.IsValid).Select(x => x.Item).OfType<IMediaItem>().ToArray();
355
356             if (validItems.Length > 0 &&
357                 ImageServiceCombo.SelectedIndex > -1)
358             {
359                 var serviceName = this.ServiceName;
360                 if (MessageBox.Show(string.Format(Properties.Resources.PostPictureConfirm1, serviceName, validItems.Length),
361                                    Properties.Resources.PostPictureConfirm2,
362                                    MessageBoxButtons.OKCancel,
363                                    MessageBoxIcon.Question,
364                                    MessageBoxDefaultButton.Button1)
365                                == DialogResult.OK)
366                 {
367                     //収集した MediaItem が破棄されないように、予め null を代入しておく
368                     foreach (SelectedMedia media in ImagePageCombo.Items)
369                     {
370                         if (media != null) media.Item = null;
371                     }
372
373                     imageService = serviceName;
374                     mediaItems = validItems;
375                     EndSelection();
376                     SetImagePageCombo();
377                     return true;
378                 }
379             }
380             else
381             {
382                 MessageBox.Show(Properties.Resources.PostPictureWarn1, Properties.Resources.PostPictureWarn2);
383             }
384
385             imageService = null;
386             mediaItems = null;
387             return false;
388         }
389
390         private MemoryImageMediaItem CreateMemoryImageMediaItem(Image image, bool noMsgBox)
391         {
392             if (image == null) return null;
393
394             MemoryImage memoryImage = null;
395             try
396             {
397                 // image から png 形式の MemoryImage を生成
398                 memoryImage = MemoryImage.CopyFromImage(image);
399
400                 return new MemoryImageMediaItem(memoryImage);
401             }
402             catch
403             {
404                 memoryImage?.Dispose();
405
406                 if (!noMsgBox) MessageBox.Show("Unable to create MemoryImage.");
407                 return null;
408             }
409         }
410
411         private IMediaItem CreateFileMediaItem(string path, bool noMsgBox)
412         {
413             if (string.IsNullOrEmpty(path)) return null;
414
415             try
416             {
417                 return new FileMediaItem(path);
418             }
419             catch
420             {
421                 if (!noMsgBox) MessageBox.Show("Invalid file path: " + path);
422                 return null;
423             }
424         }
425
426         private void ValidateNewFileMediaItem(string path, string altText, bool noMsgBox)
427         {
428             var media = (SelectedMedia)ImagePageCombo.SelectedItem;
429             var item = media.Item;
430
431             if (path != media.Path)
432             {
433                 DisposeMediaItem(media.Item);
434                 media.Item = null;
435
436                 item = CreateFileMediaItem(path, noMsgBox);
437             }
438
439             if (item != null)
440                 item.AltText = altText;
441
442             ImagefilePathText.Text = path;
443             AlternativeTextBox.Text = altText;
444             ImageFromSelectedFile(item, noMsgBox);
445         }
446
447         private void DisposeMediaItem(IMediaItem item)
448         {
449             var disposableItem = item as IDisposable;
450             disposableItem?.Dispose();
451         }
452
453         private void FilePickButton_Click(object sender, EventArgs e)
454         {
455             var service = this.SelectedService;
456
457             if (FilePickDialog == null || service == null) return;
458             FilePickDialog.Filter = service.SupportedFormatsStrForDialog;
459             FilePickDialog.Title = Properties.Resources.PickPictureDialog1;
460             FilePickDialog.FileName = "";
461
462             this.FilePickDialogOpening?.Invoke(this, EventArgs.Empty);
463
464             try
465             {
466                 if (FilePickDialog.ShowDialog() == DialogResult.Cancel) return;
467             }
468             finally
469             {
470                 this.FilePickDialogClosed?.Invoke(this, EventArgs.Empty);
471             }
472
473             ValidateNewFileMediaItem(FilePickDialog.FileName, AlternativeTextBox.Text.Trim(), false);
474         }
475
476         private void ImagefilePathText_Validating(object sender, CancelEventArgs e)
477         {
478             if (ImageCancelButton.Focused)
479             {
480                 ImagefilePathText.CausesValidation = false;
481                 return;
482             }
483
484             ValidateNewFileMediaItem(ImagefilePathText.Text.Trim(), AlternativeTextBox.Text.Trim(), false);
485         }
486
487         private void ImageFromSelectedFile(IMediaItem item, bool noMsgBox)
488         {
489             ImageFromSelectedFile(-1, item, noMsgBox);
490         }
491
492         private void ImageFromSelectedFile(int index, IMediaItem item, bool noMsgBox)
493         {
494             var valid = false;
495
496             try
497             {
498                 var imageService = this.SelectedService;
499                 if (imageService == null) return;
500
501                 var selectedIndex = ImagePageCombo.SelectedIndex;
502                 if (index < 0) index = selectedIndex;
503
504                 if (index >= ImagePageCombo.Items.Count)
505                     throw new ArgumentOutOfRangeException(nameof(index));
506
507                 var isSelectedPage = (index == selectedIndex);
508
509                 if (isSelectedPage)
510                     this.ClearImageSelectedPicture();
511
512                 if (item == null || string.IsNullOrEmpty(item.Path)) return;
513
514                 try
515                 {
516                     var ext = item.Extension;
517                     var size = item.Size;
518
519                     if (!imageService.CheckFileExtension(ext))
520                     {
521                         //画像以外の形式
522                         if (!noMsgBox)
523                         {
524                             MessageBox.Show(
525                                 string.Format(Properties.Resources.PostPictureWarn3, this.ServiceName, MakeAvailableServiceText(ext, size), ext, item.Name),
526                                 Properties.Resources.PostPictureWarn4,
527                                 MessageBoxButtons.OK,
528                                 MessageBoxIcon.Warning);
529                         }
530                         return;
531                     }
532
533                     if (!imageService.CheckFileSize(ext, size))
534                     {
535                         // ファイルサイズが大きすぎる
536                         if (!noMsgBox)
537                         {
538                             MessageBox.Show(
539                                 string.Format(Properties.Resources.PostPictureWarn5, this.ServiceName, MakeAvailableServiceText(ext, size), item.Name),
540                                 Properties.Resources.PostPictureWarn4,
541                                 MessageBoxButtons.OK,
542                                 MessageBoxIcon.Warning);
543                         }
544                         return;
545                     }
546
547                     if (item.IsImage)
548                     {
549                         if (isSelectedPage)
550                             ImageSelectedPicture.Image = item.CreateImage();
551                         SetImagePage(index, item, MyCommon.UploadFileType.Picture);
552                     }
553                     else
554                     {
555                         SetImagePage(index, item, MyCommon.UploadFileType.MultiMedia);
556                     }
557
558                     valid = true;  //正常終了
559                 }
560                 catch (FileNotFoundException)
561                 {
562                     if (!noMsgBox) MessageBox.Show("File not found.");
563                 }
564                 catch (Exception)
565                 {
566                     if (!noMsgBox) MessageBox.Show("The type of this file is not image.");
567                 }
568             }
569             finally
570             {
571                 if (!valid)
572                 {
573                     ClearImagePage(index);
574                     DisposeMediaItem(item);
575                 }
576             }
577         }
578
579         private string MakeAvailableServiceText(string ext, long fileSize)
580         {
581             var text = string.Join(", ",
582                 ImageServiceCombo.Items.Cast<string>()
583                     .Where(serviceName =>
584                         !string.IsNullOrEmpty(serviceName) &&
585                         this.pictureService[serviceName].CheckFileExtension(ext) &&
586                         this.pictureService[serviceName].CheckFileSize(ext, fileSize)));
587
588             if (string.IsNullOrEmpty(text))
589                 return Properties.Resources.PostPictureWarn6;
590
591             return text;
592         }
593
594         private void ClearImageSelectedPicture()
595         {
596             var oldImage = this.ImageSelectedPicture.Image;
597             this.ImageSelectedPicture.Image = null;
598             oldImage?.Dispose();
599
600             this.ImageSelectedPicture.ShowInitialImage();
601         }
602
603         private void ImageCancelButton_Click(object sender, EventArgs e)
604         {
605             EndSelection();
606         }
607
608         private void ImageSelection_KeyDown(object sender, KeyEventArgs e)
609         {
610             if (e.KeyCode == Keys.Escape)
611             {
612                 EndSelection();
613             }
614         }
615
616         private void ImageSelection_KeyPress(object sender, KeyPressEventArgs e)
617         {
618             if (Convert.ToInt32(e.KeyChar) == 0x1B)
619             {
620                 ImagefilePathText.CausesValidation = false;
621                 e.Handled = true;
622             }
623         }
624
625         private void ImageSelection_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
626         {
627             if (e.KeyCode == Keys.Escape)
628             {
629                 ImagefilePathText.CausesValidation = false;
630             }
631         }
632
633         private void SetImageServiceCombo()
634         {
635             using (ControlTransaction.Update(ImageServiceCombo))
636             {
637                 string svc = "";
638                 if (ImageServiceCombo.SelectedIndex > -1) svc = ImageServiceCombo.Text;
639                 ImageServiceCombo.Items.Clear();
640
641                 // Add service names to combobox
642                 foreach (var key in pictureService.Keys)
643                 {
644                     ImageServiceCombo.Items.Add(key);
645                 }
646
647                 SelectImageServiceComboItem(svc);
648             }
649         }
650
651         private void SelectImageServiceComboItem(string svc, int? index = null)
652         {
653             int idx;
654             if (string.IsNullOrEmpty(svc))
655             {
656                 idx = index ?? 0;
657             }
658             else
659             {
660                 idx = ImageServiceCombo.Items.IndexOf(svc);
661
662                 // svc が空白以外かつ存在しないサービス名の場合は Twitter を選択させる
663                 // (廃止されたサービスを選択していた場合の対応)
664                 if (idx == -1) idx = 0;
665             }
666
667             try
668             {
669                 ImageServiceCombo.SelectedIndex = idx;
670             }
671             catch (ArgumentOutOfRangeException)
672             {
673                 ImageServiceCombo.SelectedIndex = 0;
674             }
675
676             this.UpdateAltTextPanelVisible();
677         }
678
679         private void UpdateAltTextPanelVisible()
680             => this.AlternativeTextPanel.Visible = this.SelectedService.CanUseAltText;
681
682         private void ImageServiceCombo_SelectedIndexChanged(object sender, EventArgs e)
683         {
684             if (this.Visible)
685             {
686                 var imageService = this.SelectedService;
687                 if (imageService != null)
688                 {
689                     this.UpdateAltTextPanelVisible();
690
691                     if (ImagePageCombo.Items.Count > 0)
692                     {
693                         // 画像が選択された投稿先に対応しているかをチェックする
694                         // TODO: 複数の選択済み画像があるなら、できれば全てを再チェックしたほうがいい
695                         if (this.ServiceName == "Twitter")
696                         {
697                             ValidateSelectedImagePage();
698                         }
699                         else
700                         {
701                             if (ImagePageCombo.Items.Count > 1)
702                             {
703                                 // 複数の選択済み画像のうち、1枚目のみを残す
704                                 SetImagePageCombo((SelectedMedia)ImagePageCombo.Items[0]);
705                             }
706                             else
707                             {
708                                 ImagePageCombo.Enabled = false;
709                                 var valid = false;
710
711                                 try
712                                 {
713                                     var item = ((SelectedMedia)ImagePageCombo.Items[0]).Item;
714                                     if (item != null)
715                                     {
716                                         var ext = item.Extension;
717                                         if (imageService.CheckFileExtension(ext) &&
718                                             imageService.CheckFileSize(ext, item.Size))
719                                         {
720                                             valid = true;
721                                         }
722                                     }
723                                 }
724                                 catch
725                                 {
726                                 }
727                                 finally
728                                 {
729                                     if (!valid)
730                                     {
731                                         ClearImageSelectedPicture();
732                                         ClearSelectedImagePage();
733                                     }
734                                 }
735                             }
736                         }
737                     }
738                 }
739             }
740
741             this.SelectedServiceChanged?.Invoke(this, EventArgs.Empty);
742         }
743
744         private void SetImagePageCombo(SelectedMedia media = null)
745         {
746             using (ControlTransaction.Update(ImagePageCombo))
747             {
748                 ImagePageCombo.Enabled = false;
749
750                 foreach (SelectedMedia oldMedia in ImagePageCombo.Items)
751                 {
752                     if (oldMedia == null || oldMedia == media) continue;
753                     DisposeMediaItem(oldMedia.Item);
754                 }
755                 ImagePageCombo.Items.Clear();
756
757                 if (media == null)
758                     media = new SelectedMedia("1");
759
760                 ImagePageCombo.Items.Add(media);
761                 ImagefilePathText.Text = media.Path;
762                 AlternativeTextBox.Text = media.AltText;
763
764                 ImagePageCombo.SelectedIndex = 0;
765             }
766         }
767
768         private void AddNewImagePage(int selectedIndex)
769         {
770             var service = this.SelectedService;
771             if (service == null) return;
772
773             if (selectedIndex < service.MaxMediaCount - 1)
774             {
775                 // 投稿先の投稿可能枚数まで選択できるようにする
776                 var count = ImagePageCombo.Items.Count;
777                 if (selectedIndex == count - 1)
778                 {
779                     count++;
780                     ImagePageCombo.Items.Add(new SelectedMedia(count.ToString()));
781                     ImagePageCombo.Enabled = true;
782                 }
783             }
784         }
785
786         private void SetSelectedImagePage(IMediaItem item, MyCommon.UploadFileType type)
787         {
788             SetImagePage(-1, item, type);
789         }
790
791         private void SetImagePage(int index, IMediaItem item, MyCommon.UploadFileType type)
792         {
793             var selectedIndex = ImagePageCombo.SelectedIndex;
794             if (index < 0) index = selectedIndex;
795
796             var media = (SelectedMedia)ImagePageCombo.Items[index];
797             if (media.Item != item)
798             {
799                 DisposeMediaItem(media.Item);
800                 media.Item = item;
801             }
802             media.Type = type;
803
804             AddNewImagePage(index);
805         }
806
807         private void ClearSelectedImagePage()
808         {
809             ClearImagePage(-1);
810         }
811
812         private void ClearImagePage(int index)
813         {
814             var selectedIndex = ImagePageCombo.SelectedIndex;
815             if (index < 0) index = selectedIndex;
816
817             var media = (SelectedMedia)ImagePageCombo.Items[index];
818             DisposeMediaItem(media.Item);
819             media.Item = null;
820             media.Type = MyCommon.UploadFileType.Invalid;
821
822             if (index == selectedIndex)
823             {
824                 ImagefilePathText.Text = "";
825                 AlternativeTextBox.Text = "";
826             }
827         }
828
829         private void ValidateSelectedImagePage()
830         {
831             var idx = ImagePageCombo.SelectedIndex;
832             var media = (SelectedMedia)ImagePageCombo.Items[idx];
833             ImageServiceCombo.Enabled = (idx == 0);  // idx == 0 以外では投稿先サービスを選べないようにする
834             ImagefilePathText.Text = media.Path;
835             AlternativeTextBox.Text = media.AltText;
836             ImageFromSelectedFile(media.Item, true);
837         }
838
839         private void ImagePageCombo_SelectedIndexChanged(object sender, EventArgs e)
840         {
841             ValidateSelectedImagePage();
842         }
843
844         private void AlternativeTextBox_Validating(object sender, CancelEventArgs e)
845         {
846             var imageFilePath = this.ImagefilePathText.Text.Trim();
847             var altText = this.AlternativeTextBox.Text.Trim();
848             this.ValidateNewFileMediaItem(imageFilePath, altText, noMsgBox: false);
849         }
850     }
851 }