OSDN Git Service

ブラウザからのFaviconやリンクのD&Dに対応
authorKimura Youichi <kim.upsilon@bucyou.net>
Sat, 22 Feb 2014 07:00:07 +0000 (16:00 +0900)
committerKimura Youichi <kim.upsilon@bucyou.net>
Sat, 22 Feb 2014 07:04:51 +0000 (16:04 +0900)
OpenTween.Tests/OpenTween.Tests.csproj
OpenTween.Tests/TweenMainText.cs [new file with mode: 0644]
OpenTween/Resources/ChangeLog.txt
OpenTween/Tween.cs

index a7e038c..9da6e3b 100644 (file)
@@ -75,6 +75,7 @@
     <Compile Include="Thumbnail\Services\SimpleThumbnailServiceTest.cs" />
     <Compile Include="Thumbnail\Services\TinamiTest.cs" />
     <Compile Include="ToolStripAPIGaugeTest.cs" />
+    <Compile Include="TweenMainText.cs" />
     <Compile Include="TweetFormatterTest.cs" />
     <Compile Include="TweetThumbnailTest.cs" />
     <Compile Include="TwitterTest.cs" />
diff --git a/OpenTween.Tests/TweenMainText.cs b/OpenTween.Tests/TweenMainText.cs
new file mode 100644 (file)
index 0000000..cb6dd3d
--- /dev/null
@@ -0,0 +1,85 @@
+// OpenTween - Client of Twitter
+// Copyright (c) 2014 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
+// All rights reserved.
+//
+// This file is part of OpenTween.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. If not, see <http://www.gnu.org/licenses/>, or write to
+// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using Xunit;
+using Xunit.Extensions;
+
+namespace OpenTween
+{
+    public class TweenMainText
+    {
+        [Fact]
+        public void GetUrlFromDataObject_XMozUrlTest()
+        {
+            var dataBytes = Encoding.Unicode.GetBytes("https://twitter.com/\nTwitter\0");
+            using (var memstream = new MemoryStream(dataBytes))
+            {
+                var data = new DataObject("text/x-moz-url", memstream);
+
+                var expected = new Tuple<string, string>("https://twitter.com/", "Twitter");
+                Assert.Equal(expected, TweenMain.GetUrlFromDataObject(data));
+            }
+        }
+
+        [Fact]
+        public void GetUrlFromDataObject_IESiteModeToUrlTest()
+        {
+            var dataBytes = Encoding.Unicode.GetBytes("https://twitter.com/\0Twitter\0");
+            using (var memstream = new MemoryStream(dataBytes))
+            {
+                var data = new DataObject("IESiteModeToUrl", memstream);
+
+                var expected = new Tuple<string, string>("https://twitter.com/", "Twitter");
+                Assert.Equal(expected, TweenMain.GetUrlFromDataObject(data));
+            }
+        }
+
+        [Fact]
+        public void GetUrlFromDataObject_UniformResourceLocatorWTest()
+        {
+            var dataBytes = Encoding.Unicode.GetBytes("https://twitter.com/\0");
+            using (var memstream = new MemoryStream(dataBytes))
+            {
+                var data = new DataObject("UniformResourceLocatorW", memstream);
+
+                var expected = new Tuple<string, string>("https://twitter.com/", null);
+                Assert.Equal(expected, TweenMain.GetUrlFromDataObject(data));
+            }
+        }
+
+        [Fact]
+        public void GetUrlFromDataObject_UnknownFormatTest()
+        {
+            using (var memstream = new MemoryStream(new byte[0]))
+            {
+                var data = new DataObject("application/x-hogehoge", memstream);
+
+                Assert.Throws<NotSupportedException>(() => TweenMain.GetUrlFromDataObject(data));
+            }
+        }
+    }
+}
index 4355cdc..b1a0b50 100644 (file)
@@ -4,6 +4,8 @@
  * NEW: ファイルメニューに「ツイートURLを開く」を追加
   - https://twitter.com/*****/statuses/1234567890 のような形式のURLを直接開くことが出来ます
  * NEW: プロフィール画像の右クリックメニューに「再読み込み」を追加
+ * NEW: ブラウザからのD&Dに対応 (Firefox, Chrome で動作します)
+  - アドレスバーの Favicon やリンクなどを D&D すると投稿欄にURLとタイトルが入力されます
  * CHG: 投稿するツイートの末尾の全角スペースを除去しない
  * FIX: サムネイル画像の取得をキャンセルするとエラーが発生する場合がある問題の修正
  * FIX: サムネイル画像の読み込み中に画面の更新が遅くなる問題の修正
index 5cdadb0..3919fe5 100644 (file)
@@ -10351,6 +10351,15 @@ namespace OpenTween
                 this.BringToFront();
                 StatusText.Focus();
             }
+            else if (e.Data.GetDataPresent("UniformResourceLocatorW"))
+            {
+                var url = GetUrlFromDataObject(e.Data);
+
+                if (url.Item2 == null)
+                    this.StatusText.Text += " / " + url.Item1;
+                else
+                    this.StatusText.Text += " / " + url.Item2 + " " + url.Item1;
+            }
             else if (e.Data.GetDataPresent(DataFormats.StringFormat))
             {
                 string data = (string)e.Data.GetData(DataFormats.StringFormat, true);
@@ -10358,6 +10367,58 @@ namespace OpenTween
             }
         }
 
+        /// <summary>
+        /// IDataObject から URL とタイトルの対を取得します
+        /// </summary>
+        /// <remarks>
+        /// タイトルのみ取得できなかった場合は Value2 が null のタプルを返すことがあります。
+        /// </remarks>
+        /// <exception cref="ArgumentException">不正なフォーマットが入力された場合</exception>
+        /// <exception cref="NotSupportedException">サポートされていないデータが入力された場合</exception>
+        internal static Tuple<string, string> GetUrlFromDataObject(IDataObject data)
+        {
+            if (data.GetDataPresent("text/x-moz-url"))
+            {
+                // Firefox, Google Chrome で利用可能
+                // 参照: https://developer.mozilla.org/ja/docs/DragDrop/Recommended_Drag_Types
+
+                using (var stream = (MemoryStream)data.GetData("text/x-moz-url"))
+                {
+                    var lines = Encoding.Unicode.GetString(stream.ToArray()).TrimEnd('\0').Split('\n');
+                    if (lines.Length < 2)
+                        throw new ArgumentException("不正な text/x-moz-url フォーマットです", "data");
+
+                    return new Tuple<string, string>(lines[0], lines[1]);
+                }
+            }
+            else if (data.GetDataPresent("IESiteModeToUrl"))
+            {
+                // Internet Exproler 用
+                // 保護モードが有効なデフォルトの IE では DragDrop イベントが発火しないため使えない
+
+                using (var stream = (MemoryStream)data.GetData("IESiteModeToUrl"))
+                {
+                    var lines = Encoding.Unicode.GetString(stream.ToArray()).TrimEnd('\0').Split('\0');
+                    if (lines.Length < 2)
+                        throw new ArgumentException("不正な IESiteModeToUrl フォーマットです", "data");
+
+                    return new Tuple<string, string>(lines[0], lines[1]);
+                }
+            }
+            else if (data.GetDataPresent("UniformResourceLocatorW"))
+            {
+                // それ以外のブラウザ向け
+
+                using (var stream = (MemoryStream)data.GetData("UniformResourceLocatorW"))
+                {
+                    var url = Encoding.Unicode.GetString(stream.ToArray()).TrimEnd('\0');
+                    return new Tuple<string, string>(url, null);
+                }
+            }
+
+            throw new NotSupportedException("サポートされていないデータ形式です: " + data.GetFormats()[0]);
+        }
+
         private void TweenMain_DragOver(object sender, DragEventArgs e)
         {
             if (e.Data.GetDataPresent(DataFormats.FileDrop))
@@ -10383,6 +10444,10 @@ namespace OpenTween
                 }
                 e.Effect = DragDropEffects.None;
             }
+            else if (e.Data.GetDataPresent("UniformResourceLocatorW"))
+            {
+                e.Effect = DragDropEffects.Copy;
+            }
             else if (e.Data.GetDataPresent(DataFormats.StringFormat))
             {
                 e.Effect = DragDropEffects.Copy;