OSDN Git Service

画像投稿先のサービスから「img.ly」を削除
[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             EndSelection();
386             imageService = null;
387             mediaItems = null;
388             return false;
389         }
390
391         private MemoryImageMediaItem CreateMemoryImageMediaItem(Image image, bool noMsgBox)
392         {
393             if (image == null) return null;
394
395             MemoryImage memoryImage = null;
396             try
397             {
398                 // image から png 形式の MemoryImage を生成
399                 memoryImage = MemoryImage.CopyFromImage(image);
400
401                 return new MemoryImageMediaItem(memoryImage);
402             }
403             catch
404             {
405                 memoryImage?.Dispose();
406
407                 if (!noMsgBox) MessageBox.Show("Unable to create MemoryImage.");
408                 return null;
409             }
410         }
411
412         private IMediaItem CreateFileMediaItem(string path, bool noMsgBox)
413         {
414             if (string.IsNullOrEmpty(path)) return null;
415
416             try
417             {
418                 return new FileMediaItem(path);
419             }
420             catch
421             {
422                 if (!noMsgBox) MessageBox.Show("Invalid file path: " + path);
423                 return null;
424             }
425         }
426
427         private void ValidateNewFileMediaItem(string path, string altText, bool noMsgBox)
428         {
429             var media = (SelectedMedia)ImagePageCombo.SelectedItem;
430             var item = media.Item;
431
432             if (path != media.Path)
433             {
434                 DisposeMediaItem(media.Item);
435                 media.Item = null;
436
437                 item = CreateFileMediaItem(path, noMsgBox);
438             }
439
440             if (item != null)
441                 item.AltText = altText;
442
443             ImagefilePathText.Text = path;
444             AlternativeTextBox.Text = altText;
445             ImageFromSelectedFile(item, noMsgBox);
446         }
447
448         private void DisposeMediaItem(IMediaItem item)
449         {
450             var disposableItem = item as IDisposable;
451             disposableItem?.Dispose();
452         }
453
454         private void FilePickButton_Click(object sender, EventArgs e)
455         {
456             var service = this.SelectedService;
457
458             if (FilePickDialog == null || service == null) return;
459             FilePickDialog.Filter = service.SupportedFormatsStrForDialog;
460             FilePickDialog.Title = Properties.Resources.PickPictureDialog1;
461             FilePickDialog.FileName = "";
462
463             this.FilePickDialogOpening?.Invoke(this, EventArgs.Empty);
464
465             try
466             {
467                 if (FilePickDialog.ShowDialog() == DialogResult.Cancel) return;
468             }
469             finally
470             {
471                 this.FilePickDialogClosed?.Invoke(this, EventArgs.Empty);
472             }
473
474             ValidateNewFileMediaItem(FilePickDialog.FileName, AlternativeTextBox.Text.Trim(), false);
475         }
476
477         private void ImagefilePathText_Validating(object sender, CancelEventArgs e)
478         {
479             if (ImageCancelButton.Focused)
480             {
481                 ImagefilePathText.CausesValidation = false;
482                 return;
483             }
484
485             ValidateNewFileMediaItem(ImagefilePathText.Text.Trim(), AlternativeTextBox.Text.Trim(), false);
486         }
487
488         private void ImageFromSelectedFile(IMediaItem item, bool noMsgBox)
489         {
490             ImageFromSelectedFile(-1, item, noMsgBox);
491         }
492
493         private void ImageFromSelectedFile(int index, IMediaItem item, bool noMsgBox)
494         {
495             var valid = false;
496
497             try
498             {
499                 var imageService = this.SelectedService;
500                 if (imageService == null) return;
501
502                 var selectedIndex = ImagePageCombo.SelectedIndex;
503                 if (index < 0) index = selectedIndex;
504
505                 if (index >= ImagePageCombo.Items.Count)
506                     throw new ArgumentOutOfRangeException(nameof(index));
507
508                 var isSelectedPage = (index == selectedIndex);
509
510                 if (isSelectedPage)
511                     this.ClearImageSelectedPicture();
512
513                 if (item == null || string.IsNullOrEmpty(item.Path)) return;
514
515                 try
516                 {
517                     var ext = item.Extension;
518                     var size = item.Size;
519
520                     if (!imageService.CheckFileExtension(ext))
521                     {
522                         //画像以外の形式
523                         if (!noMsgBox)
524                         {
525                             MessageBox.Show(
526                                 string.Format(Properties.Resources.PostPictureWarn3, this.ServiceName, MakeAvailableServiceText(ext, size), ext, item.Name),
527                                 Properties.Resources.PostPictureWarn4,
528                                 MessageBoxButtons.OK,
529                                 MessageBoxIcon.Warning);
530                         }
531                         return;
532                     }
533
534                     if (!imageService.CheckFileSize(ext, size))
535                     {
536                         // ファイルサイズが大きすぎる
537                         if (!noMsgBox)
538                         {
539                             MessageBox.Show(
540                                 string.Format(Properties.Resources.PostPictureWarn5, this.ServiceName, MakeAvailableServiceText(ext, size), item.Name),
541                                 Properties.Resources.PostPictureWarn4,
542                                 MessageBoxButtons.OK,
543                                 MessageBoxIcon.Warning);
544                         }
545                         return;
546                     }
547
548                     if (item.IsImage)
549                     {
550                         if (isSelectedPage)
551                             ImageSelectedPicture.Image = item.CreateImage();
552                         SetImagePage(index, item, MyCommon.UploadFileType.Picture);
553                     }
554                     else
555                     {
556                         SetImagePage(index, item, MyCommon.UploadFileType.MultiMedia);
557                     }
558
559                     valid = true;  //正常終了
560                 }
561                 catch (FileNotFoundException)
562                 {
563                     if (!noMsgBox) MessageBox.Show("File not found.");
564                 }
565                 catch (Exception)
566                 {
567                     if (!noMsgBox) MessageBox.Show("The type of this file is not image.");
568                 }
569             }
570             finally
571             {
572                 if (!valid)
573                 {
574                     ClearImagePage(index);
575                     DisposeMediaItem(item);
576                 }
577             }
578         }
579
580         private string MakeAvailableServiceText(string ext, long fileSize)
581         {
582             var text = string.Join(", ",
583                 ImageServiceCombo.Items.Cast<string>()
584                     .Where(serviceName =>
585                         !string.IsNullOrEmpty(serviceName) &&
586                         this.pictureService[serviceName].CheckFileExtension(ext) &&
587                         this.pictureService[serviceName].CheckFileSize(ext, fileSize)));
588
589             if (string.IsNullOrEmpty(text))
590                 return Properties.Resources.PostPictureWarn6;
591
592             return text;
593         }
594
595         private void ClearImageSelectedPicture()
596         {
597             var oldImage = this.ImageSelectedPicture.Image;
598             this.ImageSelectedPicture.Image = null;
599             oldImage?.Dispose();
600
601             this.ImageSelectedPicture.ShowInitialImage();
602         }
603
604         private void ImageCancelButton_Click(object sender, EventArgs e)
605         {
606             EndSelection();
607         }
608
609         private void ImageSelection_KeyDown(object sender, KeyEventArgs e)
610         {
611             if (e.KeyCode == Keys.Escape)
612             {
613                 EndSelection();
614             }
615         }
616
617         private void ImageSelection_KeyPress(object sender, KeyPressEventArgs e)
618         {
619             if (Convert.ToInt32(e.KeyChar) == 0x1B)
620             {
621                 ImagefilePathText.CausesValidation = false;
622                 e.Handled = true;
623             }
624         }
625
626         private void ImageSelection_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
627         {
628             if (e.KeyCode == Keys.Escape)
629             {
630                 ImagefilePathText.CausesValidation = false;
631             }
632         }
633
634         private void SetImageServiceCombo()
635         {
636             using (ControlTransaction.Update(ImageServiceCombo))
637             {
638                 string svc = "";
639                 if (ImageServiceCombo.SelectedIndex > -1) svc = ImageServiceCombo.Text;
640                 ImageServiceCombo.Items.Clear();
641
642                 // Add service names to combobox
643                 foreach (var key in pictureService.Keys)
644                 {
645                     ImageServiceCombo.Items.Add(key);
646                 }
647
648                 SelectImageServiceComboItem(svc);
649             }
650         }
651
652         private void SelectImageServiceComboItem(string svc, int? index = null)
653         {
654             int idx;
655             if (string.IsNullOrEmpty(svc))
656             {
657                 idx = index ?? 0;
658             }
659             else
660             {
661                 idx = ImageServiceCombo.Items.IndexOf(svc);
662                 if (idx == -1) idx = index ?? 0;
663             }
664
665             try
666             {
667                 ImageServiceCombo.SelectedIndex = idx;
668             }
669             catch (ArgumentOutOfRangeException)
670             {
671                 ImageServiceCombo.SelectedIndex = 0;
672             }
673
674             this.UpdateAltTextPanelVisible();
675         }
676
677         private void UpdateAltTextPanelVisible()
678             => this.AlternativeTextPanel.Visible = this.SelectedService.CanUseAltText;
679
680         private void ImageServiceCombo_SelectedIndexChanged(object sender, EventArgs e)
681         {
682             if (this.Visible)
683             {
684                 var imageService = this.SelectedService;
685                 if (imageService != null)
686                 {
687                     this.UpdateAltTextPanelVisible();
688
689                     if (ImagePageCombo.Items.Count > 0)
690                     {
691                         // 画像が選択された投稿先に対応しているかをチェックする
692                         // TODO: 複数の選択済み画像があるなら、できれば全てを再チェックしたほうがいい
693                         if (this.ServiceName == "Twitter")
694                         {
695                             ValidateSelectedImagePage();
696                         }
697                         else
698                         {
699                             if (ImagePageCombo.Items.Count > 1)
700                             {
701                                 // 複数の選択済み画像のうち、1枚目のみを残す
702                                 SetImagePageCombo((SelectedMedia)ImagePageCombo.Items[0]);
703                             }
704                             else
705                             {
706                                 ImagePageCombo.Enabled = false;
707                                 var valid = false;
708
709                                 try
710                                 {
711                                     var item = ((SelectedMedia)ImagePageCombo.Items[0]).Item;
712                                     if (item != null)
713                                     {
714                                         var ext = item.Extension;
715                                         if (imageService.CheckFileExtension(ext) &&
716                                             imageService.CheckFileSize(ext, item.Size))
717                                         {
718                                             valid = true;
719                                         }
720                                     }
721                                 }
722                                 catch
723                                 {
724                                 }
725                                 finally
726                                 {
727                                     if (!valid)
728                                     {
729                                         ClearImageSelectedPicture();
730                                         ClearSelectedImagePage();
731                                     }
732                                 }
733                             }
734                         }
735                     }
736                 }
737             }
738
739             this.SelectedServiceChanged?.Invoke(this, EventArgs.Empty);
740         }
741
742         private void SetImagePageCombo(SelectedMedia media = null)
743         {
744             using (ControlTransaction.Update(ImagePageCombo))
745             {
746                 ImagePageCombo.Enabled = false;
747
748                 foreach (SelectedMedia oldMedia in ImagePageCombo.Items)
749                 {
750                     if (oldMedia == null || oldMedia == media) continue;
751                     DisposeMediaItem(oldMedia.Item);
752                 }
753                 ImagePageCombo.Items.Clear();
754
755                 if (media == null)
756                     media = new SelectedMedia("1");
757
758                 ImagePageCombo.Items.Add(media);
759                 ImagefilePathText.Text = media.Path;
760                 AlternativeTextBox.Text = media.AltText;
761
762                 ImagePageCombo.SelectedIndex = 0;
763             }
764         }
765
766         private void AddNewImagePage(int selectedIndex)
767         {
768             var service = this.SelectedService;
769             if (service == null) return;
770
771             if (selectedIndex < service.MaxMediaCount - 1)
772             {
773                 // 投稿先の投稿可能枚数まで選択できるようにする
774                 var count = ImagePageCombo.Items.Count;
775                 if (selectedIndex == count - 1)
776                 {
777                     count++;
778                     ImagePageCombo.Items.Add(new SelectedMedia(count.ToString()));
779                     ImagePageCombo.Enabled = true;
780                 }
781             }
782         }
783
784         private void SetSelectedImagePage(IMediaItem item, MyCommon.UploadFileType type)
785         {
786             SetImagePage(-1, item, type);
787         }
788
789         private void SetImagePage(int index, IMediaItem item, MyCommon.UploadFileType type)
790         {
791             var selectedIndex = ImagePageCombo.SelectedIndex;
792             if (index < 0) index = selectedIndex;
793
794             var media = (SelectedMedia)ImagePageCombo.Items[index];
795             if (media.Item != item)
796             {
797                 DisposeMediaItem(media.Item);
798                 media.Item = item;
799             }
800             media.Type = type;
801
802             AddNewImagePage(index);
803         }
804
805         private void ClearSelectedImagePage()
806         {
807             ClearImagePage(-1);
808         }
809
810         private void ClearImagePage(int index)
811         {
812             var selectedIndex = ImagePageCombo.SelectedIndex;
813             if (index < 0) index = selectedIndex;
814
815             var media = (SelectedMedia)ImagePageCombo.Items[index];
816             DisposeMediaItem(media.Item);
817             media.Item = null;
818             media.Type = MyCommon.UploadFileType.Invalid;
819
820             if (index == selectedIndex)
821             {
822                 ImagefilePathText.Text = "";
823                 AlternativeTextBox.Text = "";
824             }
825         }
826
827         private void ValidateSelectedImagePage()
828         {
829             var idx = ImagePageCombo.SelectedIndex;
830             var media = (SelectedMedia)ImagePageCombo.Items[idx];
831             ImageServiceCombo.Enabled = (idx == 0);  // idx == 0 以外では投稿先サービスを選べないようにする
832             ImagefilePathText.Text = media.Path;
833             AlternativeTextBox.Text = media.AltText;
834             ImageFromSelectedFile(media.Item, true);
835         }
836
837         private void ImagePageCombo_SelectedIndexChanged(object sender, EventArgs e)
838         {
839             ValidateSelectedImagePage();
840         }
841
842         private void AlternativeTextBox_Validating(object sender, CancelEventArgs e)
843         {
844             var imageFilePath = this.ImagefilePathText.Text.Trim();
845             var altText = this.AlternativeTextBox.Text.Trim();
846             this.ValidateNewFileMediaItem(imageFilePath, altText, noMsgBox: false);
847         }
848     }
849 }