1 // OpenTween - Client of Twitter
2 // Copyright (c) 2014 spx (@5px)
3 // All rights reserved.
5 // This file is part of OpenTween.
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)
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
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.
23 using System.Collections.Generic;
24 using System.ComponentModel;
30 using System.Threading.Tasks;
31 using System.Windows.Forms;
32 using OpenTween.Connection;
36 public partial class MediaSelector : UserControl
38 public event EventHandler BeginSelecting;
39 public event EventHandler EndSelecting;
41 public event EventHandler FilePickDialogOpening;
42 public event EventHandler FilePickDialogClosed;
44 public event EventHandler SelectedServiceChanged;
47 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
48 public OpenFileDialog FilePickDialog { get; set; }
54 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
55 public string ServiceName
57 get { return ImageServiceCombo.Text; }
61 /// 選択されている投稿先を示すインデックスを取得する。
64 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
65 public int ServiceIndex
67 get { return ImageServiceCombo.SelectedIndex; }
71 /// 指定された投稿先名から、作成済みの IMultimediaShareService インスタンスを取得する。
73 public IMultimediaShareService GetService(string serviceName)
75 IMultimediaShareService service;
76 this.pictureService.TryGetValue(serviceName, out service);
80 private class SelectedMedia
82 public string Path { get; set; }
83 public MyCommon.UploadFileType Type { get; set; }
84 public string Text { get; set; }
86 public SelectedMedia(string path, MyCommon.UploadFileType type, string text)
93 public SelectedMedia(string text)
94 : this("", MyCommon.UploadFileType.Invalid, text)
100 get { return this.Type != MyCommon.UploadFileType.Invalid; }
103 public override string ToString()
109 private Dictionary<string, IMultimediaShareService> pictureService;
111 private void CreateServices(Twitter tw)
113 if (this.pictureService != null) this.pictureService.Clear();
114 this.pictureService = null;
116 this.pictureService = new Dictionary<string, IMultimediaShareService> {
117 {"TwitPic", new TwitPic(tw)},
118 {"img.ly", new imgly(tw)},
119 {"yfrog", new yfrog(tw)},
120 {"Twitter", new TwitterPhoto(tw)},
121 {"ついっぷるフォト", new TwipplePhoto(tw)},
122 {"Imgur", new Imgur(tw)},
126 public MediaSelector()
128 InitializeComponent();
130 this.ImageSelectedPicture.InitialImage = Properties.Resources.InitialImage;
136 public void Initialize(Twitter tw, string svc, int? index = null)
140 SetImageServiceCombo();
143 SelectImageServiceComboItem(svc, index);
149 public void Reset(Twitter tw)
153 SetImageServiceCombo();
157 /// 指定されたファイルの投稿に対応した投稿先があるかどうかを示す値を取得する。
159 public bool HasUploadableService(string fileName)
161 FileInfo fl = new FileInfo(fileName);
162 string ext = fl.Extension;
164 var serviceName = this.ServiceName;
165 if (!string.IsNullOrEmpty(serviceName) &&
166 this.pictureService[serviceName].CheckValidFilesize(ext, fl.Length))
171 foreach (string svc in ImageServiceCombo.Items)
173 if (!string.IsNullOrEmpty(svc) &&
174 this.pictureService[svc].CheckValidFilesize(ext, fl.Length))
184 /// 投稿するファイルとその投稿先を選択するためのコントロールを表示する。
185 /// D&Dをサポートする場合は引数にドロップされたファイル名を指定して呼ぶこと。
187 public void BeginSelection(string fileName = null)
189 if (!string.IsNullOrEmpty(fileName))
193 // 非表示時のファイル指定は新規選択として扱う
196 if (this.BeginSelecting != null)
197 this.BeginSelecting(this, EventArgs.Empty);
202 ImagefilePathText.Text = fileName;
203 ImageFromSelectedFile(false);
209 if (this.BeginSelecting != null)
210 this.BeginSelecting(this, EventArgs.Empty);
214 ImageFromSelectedFile(true);
215 ImagefilePathText.Focus();
221 /// 選択処理を終了してコントロールを隠す。
223 public void EndSelection()
227 ImagefilePathText.CausesValidation = false;
229 if (this.EndSelecting != null)
230 this.EndSelecting(this, EventArgs.Empty);
232 this.Visible = false;
233 this.Enabled = false;
234 ClearImageSelectedPicture();
236 ImagefilePathText.CausesValidation = true;
241 /// 選択された投稿先名と投稿ファイル名を取得する。
243 public bool TryGetSelectedMedia(out string imageService, out string[] imagePaths)
245 var validPaths = ImagePageCombo.Items.Cast<SelectedMedia>()
246 .Where(x => x.IsValid).Select(x => x.Path).ToArray();
248 if (validPaths.Length > 0 &&
249 ImageServiceCombo.SelectedIndex > -1)
251 var serviceName = this.ServiceName;
252 if (MessageBox.Show(string.Format(Properties.Resources.PostPictureConfirm1, serviceName, validPaths.Length),
253 Properties.Resources.PostPictureConfirm2,
254 MessageBoxButtons.OKCancel,
255 MessageBoxIcon.Question,
256 MessageBoxDefaultButton.Button1)
259 imageService = serviceName;
260 imagePaths = validPaths;
268 MessageBox.Show(Properties.Resources.PostPictureWarn1, Properties.Resources.PostPictureWarn2);
277 private void FilePickButton_Click(object sender, EventArgs e)
279 if (FilePickDialog == null || string.IsNullOrEmpty(this.ServiceName)) return;
280 FilePickDialog.Filter = this.pictureService[this.ServiceName].GetFileOpenDialogFilter();
281 FilePickDialog.Title = Properties.Resources.PickPictureDialog1;
282 FilePickDialog.FileName = "";
284 if (this.FilePickDialogOpening != null)
285 this.FilePickDialogOpening(this, EventArgs.Empty);
289 if (FilePickDialog.ShowDialog() == DialogResult.Cancel) return;
293 if (this.FilePickDialogClosed != null)
294 this.FilePickDialogClosed(this, EventArgs.Empty);
297 ImagefilePathText.Text = FilePickDialog.FileName;
298 ImageFromSelectedFile(false);
301 private void ImagefilePathText_Validating(object sender, CancelEventArgs e)
303 if (ImageCancelButton.Focused)
305 ImagefilePathText.CausesValidation = false;
309 ImageFromSelectedFile(false);
312 private void ImageFromSelectedFile(bool suppressMsgBox)
314 this.ClearImageSelectedPicture();
318 ImagefilePathText.Text = ImagefilePathText.Text.Trim();
319 var fileName = ImagefilePathText.Text;
320 var serviceName = this.ServiceName;
321 if (string.IsNullOrEmpty(fileName) || string.IsNullOrEmpty(serviceName))
323 ClearSelectedImagePage();
327 FileInfo fl = new FileInfo(fileName);
328 string ext = fl.Extension;
329 var imageService = this.pictureService[serviceName];
331 if (!imageService.CheckValidExtension(ext))
334 ClearSelectedImagePage();
338 string.Format(Properties.Resources.PostPictureWarn3, serviceName, MakeAvailableServiceText(ext, fl.Length), ext),
339 Properties.Resources.PostPictureWarn4,
340 MessageBoxButtons.OK,
341 MessageBoxIcon.Warning);
346 if (!imageService.CheckValidFilesize(ext, fl.Length))
349 ClearSelectedImagePage();
353 string.Format(Properties.Resources.PostPictureWarn5, serviceName, MakeAvailableServiceText(ext, fl.Length)),
354 Properties.Resources.PostPictureWarn4,
355 MessageBoxButtons.OK,
356 MessageBoxIcon.Warning);
361 switch (imageService.GetFileType(ext))
363 case MyCommon.UploadFileType.Picture:
364 using (var fs = File.OpenRead(fileName))
366 ImageSelectedPicture.Image = MemoryImage.CopyFromStream(fs);
368 SetSelectedImagePage(fileName, MyCommon.UploadFileType.Picture);
370 case MyCommon.UploadFileType.MultiMedia:
371 SetSelectedImagePage(fileName, MyCommon.UploadFileType.MultiMedia);
374 ClearSelectedImagePage();
378 catch (FileNotFoundException)
380 ClearSelectedImagePage();
381 if (!suppressMsgBox) MessageBox.Show("File not found.");
385 ClearSelectedImagePage();
386 if (!suppressMsgBox) MessageBox.Show("The type of this file is not image.");
390 private string MakeAvailableServiceText(string ext, long fileSize)
392 var text = string.Join(", ",
393 ImageServiceCombo.Items.Cast<string>()
394 .Where(x => !string.IsNullOrEmpty(x) && this.pictureService[x].CheckValidFilesize(ext, fileSize)));
396 if (string.IsNullOrEmpty(text))
397 return Properties.Resources.PostPictureWarn6;
402 private void ClearImageSelectedPicture()
404 var oldImage = this.ImageSelectedPicture.Image;
405 if (oldImage != null)
407 this.ImageSelectedPicture.Image = null;
411 this.ImageSelectedPicture.ShowInitialImage();
414 private void ImageCancelButton_Click(object sender, EventArgs e)
419 private void ImageSelection_KeyDown(object sender, KeyEventArgs e)
421 if (e.KeyCode == Keys.Escape)
427 private void ImageSelection_KeyPress(object sender, KeyPressEventArgs e)
429 if (Convert.ToInt32(e.KeyChar) == 0x1B)
431 ImagefilePathText.CausesValidation = false;
436 private void ImageSelection_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
438 if (e.KeyCode == Keys.Escape)
440 ImagefilePathText.CausesValidation = false;
444 private void SetImageServiceCombo()
446 using (ControlTransaction.Update(ImageServiceCombo))
449 if (ImageServiceCombo.SelectedIndex > -1) svc = ImageServiceCombo.Text;
450 ImageServiceCombo.Items.Clear();
452 // Add service names to combobox
453 foreach (var key in pictureService.Keys)
455 ImageServiceCombo.Items.Add(key);
458 SelectImageServiceComboItem(svc);
462 private void SelectImageServiceComboItem(string svc, int? index = null)
465 if (string.IsNullOrEmpty(svc))
471 idx = ImageServiceCombo.Items.IndexOf(svc);
472 if (idx == -1) idx = index ?? 0;
477 ImageServiceCombo.SelectedIndex = idx;
479 catch (ArgumentOutOfRangeException)
481 ImageServiceCombo.SelectedIndex = 0;
485 private void ImageServiceCombo_SelectedIndexChanged(object sender, EventArgs e)
489 var serviceName = this.ServiceName;
490 if (!string.IsNullOrEmpty(serviceName))
492 if (ImagePageCombo.Items.Count > 0)
494 // 画像が選択された投稿先に対応しているかをチェックする
495 // TODO: 複数の選択済み画像があるなら、できれば全てを再チェックしたほうがいい
496 if (serviceName.Equals("Twitter"))
498 ValidateSelectedImagePage();
502 if (ImagePageCombo.Items.Count > 1)
504 // 複数の選択済み画像のうち、1枚目のみを残す
505 SetImagePageCombo((SelectedMedia)ImagePageCombo.Items[0]);
509 ImagePageCombo.Enabled = false;
513 FileInfo fi = new FileInfo(ImagefilePathText.Text.Trim());
514 string ext = fi.Extension;
515 var imageService = this.pictureService[serviceName];
516 if (!imageService.CheckValidFilesize(ext, fi.Length))
518 ClearImageSelectedPicture();
519 ClearSelectedImagePage();
524 ClearImageSelectedPicture();
525 ClearSelectedImagePage();
533 if (this.SelectedServiceChanged != null)
534 this.SelectedServiceChanged(this, EventArgs.Empty);
537 private void SetImagePageCombo(SelectedMedia media = null)
539 using (ControlTransaction.Update(ImagePageCombo))
541 ImagePageCombo.Enabled = false;
542 ImagePageCombo.Items.Clear();
545 ImagePageCombo.Items.Add(media);
546 ImagefilePathText.Text = media.Path;
550 ImagePageCombo.Items.Add(new SelectedMedia("1"));
551 ImagefilePathText.Text = "";
553 ImagePageCombo.SelectedIndex = 0;
557 private void AddNewImagePage(int selectedIndex)
559 if (this.ServiceName.Equals("Twitter") && selectedIndex < 3)
561 // 投稿先が Twitter であれば、最大 4 枚まで選択できるようにする
562 var count = ImagePageCombo.Items.Count;
563 if (selectedIndex == count - 1)
566 ImagePageCombo.Items.Add(new SelectedMedia(count.ToString()));
567 ImagePageCombo.Enabled = true;
572 private void SetSelectedImagePage(string path, MyCommon.UploadFileType type)
574 var idx = ImagePageCombo.SelectedIndex;
575 var item = (SelectedMedia)ImagePageCombo.Items[idx];
579 AddNewImagePage(idx);
582 private void ClearSelectedImagePage()
584 var item = (SelectedMedia)ImagePageCombo.SelectedItem;
586 item.Type = MyCommon.UploadFileType.Invalid;
587 ImagefilePathText.Text = "";
590 private void ValidateSelectedImagePage()
592 var idx = ImagePageCombo.SelectedIndex;
593 var item = (SelectedMedia)ImagePageCombo.Items[idx];
594 ImageServiceCombo.Enabled = (idx == 0); // idx == 0 以外では投稿先サービスを選べないようにする
595 ImagefilePathText.Text = item.Path;
596 ImageFromSelectedFile(true);
599 private void ImagePageCombo_SelectedIndexChanged(object sender, EventArgs e)
601 ValidateSelectedImagePage();