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;
33 using OpenTween.Connection;
37 public partial class MediaSelector : UserControl
39 public event EventHandler BeginSelecting;
40 public event EventHandler EndSelecting;
42 public event EventHandler FilePickDialogOpening;
43 public event EventHandler FilePickDialogClosed;
45 public event EventHandler SelectedServiceChanged;
48 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
49 public OpenFileDialog FilePickDialog { get; set; }
55 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
56 public string ServiceName
58 get { return ImageServiceCombo.Text; }
62 /// 選択されている投稿先を示すインデックスを取得する。
65 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
66 public int ServiceIndex
68 get { return ImageServiceCombo.SelectedIndex; }
72 /// 指定された投稿先名から、作成済みの IMediaUploadService インスタンスを取得する。
74 public IMediaUploadService GetService(string serviceName)
76 IMediaUploadService service;
77 this.pictureService.TryGetValue(serviceName, out service);
82 /// 利用可能な全ての IMediaUploadService インスタンスを取得する。
84 public ICollection<IMediaUploadService> GetServices()
86 return this.pictureService.Values;
89 private class SelectedMedia
91 public string Path { get; set; }
92 public MyCommon.UploadFileType Type { get; set; }
93 public string Text { get; set; }
95 public SelectedMedia(string path, MyCommon.UploadFileType type, string text)
102 public SelectedMedia(string text)
103 : this("", MyCommon.UploadFileType.Invalid, text)
109 get { return this.Type != MyCommon.UploadFileType.Invalid; }
112 public override string ToString()
118 private Dictionary<string, IMediaUploadService> pictureService;
120 private void CreateServices(Twitter tw, TwitterConfiguration twitterConfig)
122 if (this.pictureService != null) this.pictureService.Clear();
123 this.pictureService = null;
125 this.pictureService = new Dictionary<string, IMediaUploadService> {
126 {"TwitPic", new TwitPic(tw, twitterConfig)},
127 {"img.ly", new imgly(tw, twitterConfig)},
128 {"yfrog", new yfrog(tw, twitterConfig)},
129 {"Twitter", new TwitterPhoto(tw, twitterConfig)},
130 {"ついっぷるフォト", new TwipplePhoto(tw, twitterConfig)},
131 {"Imgur", new Imgur(tw, twitterConfig)},
135 public MediaSelector()
137 InitializeComponent();
139 this.ImageSelectedPicture.InitialImage = Properties.Resources.InitialImage;
145 public void Initialize(Twitter tw, TwitterConfiguration twitterConfig, string svc, int? index = null)
147 CreateServices(tw, twitterConfig);
149 SetImageServiceCombo();
152 SelectImageServiceComboItem(svc, index);
158 public void Reset(Twitter tw, TwitterConfiguration twitterConfig)
160 CreateServices(tw, twitterConfig);
162 SetImageServiceCombo();
166 /// 指定されたファイルの投稿に対応した投稿先があるかどうかを示す値を取得する。
168 public bool HasUploadableService(string fileName)
170 FileInfo fl = new FileInfo(fileName);
171 string ext = fl.Extension;
173 var serviceName = this.ServiceName;
174 if (!string.IsNullOrEmpty(serviceName) &&
175 this.pictureService[serviceName].CheckFileSize(ext, fl.Length))
180 foreach (string svc in ImageServiceCombo.Items)
182 if (!string.IsNullOrEmpty(svc) &&
183 this.pictureService[svc].CheckFileSize(ext, fl.Length))
193 /// 投稿するファイルとその投稿先を選択するためのコントロールを表示する。
194 /// D&Dをサポートする場合は引数にドロップされたファイル名を指定して呼ぶこと。
196 public void BeginSelection(string fileName = null)
198 if (!string.IsNullOrEmpty(fileName))
202 // 非表示時のファイル指定は新規選択として扱う
205 if (this.BeginSelecting != null)
206 this.BeginSelecting(this, EventArgs.Empty);
211 ImagefilePathText.Text = fileName;
212 ImageFromSelectedFile(false);
218 if (this.BeginSelecting != null)
219 this.BeginSelecting(this, EventArgs.Empty);
223 ImageFromSelectedFile(true);
224 ImagefilePathText.Focus();
230 /// 選択処理を終了してコントロールを隠す。
232 public void EndSelection()
236 ImagefilePathText.CausesValidation = false;
238 if (this.EndSelecting != null)
239 this.EndSelecting(this, EventArgs.Empty);
241 this.Visible = false;
242 this.Enabled = false;
243 ClearImageSelectedPicture();
245 ImagefilePathText.CausesValidation = true;
250 /// 選択された投稿先名と投稿ファイル名を取得する。
252 public bool TryGetSelectedMedia(out string imageService, out string[] imagePaths)
254 var validPaths = ImagePageCombo.Items.Cast<SelectedMedia>()
255 .Where(x => x.IsValid).Select(x => x.Path).ToArray();
257 if (validPaths.Length > 0 &&
258 ImageServiceCombo.SelectedIndex > -1)
260 var serviceName = this.ServiceName;
261 if (MessageBox.Show(string.Format(Properties.Resources.PostPictureConfirm1, serviceName, validPaths.Length),
262 Properties.Resources.PostPictureConfirm2,
263 MessageBoxButtons.OKCancel,
264 MessageBoxIcon.Question,
265 MessageBoxDefaultButton.Button1)
268 imageService = serviceName;
269 imagePaths = validPaths;
277 MessageBox.Show(Properties.Resources.PostPictureWarn1, Properties.Resources.PostPictureWarn2);
286 private void FilePickButton_Click(object sender, EventArgs e)
288 if (FilePickDialog == null || string.IsNullOrEmpty(this.ServiceName)) return;
289 FilePickDialog.Filter = this.pictureService[this.ServiceName].SupportedFormatsStrForDialog;
290 FilePickDialog.Title = Properties.Resources.PickPictureDialog1;
291 FilePickDialog.FileName = "";
293 if (this.FilePickDialogOpening != null)
294 this.FilePickDialogOpening(this, EventArgs.Empty);
298 if (FilePickDialog.ShowDialog() == DialogResult.Cancel) return;
302 if (this.FilePickDialogClosed != null)
303 this.FilePickDialogClosed(this, EventArgs.Empty);
306 ImagefilePathText.Text = FilePickDialog.FileName;
307 ImageFromSelectedFile(false);
310 private void ImagefilePathText_Validating(object sender, CancelEventArgs e)
312 if (ImageCancelButton.Focused)
314 ImagefilePathText.CausesValidation = false;
318 ImageFromSelectedFile(false);
321 private void ImageFromSelectedFile(bool suppressMsgBox)
323 this.ClearImageSelectedPicture();
327 ImagefilePathText.Text = ImagefilePathText.Text.Trim();
328 var fileName = ImagefilePathText.Text;
329 var serviceName = this.ServiceName;
330 if (string.IsNullOrEmpty(fileName) || string.IsNullOrEmpty(serviceName))
332 ClearSelectedImagePage();
336 FileInfo fl = new FileInfo(fileName);
337 string ext = fl.Extension;
338 var imageService = this.pictureService[serviceName];
340 if (!imageService.CheckFileExtension(ext))
343 ClearSelectedImagePage();
347 string.Format(Properties.Resources.PostPictureWarn3, serviceName, MakeAvailableServiceText(ext, fl.Length), ext),
348 Properties.Resources.PostPictureWarn4,
349 MessageBoxButtons.OK,
350 MessageBoxIcon.Warning);
355 if (!imageService.CheckFileSize(ext, fl.Length))
358 ClearSelectedImagePage();
362 string.Format(Properties.Resources.PostPictureWarn5, serviceName, MakeAvailableServiceText(ext, fl.Length)),
363 Properties.Resources.PostPictureWarn4,
364 MessageBoxButtons.OK,
365 MessageBoxIcon.Warning);
372 using (var fs = File.OpenRead(fileName))
374 ImageSelectedPicture.Image = MemoryImage.CopyFromStream(fs);
376 SetSelectedImagePage(fileName, MyCommon.UploadFileType.Picture);
378 catch (InvalidImageException)
380 SetSelectedImagePage(fileName, MyCommon.UploadFileType.MultiMedia);
383 catch (FileNotFoundException)
385 ClearSelectedImagePage();
386 if (!suppressMsgBox) MessageBox.Show("File not found.");
390 ClearSelectedImagePage();
391 if (!suppressMsgBox) MessageBox.Show("The type of this file is not image.");
395 private string MakeAvailableServiceText(string ext, long fileSize)
397 var text = string.Join(", ",
398 ImageServiceCombo.Items.Cast<string>()
399 .Where(x => !string.IsNullOrEmpty(x) && this.pictureService[x].CheckFileSize(ext, fileSize)));
401 if (string.IsNullOrEmpty(text))
402 return Properties.Resources.PostPictureWarn6;
407 private void ClearImageSelectedPicture()
409 var oldImage = this.ImageSelectedPicture.Image;
410 if (oldImage != null)
412 this.ImageSelectedPicture.Image = null;
416 this.ImageSelectedPicture.ShowInitialImage();
419 private void ImageCancelButton_Click(object sender, EventArgs e)
424 private void ImageSelection_KeyDown(object sender, KeyEventArgs e)
426 if (e.KeyCode == Keys.Escape)
432 private void ImageSelection_KeyPress(object sender, KeyPressEventArgs e)
434 if (Convert.ToInt32(e.KeyChar) == 0x1B)
436 ImagefilePathText.CausesValidation = false;
441 private void ImageSelection_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
443 if (e.KeyCode == Keys.Escape)
445 ImagefilePathText.CausesValidation = false;
449 private void SetImageServiceCombo()
451 using (ControlTransaction.Update(ImageServiceCombo))
454 if (ImageServiceCombo.SelectedIndex > -1) svc = ImageServiceCombo.Text;
455 ImageServiceCombo.Items.Clear();
457 // Add service names to combobox
458 foreach (var key in pictureService.Keys)
460 ImageServiceCombo.Items.Add(key);
463 SelectImageServiceComboItem(svc);
467 private void SelectImageServiceComboItem(string svc, int? index = null)
470 if (string.IsNullOrEmpty(svc))
476 idx = ImageServiceCombo.Items.IndexOf(svc);
477 if (idx == -1) idx = index ?? 0;
482 ImageServiceCombo.SelectedIndex = idx;
484 catch (ArgumentOutOfRangeException)
486 ImageServiceCombo.SelectedIndex = 0;
490 private void ImageServiceCombo_SelectedIndexChanged(object sender, EventArgs e)
494 var serviceName = this.ServiceName;
495 if (!string.IsNullOrEmpty(serviceName))
497 if (ImagePageCombo.Items.Count > 0)
499 // 画像が選択された投稿先に対応しているかをチェックする
500 // TODO: 複数の選択済み画像があるなら、できれば全てを再チェックしたほうがいい
501 if (serviceName.Equals("Twitter"))
503 ValidateSelectedImagePage();
507 if (ImagePageCombo.Items.Count > 1)
509 // 複数の選択済み画像のうち、1枚目のみを残す
510 SetImagePageCombo((SelectedMedia)ImagePageCombo.Items[0]);
514 ImagePageCombo.Enabled = false;
518 FileInfo fi = new FileInfo(ImagefilePathText.Text.Trim());
519 string ext = fi.Extension;
520 var imageService = this.pictureService[serviceName];
521 if (!imageService.CheckFileSize(ext, fi.Length))
523 ClearImageSelectedPicture();
524 ClearSelectedImagePage();
529 ClearImageSelectedPicture();
530 ClearSelectedImagePage();
538 if (this.SelectedServiceChanged != null)
539 this.SelectedServiceChanged(this, EventArgs.Empty);
542 private void SetImagePageCombo(SelectedMedia media = null)
544 using (ControlTransaction.Update(ImagePageCombo))
546 ImagePageCombo.Enabled = false;
547 ImagePageCombo.Items.Clear();
550 ImagePageCombo.Items.Add(media);
551 ImagefilePathText.Text = media.Path;
555 ImagePageCombo.Items.Add(new SelectedMedia("1"));
556 ImagefilePathText.Text = "";
558 ImagePageCombo.SelectedIndex = 0;
562 private void AddNewImagePage(int selectedIndex)
564 if (this.ServiceName.Equals("Twitter") && selectedIndex < 3)
566 // 投稿先が Twitter であれば、最大 4 枚まで選択できるようにする
567 var count = ImagePageCombo.Items.Count;
568 if (selectedIndex == count - 1)
571 ImagePageCombo.Items.Add(new SelectedMedia(count.ToString()));
572 ImagePageCombo.Enabled = true;
577 private void SetSelectedImagePage(string path, MyCommon.UploadFileType type)
579 var idx = ImagePageCombo.SelectedIndex;
580 var item = (SelectedMedia)ImagePageCombo.Items[idx];
584 AddNewImagePage(idx);
587 private void ClearSelectedImagePage()
589 var item = (SelectedMedia)ImagePageCombo.SelectedItem;
591 item.Type = MyCommon.UploadFileType.Invalid;
592 ImagefilePathText.Text = "";
595 private void ValidateSelectedImagePage()
597 var idx = ImagePageCombo.SelectedIndex;
598 var item = (SelectedMedia)ImagePageCombo.Items[idx];
599 ImageServiceCombo.Enabled = (idx == 0); // idx == 0 以外では投稿先サービスを選べないようにする
600 ImagefilePathText.Text = item.Path;
601 ImageFromSelectedFile(true);
604 private void ImagePageCombo_SelectedIndexChanged(object sender, EventArgs e)
606 ValidateSelectedImagePage();