OSDN Git Service

Merge branch 'api11'
authorKimura Youichi <kim.upsilon@bucyou.net>
Mon, 10 Jun 2013 15:11:40 +0000 (00:11 +0900)
committerKimura Youichi <kim.upsilon@bucyou.net>
Mon, 10 Jun 2013 15:11:40 +0000 (00:11 +0900)
32 files changed:
.travis.yml
.tx/config [new file with mode: 0644]
OpenTween.Tests/FiltersClassTest.cs
OpenTween.Tests/MyCommonTest.cs
OpenTween.Tests/TweetThumbnailTest.cs
OpenTween.Tests/TwitterTest.cs
OpenTween/Api/ApiLimit.cs
OpenTween/AppendSettingDialog.cs
OpenTween/ApplicationSettings.cs
OpenTween/Connection/HttpConnection.cs
OpenTween/Connection/HttpConnectionOAuth.cs
OpenTween/Connection/HttpTwitter.cs
OpenTween/FormInfo.cs
OpenTween/MemoryImage.cs
OpenTween/MyCommon.cs
OpenTween/MyLists.Designer.cs
OpenTween/MyLists.resx
OpenTween/OpenTween.csproj
OpenTween/Properties/AssemblyInfo.cs
OpenTween/Properties/Resources.Designer.cs
OpenTween/Properties/Resources.en.resx
OpenTween/Properties/Resources.resx
OpenTween/Resources/ChangeLog.txt
OpenTween/StatusDictionary.cs
OpenTween/Thumbnail/Services/SimpleThumbnailService.cs
OpenTween/Thumbnail/ThumbnailGenerator.cs
OpenTween/Thumbnail/ThumbnailInfo.cs
OpenTween/Tween.Designer.cs
OpenTween/Tween.cs
OpenTween/TweetThumbnail.cs
OpenTween/Twitter.cs
OpenTween/Win32Api.cs

index d5a2561..0520ac7 100644 (file)
@@ -9,11 +9,9 @@ install:
   - export DISPLAY=:99.0
   - sh -e /etc/init.d/xvfb start
 
-# Build
 script:
+  # Build
   - xbuild /verbosity:quiet
-
-# Run Tests
-after_script:
+  # Run Tests
   - if ! grep -q 'Version 11.00' OpenTween.sln; then echo 'OpenTween.sln is not compatible with Visual C# 2010 Express.'; false; fi
   - nunit-console -timeout=10000 ./OpenTween.Tests/OpenTween.Tests.nunit
diff --git a/.tx/config b/.tx/config
new file mode 100644 (file)
index 0000000..fcc6eac
--- /dev/null
@@ -0,0 +1,100 @@
+[main]
+host = https://www.transifex.com
+lang_map = zh_CN: zh-CHS
+type = RESX
+
+[opentween.global]
+file_filter = OpenTween/Properties/Resources.<lang>.resx
+source_file = OpenTween/Properties/Resources.resx
+source_lang = ja
+
+[opentween.AppendSettingDialog]
+file_filter = OpenTween/AppendSettingDialog.<lang>.resx
+source_file = OpenTween/AppendSettingDialog.resx
+source_lang = ja
+
+[opentween.AtIdSupplement]
+file_filter = OpenTween/AtIdSupplement.<lang>.resx
+source_file = OpenTween/AtIdSupplement.resx
+source_lang = ja
+
+[opentween.AuthDialog]
+file_filter = OpenTween/AuthDialog.<lang>.resx
+source_file = OpenTween/AuthDialog.resx
+source_lang = ja
+
+[opentween.EventViewerDialog]
+file_filter = OpenTween/EventViewerDialog.<lang>.resx
+source_file = OpenTween/EventViewerDialog.resx
+source_lang = ja
+
+[opentween.FilterDialog]
+file_filter = OpenTween/FilterDialog.<lang>.resx
+source_file = OpenTween/FilterDialog.resx
+source_lang = ja
+
+[opentween.FormInfo]
+file_filter = OpenTween/FormInfo.<lang>.resx
+source_file = OpenTween/FormInfo.resx
+source_lang = ja
+
+[opentween.HashtagManage]
+file_filter = OpenTween/HashtagManage.<lang>.resx
+source_file = OpenTween/HashtagManage.resx
+source_lang = ja
+
+[opentween.InputTabName]
+file_filter = OpenTween/InputTabName.<lang>.resx
+source_file = OpenTween/InputTabName.resx
+source_lang = ja
+
+[opentween.ListAvailable]
+file_filter = OpenTween/ListAvailable.<lang>.resx
+source_file = OpenTween/ListAvailable.resx
+source_lang = ja
+
+[opentween.ListManage]
+file_filter = OpenTween/ListManage.<lang>.resx
+source_file = OpenTween/ListManage.resx
+source_lang = ja
+
+[opentween.MyLists]
+file_filter = OpenTween/MyLists.<lang>.resx
+source_file = OpenTween/MyLists.resx
+source_lang = ja
+
+[opentween.OpenURL]
+file_filter = OpenTween/OpenURL.<lang>.resx
+source_file = OpenTween/OpenURL.resx
+source_lang = ja
+
+[opentween.SearchWord]
+file_filter = OpenTween/SearchWord.<lang>.resx
+source_file = OpenTween/SearchWord.resx
+source_lang = ja
+
+[opentween.ShowUserInfo]
+file_filter = OpenTween/ShowUserInfo.<lang>.resx
+source_file = OpenTween/ShowUserInfo.resx
+source_lang = ja
+
+[opentween.TabsDialog]
+file_filter = OpenTween/TabsDialog.<lang>.resx
+source_file = OpenTween/TabsDialog.resx
+source_lang = ja
+
+[opentween.Tween]
+file_filter = OpenTween/Tween.<lang>.resx
+source_file = OpenTween/Tween.resx
+source_lang = ja
+
+[opentween.TweenAboutBox]
+file_filter = OpenTween/TweenAboutBox.<lang>.resx
+source_file = OpenTween/TweenAboutBox.resx
+source_lang = ja
+
+[opentween.UpdateDialog]
+file_filter = OpenTween/UpdateDialog.<lang>.resx
+source_file = OpenTween/UpdateDialog.resx
+source_lang = ja
+
index fdde3ca..1b56c1f 100644 (file)
@@ -71,25 +71,25 @@ namespace OpenTween
             var filter = new FiltersClass { UseRegex = true };
             PostClass post;
 
-            filter.NameFilter = "(hoge)+";
+            filter.NameFilter = "hoge(hoge)+";
             post = new PostClass { ScreenName = "hogehoge", Text = "test" };
             Assert.That(filter.IsHit(post), Is.EqualTo(MyCommon.HITRESULT.CopyAndMark));
 
-            filter.NameFilter = "(hoge)+";
+            filter.NameFilter = "hoge(hoge)+";
             post = new PostClass { ScreenName = "hoge", Text = "test" };
             Assert.That(filter.IsHit(post), Is.EqualTo(MyCommon.HITRESULT.None));
 
             // NameFilter は RetweetedBy にもマッチする
-            filter.NameFilter = "(hoge)+";
+            filter.NameFilter = "hoge(hoge)+";
             post = new PostClass { ScreenName = "foo", Text = "test", RetweetedBy = "hogehoge" };
             Assert.That(filter.IsHit(post), Is.EqualTo(MyCommon.HITRESULT.CopyAndMark));
 
-            filter.NameFilter = "(hoge)+";
+            filter.NameFilter = "hoge(hoge)+";
             post = new PostClass { ScreenName = "foo", Text = "test", RetweetedBy = "hoge2" };
             Assert.That(filter.IsHit(post), Is.EqualTo(MyCommon.HITRESULT.None));
 
             // 大小文字を区別しないオプション
-            filter.NameFilter = "(hoge)+";
+            filter.NameFilter = "hoge(hoge)+";
             filter.CaseSensitive = false;
             post = new PostClass { ScreenName = "HogeHogeHoge", Text = "test" };
             Assert.That(filter.IsHit(post), Is.EqualTo(MyCommon.HITRESULT.CopyAndMark));
index e83aa27..f120514 100644 (file)
@@ -30,6 +30,7 @@ using System.Runtime.InteropServices;
 using System.Reflection;
 using System.Windows.Forms;
 using System.Runtime.Serialization;
+using System.IO;
 
 namespace OpenTween
 {
@@ -207,5 +208,27 @@ namespace OpenTween
         {
             Assert.That(MyCommon.GetStatusUrl(screenName, statusId), Is.EqualTo(except));
         }
+
+        [Test]
+        [Platform("Win")]
+        public void GetErrorLogPathTestWindows()
+        {
+            var mockAssembly = Substitute.For<_Assembly>();
+            mockAssembly.Location.Returns(@"C:\hogehoge\OpenTween\OpenTween.exe");
+            MyCommon.EntryAssembly = mockAssembly;
+
+            Assert.That(MyCommon.GetErrorLogPath(), Is.SamePath(@"C:\hogehoge\OpenTween\ErrorLogs\"));
+        }
+
+        [Test]
+        [Platform(Exclude = "Win")]
+        public void GetErrorLogPathTestOther()
+        {
+            var mockAssembly = Substitute.For<_Assembly>();
+            mockAssembly.Location.Returns(@"/hogehoge/OpenTween/OpenTween.exe");
+            MyCommon.EntryAssembly = mockAssembly;
+
+            Assert.That(MyCommon.GetErrorLogPath(), Is.SamePath(@"/hogehoge/OpenTween/ErrorLogs/"));
+        }
     }
 }
index a8e8cd9..6420cbf 100644 (file)
@@ -102,6 +102,7 @@ namespace OpenTween
         }
 
         [Test]
+        [Ignore]
         public void CancelAsyncTest()
         {
             using (var thumbbox = new TweetThumbnail())
index f4d145f..4ea6be0 100644 (file)
@@ -63,5 +63,30 @@ namespace OpenTween
             return Twitter.ThirdPartyStatusUrlRegex.Matches(url).Cast<Match>()
                 .Select(x => x.Groups["StatusId"].Value).ToArray();
         }
+
+        [Test]
+        public void FindTopOfReplyChainTest()
+        {
+            var posts = new Dictionary<long, PostClass>
+            {
+                {950L, new PostClass { StatusId = 950L, InReplyToStatusId = 0L }}, // このツイートが末端
+                {987L, new PostClass { StatusId = 987L, InReplyToStatusId = 950L }},
+                {999L, new PostClass { StatusId = 999L, InReplyToStatusId = 987L }},
+                {1000L, new PostClass { StatusId = 1000L, InReplyToStatusId = 999L }},
+            };
+            Assert.That(Twitter.FindTopOfReplyChain(posts, 1000L).StatusId, Is.EqualTo(950L));
+            Assert.That(Twitter.FindTopOfReplyChain(posts, 950L).StatusId, Is.EqualTo(950L));
+            Assert.That(() => Twitter.FindTopOfReplyChain(posts, 500L), Throws.ArgumentException);
+
+            posts = new Dictionary<long, PostClass>
+            {
+                // 1200L は posts の中に存在しない
+                {1210L, new PostClass { StatusId = 1210L, InReplyToStatusId = 1200L }},
+                {1220L, new PostClass { StatusId = 1220L, InReplyToStatusId = 1210L }},
+                {1230L, new PostClass { StatusId = 1230L, InReplyToStatusId = 1220L }},
+            };
+            Assert.That(Twitter.FindTopOfReplyChain(posts, 1230L).StatusId, Is.EqualTo(1210L));
+            Assert.That(Twitter.FindTopOfReplyChain(posts, 1210L).StatusId, Is.EqualTo(1210L));
+        }
     }
 }
index 42b48de..87be5b9 100644 (file)
@@ -43,11 +43,22 @@ namespace OpenTween.Api
         /// </summary>
         public readonly DateTime AccessLimitResetDate;
 
+        /// <summary>
+        /// API 実行回数制限値を取得した日時
+        /// </summary>
+        public readonly DateTime UpdatedAt;
+
         public ApiLimit(int limitCount, int limitRemain, DateTime resetDate)
+            : this(limitCount, limitRemain, resetDate, DateTime.Now)
+        {
+        }
+
+        public ApiLimit(int limitCount, int limitRemain, DateTime resetDate, DateTime updatedAt)
         {
             this.AccessLimitCount = limitCount;
             this.AccessLimitRemain = limitRemain;
             this.AccessLimitResetDate = resetDate;
+            this.UpdatedAt = updatedAt;
         }
 
         public override bool Equals(object obj)
index d710972..e9232ad 100644 (file)
@@ -769,6 +769,8 @@ namespace OpenTween
 
             CheckPeriodAdjust.Checked = PeriodAdjust;
             CheckStartupVersion.Checked = StartupVersion;
+            if (ApplicationSettings.VersionInfoUrl == null)
+                CheckStartupVersion.Enabled = false; // 更新チェック無効化
             CheckStartupFollowers.Checked = StartupFollowers;
             CheckFavRestrict.Checked = RestrictFavCheck;
             CheckAlwaysTop.Checked = AlwaysTop;
index 695f3b3..0c92551 100644 (file)
@@ -72,8 +72,9 @@ namespace OpenTween
         /// </summary>
         /// <remarks>
         /// version.txt のフォーマットについては http://sourceforge.jp/projects/opentween/wiki/VersionTxt を参照。
+        /// 派生プロジェクトなどでこの機能を無効にする場合は null をセットして下さい。
         /// </remarks>
-        public const string VersionInfoUrl = "http://www.opentween.org/status/version.txt";
+        public static readonly string VersionInfoUrl = "http://www.opentween.org/status/version.txt";
 
         //=====================================================================
         // Twitter
index 8aa22d7..61247a2 100644 (file)
@@ -143,7 +143,7 @@ namespace OpenTween
         ///<param name="method">HTTP通信メソッド(POST/PUT)</param>
         ///<param name="requestUri">通信先URI</param>
         ///<param name="param">form-dataで指定する名前と文字列のディクショナリ</param>
-        ///<param name="param">form-dataで指定する名前とバイナリファイル情報のリスト</param>
+        ///<param name="binaryFileInfo">form-dataで指定する名前とバイナリファイル情報のリスト</param>
         ///<param name="withCookie">通信にcookieを使用するか</param>
         ///<returns>引数で指定された内容を反映したHttpWebRequestオブジェクト</returns>
         protected HttpWebRequest CreateRequest(string method,
@@ -446,7 +446,7 @@ namespace OpenTween
         ///WebExceptionはハンドルしていないので、呼び出し元でキャッチすること
         ///</remarks>
         ///<param name="webRequest">HTTP通信リクエストオブジェクト</param>
-        ///<param name="contentText">[OUT]HTTP応答のボディデータを書き込むBitmap</param>
+        ///<param name="contentBitmap">[OUT]HTTP応答のボディデータを書き込むBitmap</param>
         ///<param name="headerInfo">[IN/OUT]HTTP応答のヘッダ情報。ヘッダ名をキーにして空データのコレクションを渡すことで、該当ヘッダの値をデータに設定して戻す</param>
         ///<param name="withCookie">通信にcookieを使用する</param>
         ///<returns>HTTP応答のステータスコード</returns>
@@ -597,7 +597,7 @@ namespace OpenTween
         ///<summary>
         ///2バイト文字も考慮したUrlエンコード
         ///</summary>
-        ///<param name="str">エンコードする文字列</param>
+        ///<param name="stringToEncode">エンコードする文字列</param>
         ///<returns>エンコード結果文字列</returns>
         protected string UrlEncode(string stringToEncode)
         {
index 0d5bb82..026c5be 100644 (file)
@@ -253,7 +253,7 @@ namespace OpenTween
                /// 呼び出し元では戻されたurlをブラウザで開き、認証完了後PIN入力を受け付けて、リクエストトークンと共にAuthenticatePinFlowを呼び出す
                /// </remarks>
                /// <param name="requestTokenUrl">リクエストトークンの取得先URL</param>
-               /// <param name="requestUri">ブラウザで開く認証用URLのベース</param>
+               /// <param name="authorizeUrl">ブラウザで開く認証用URLのベース</param>
                /// <param name="requestToken">[OUT]認証要求で戻されるリクエストトークン。使い捨て</param>
                /// <param name="authUri">[OUT]requestUriを元に生成された認証用URL。通常はリクエストトークンをクエリとして付加したUri</param>
                /// <returns>取得結果真偽値</returns>
@@ -273,7 +273,7 @@ namespace OpenTween
                /// 事前にAuthenticatePinFlowRequestを呼んで、ブラウザで認証後に表示されるPINを入力してもらい、その値とともに呼び出すこと
                /// </remarks>
                /// <param name="accessTokenUrl">アクセストークンの取得先URL</param>
-               /// <param name="requestUri">AuthenticatePinFlowRequestで取得したリクエストトークン</param>
+               /// <param name="requestToken">AuthenticatePinFlowRequestで取得したリクエストトークン</param>
                /// <param name="pinCode">Webで認証後に表示されるPINコード</param>
                /// <returns>取得結果真偽値</returns>
                public HttpStatusCode AuthenticatePinFlow( string accessTokenUrl, string requestToken, string pinCode )
@@ -397,7 +397,7 @@ namespace OpenTween
                /// <summary>
                /// OAuth認証のリクエストトークン取得。リクエストトークンと組み合わせた認証用のUriも生成する
                /// </summary>
-               /// <param name="accessTokenUrl">リクエストトークンの取得先URL</param>
+               /// <param name="requestTokenUrl">リクエストトークンの取得先URL</param>
                /// <param name="authorizeUrl">ブラウザで開く認証用URLのベース</param>
                /// <param name="requestToken">[OUT]取得したリクエストトークン</param>
                /// <returns>取得結果真偽値</returns>
index add11f5..978bf06 100644 (file)
@@ -958,12 +958,13 @@ namespace OpenTween
             //認証なくても取得できるが、protectedユーザー分が抜ける
             Dictionary<string, string> param = new Dictionary<string, string>();
 
+            param.Add("id", id.ToString());
             param.Add("include_entities", "true");
 
             // TODO: API v1.1 に存在しない API (旧 API で代替)
 
             return httpCon.GetContent(GetMethod,
-                CreateTwitterUri("/1/related_results/show/" + id + ".json"),
+                CreateTwitterUri("/1/related_results/show.json"),
                 param,
                 ref content,
                 this.apiStatusHeaders,
index 5a51081..bf071a2 100644 (file)
@@ -118,11 +118,10 @@ namespace OpenTween
             LabelInformation.Refresh();
         }
 
-        ///<summary>
-        ///ダイアログに表示されるユーザー向けメッセージを設定あるいは取得する
-        ///</summary>
-        ///<param name="msg">表示するメッセージ</param>
-        ///<returns>現在設定されているメッセージ</returns>
+        /// <summary>
+        /// ダイアログに表示されるユーザー向けメッセージを設定あるいは取得する
+        /// </summary>
+        /// <returns>現在設定されているメッセージ</returns>
         public string InfoMessage
         {
             get { return _msg; }
@@ -133,11 +132,10 @@ namespace OpenTween
             }
         }
 
-        ///<summary>
-        ///Servicerへ渡すパラメータ
-        ///</summary>
-        ///<param name="args">Servicerへ渡すパラメータ</param>
-        ///<returns>現在設定されているServicerへ渡すパラメータ</returns>
+        /// <summary>
+        /// Servicerへ渡すパラメータ
+        /// </summary>
+        /// <returns>現在設定されているServicerへ渡すパラメータ</returns>
         public object Argument
         {
             get { return _arg; }
index 069e76b..b15507f 100644 (file)
@@ -101,7 +101,7 @@ namespace OpenTween
         /// <summary>
         /// 指定されたバイト列から MemoryImage を作成します。
         /// </summary>
-        /// <param name="stream">読み込む対象となるバイト列</param>
+        /// <param name="bytes">読み込む対象となるバイト列</param>
         /// <returns>作成された MemoryImage</returns>
         public static MemoryImage CopyFromBytes(byte[] bytes)
         {
index 3e95522..3306feb 100644 (file)
@@ -219,6 +219,11 @@ namespace OpenTween
                    Block | Unblock | UserUpdate | Deleted | ListCreated | ListUpdated | Unfollow),
         }
 
+        public static string GetErrorLogPath()
+        {
+            return Path.Combine(Path.GetDirectoryName(MyCommon.EntryAssembly.Location), "ErrorLogs");
+        }
+
         public static void TraceOut(Exception ex, string Message)
         {
             var buf = ExceptionOutMessage(ex);
@@ -235,8 +240,14 @@ namespace OpenTween
             lock (LockObj)
             {
                 if (!OutputFlag) return;
+
+                var logPath = MyCommon.GetErrorLogPath();
+                if (!Directory.Exists(logPath))
+                    Directory.CreateDirectory(logPath);
+
                 var now = DateTime.Now;
                 var fileName = string.Format("{0}Trace-{1:0000}{2:00}{3:00}-{4:00}{5:00}{6:00}.log", GetAssemblyName(), now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second);
+                fileName = Path.Combine(logPath, fileName);
 
                 using (var writer = new StreamWriter(fileName))
                 {
@@ -344,8 +355,14 @@ namespace OpenTween
             lock (LockObj)
             {
                 var IsTerminatePermission = true;
+
+                var logPath = MyCommon.GetErrorLogPath();
+                if (!Directory.Exists(logPath))
+                    Directory.CreateDirectory(logPath);
+
                 var now = DateTime.Now;
                 var fileName = string.Format("{0}-{1:0000}{2:00}{3:00}-{4:00}{5:00}{6:00}.log", GetAssemblyName(), now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second);
+                fileName = Path.Combine(logPath, fileName);
 
                 using (var writer = new StreamWriter(fileName))
                 {
@@ -391,7 +408,7 @@ namespace OpenTween
         /// マルチバイト文字のコードはUTF-8またはUnicodeで自動的に判断します。
         /// </newpara>
         /// </summary>
-        /// <param name = input>エンコード対象のURL</param>
+        /// <param name="_input">エンコード対象のURL</param>
         /// <returns>マルチバイト文字の部分をUTF-8/%xx形式でエンコードした文字列を返します。</returns>
 
         public static string urlEncodeMultibyteChar(string _input)
@@ -743,11 +760,9 @@ namespace OpenTween
         public static T CreateDataFromJson<T>(string content)
         {
             T data;
-            using (var stream = new MemoryStream())
+            var buf = Encoding.Unicode.GetBytes(content);
+            using (var stream = new MemoryStream(buf))
             {
-                var buf = Encoding.Unicode.GetBytes(content);
-                stream.Write(Encoding.Unicode.GetBytes(content), offset: 0, count: buf.Length);
-                stream.Seek(offset: 0, loc: SeekOrigin.Begin);
                 data = (T)((new DataContractJsonSerializer(typeof(T))).ReadObject(stream));
             }
             return data;
index 1394bc5..8d26ae6 100644 (file)
         {
             this.components = new System.ComponentModel.Container();
             System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MyLists));
-            this.更新RToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+            this.MenuItemReload = new System.Windows.Forms.ToolStripMenuItem();
             this.ListRefreshButton = new System.Windows.Forms.Button();
             this.ListsCheckedListBox = new System.Windows.Forms.CheckedListBox();
             this.ContextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
-            this.追加AToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
-            this.削除DToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+            this.MenuItemAdd = new System.Windows.Forms.ToolStripMenuItem();
+            this.MenuItemDelete = new System.Windows.Forms.ToolStripMenuItem();
             this.ToolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
             this.CloseButton = new System.Windows.Forms.Button();
             this.ContextMenuStrip1.SuspendLayout();
             this.SuspendLayout();
             // 
-            // 更新RToolStripMenuItem
+            // MenuItemReload
             // 
-            this.更新RToolStripMenuItem.Name = "更新RToolStripMenuItem";
-            resources.ApplyResources(this.更新RToolStripMenuItem, "更新RToolStripMenuItem");
-            this.更新RToolStripMenuItem.Click += new System.EventHandler(this.更新RToolStripMenuItem_Click);
+            this.MenuItemReload.Name = "MenuItemReload";
+            resources.ApplyResources(this.MenuItemReload, "MenuItemReload");
+            this.MenuItemReload.Click += new System.EventHandler(this.更新RToolStripMenuItem_Click);
             // 
             // ListRefreshButton
             // 
             // ContextMenuStrip1
             // 
             this.ContextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.追加AToolStripMenuItem,
-            this.削除DToolStripMenuItem,
+            this.MenuItemAdd,
+            this.MenuItemDelete,
             this.ToolStripMenuItem1,
-            this.更新RToolStripMenuItem});
+            this.MenuItemReload});
             this.ContextMenuStrip1.Name = "ContextMenuStrip1";
             resources.ApplyResources(this.ContextMenuStrip1, "ContextMenuStrip1");
             this.ContextMenuStrip1.Opening += new System.ComponentModel.CancelEventHandler(this.ContextMenuStrip1_Opening);
             // 
-            // 追加AToolStripMenuItem
+            // MenuItemAdd
             // 
-            this.追加AToolStripMenuItem.Name = "追加AToolStripMenuItem";
-            resources.ApplyResources(this.追加AToolStripMenuItem, "追加AToolStripMenuItem");
-            this.追加AToolStripMenuItem.Click += new System.EventHandler(this.追加AToolStripMenuItem_Click);
+            this.MenuItemAdd.Name = "MenuItemAdd";
+            resources.ApplyResources(this.MenuItemAdd, "MenuItemAdd");
+            this.MenuItemAdd.Click += new System.EventHandler(this.追加AToolStripMenuItem_Click);
             // 
-            // 削除DToolStripMenuItem
+            // MenuItemDelete
             // 
-            this.削除DToolStripMenuItem.Name = "削除DToolStripMenuItem";
-            resources.ApplyResources(this.削除DToolStripMenuItem, "削除DToolStripMenuItem");
-            this.削除DToolStripMenuItem.Click += new System.EventHandler(this.削除DToolStripMenuItem_Click);
+            this.MenuItemDelete.Name = "MenuItemDelete";
+            resources.ApplyResources(this.MenuItemDelete, "MenuItemDelete");
+            this.MenuItemDelete.Click += new System.EventHandler(this.削除DToolStripMenuItem_Click);
             // 
             // ToolStripMenuItem1
             // 
 
         #endregion
 
-        internal System.Windows.Forms.ToolStripMenuItem 更新RToolStripMenuItem;
+        internal System.Windows.Forms.ToolStripMenuItem MenuItemReload;
         internal System.Windows.Forms.Button ListRefreshButton;
         internal System.Windows.Forms.CheckedListBox ListsCheckedListBox;
         internal System.Windows.Forms.ContextMenuStrip ContextMenuStrip1;
-        internal System.Windows.Forms.ToolStripMenuItem 追加AToolStripMenuItem;
-        internal System.Windows.Forms.ToolStripMenuItem 削除DToolStripMenuItem;
+        internal System.Windows.Forms.ToolStripMenuItem MenuItemAdd;
+        internal System.Windows.Forms.ToolStripMenuItem MenuItemDelete;
         internal System.Windows.Forms.ToolStripSeparator ToolStripMenuItem1;
         internal System.Windows.Forms.Button CloseButton;
     }
index 4ac4875..1f8b787 100644 (file)
     <value>17, 17</value>
   </metadata>
   <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
-  <data name="追加AToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
+  <data name="MenuItemAdd.Size" type="System.Drawing.Size, System.Drawing">
     <value>152, 22</value>
   </data>
-  <data name="追加AToolStripMenuItem.Text" xml:space="preserve">
+  <data name="MenuItemAdd.Text" xml:space="preserve">
     <value>追加(&amp;A)</value>
   </data>
-  <data name="削除DToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
+  <data name="MenuItemDelete.Size" type="System.Drawing.Size, System.Drawing">
     <value>152, 22</value>
   </data>
-  <data name="削除DToolStripMenuItem.Text" xml:space="preserve">
+  <data name="MenuItemDelete.Text" xml:space="preserve">
     <value>削除(&amp;D)</value>
   </data>
   <data name="ToolStripMenuItem1.Size" type="System.Drawing.Size, System.Drawing">
     <value>149, 6</value>
   </data>
-  <data name="更新RToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
+  <data name="MenuItemReload.Size" type="System.Drawing.Size, System.Drawing">
     <value>152, 22</value>
   </data>
-  <data name="更新RToolStripMenuItem.Text" xml:space="preserve">
+  <data name="MenuItemReload.Text" xml:space="preserve">
     <value>更新(&amp;R)</value>
   </data>
   <data name="ContextMenuStrip1.Size" type="System.Drawing.Size, System.Drawing">
   <data name="$this.Text" xml:space="preserve">
     <value>MyLists</value>
   </data>
-  <data name="&gt;&gt;追加AToolStripMenuItem.Name" xml:space="preserve">
-    <value>追加AToolStripMenuItem</value>
+  <data name="&gt;&gt;MenuItemAdd.Name" xml:space="preserve">
+    <value>MenuItemAdd</value>
   </data>
-  <data name="&gt;&gt;追加AToolStripMenuItem.Type" xml:space="preserve">
+  <data name="&gt;&gt;MenuItemAdd.Type" xml:space="preserve">
     <value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </data>
-  <data name="&gt;&gt;削除DToolStripMenuItem.Name" xml:space="preserve">
-    <value>削除DToolStripMenuItem</value>
+  <data name="&gt;&gt;MenuItemDelete.Name" xml:space="preserve">
+    <value>MenuItemDelete</value>
   </data>
-  <data name="&gt;&gt;削除DToolStripMenuItem.Type" xml:space="preserve">
+  <data name="&gt;&gt;MenuItemDelete.Type" xml:space="preserve">
     <value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </data>
   <data name="&gt;&gt;ToolStripMenuItem1.Name" xml:space="preserve">
   <data name="&gt;&gt;ToolStripMenuItem1.Type" xml:space="preserve">
     <value>System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </data>
-  <data name="&gt;&gt;更新RToolStripMenuItem.Name" xml:space="preserve">
-    <value>更新RToolStripMenuItem</value>
+  <data name="&gt;&gt;MenuItemReload.Name" xml:space="preserve">
+    <value>MenuItemReload</value>
   </data>
-  <data name="&gt;&gt;更新RToolStripMenuItem.Type" xml:space="preserve">
+  <data name="&gt;&gt;MenuItemReload.Type" xml:space="preserve">
     <value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </data>
   <data name="&gt;&gt;$this.Name" xml:space="preserve">
index ca5645f..536173d 100644 (file)
     <EmbeddedResource Include="ListAvailable.zh-CHS.resx">
       <DependentUpon>ListAvailable.cs</DependentUpon>
     </EmbeddedResource>
+    <EmbeddedResource Include="ListManage.en.resx">
+      <DependentUpon>ListManage.cs</DependentUpon>
+    </EmbeddedResource>
     <EmbeddedResource Include="ListManage.resx">
       <DependentUpon>ListManage.cs</DependentUpon>
     </EmbeddedResource>
     <EmbeddedResource Include="AppendSettingDialog.zh-CHS.resx">
       <DependentUpon>AppendSettingDialog.cs</DependentUpon>
     </EmbeddedResource>
+    <EmbeddedResource Include="ListManage.zh-CHS.resx">
+      <DependentUpon>ListManage.cs</DependentUpon>
+    </EmbeddedResource>
     <EmbeddedResource Include="TabsDialog.en.resx">
       <DependentUpon>TabsDialog.cs</DependentUpon>
     </EmbeddedResource>
index 84cd592..05a5b39 100644 (file)
@@ -33,6 +33,6 @@ using System.Runtime.InteropServices;
 // 既定値にすることができます:
 // [assembly: AssemblyVersion("1.0.*")]
 [assembly: AssemblyVersion("0.1.0.0")]
-[assembly: AssemblyFileVersion("1.0.9.1")]
+[assembly: AssemblyFileVersion("1.1.0.1")]
 
 [assembly: InternalsVisibleTo("OpenTween.Tests")]
\ No newline at end of file
index 54bb259..2b01559 100644 (file)
@@ -1,7 +1,7 @@
 //------------------------------------------------------------------------------
 // <auto-generated>
 //     このコードはツールによって生成されました。
-//     ランタイム バージョン:4.0.30319.18033
+//     ランタイム バージョン:4.0.30319.18034
 //
 //     このファイルへの変更は、以下の状況下で不正な動作の原因になったり、
 //     コードが再生成されるときに損失したりします。
@@ -625,18 +625,17 @@ namespace OpenTween.Properties {
         /// <summary>
         ///   更新履歴
         ///
-        ///==== Ver 1.1.0-beta1(2013/xx/xx)
+        ///==== Ver 1.1.1-beta1(2013/xx/xx)
         ///
-        ///==== Ver 1.0.9(2013/04/07)
-        /// * CHG: APIレートリミット関連の実装を修正
-        /// * FIX: アイコンキャッシュの破棄時にエラーが出ることがある問題を修正
-        /// * FIX: UserStreamsのunfollowイベントでエラーが起きていたのを修正
-        /// * FIX: プロフィール画像・サムネイルの表示切り替え時にエラーが起きる場合がある問題を修正
-        /// * FIX: タイムライン上のアイコンが空白のまま表示されない場合がある問題を修正 (thx @5px!)
-        /// * FIX: アカウント追加時の初回認証に失敗する問題を修正 (thx @polka_roco_!)
-        /// * FIX: ツールバー上のAPIレートリミット表示が正しく動作しなくなった問題を修正
-        /// * FIX: ツイタマなど一部のTwitterクライアントから投稿されたツイートの改行が正しく表示されない問題を修正 (thx @ohta8801, @kossetsu_inryo!)
-        /// * FIX: プロフィール編集画面で入力した  [残りの文字列は切り詰められました]&quot;; に類似しているローカライズされた文字列を検索します。
+        ///==== Ver 1.1.0(2013/05/15)
+        /// * NEW: タブの表示位置を画面上部に変更可能に (thx @aokomoriuta!)
+        /// * NEW: mobile.twitter.com/&lt;スクリーン名&gt;/status/&lt;ステータスID&gt; のURLも関連発言表示の対象に追加
+        /// * NEW: Favstarなどサードパーティ製サービスのパーマリンクURLも関連発言表示の対象に追加
+        /// * CHG: エラーログの出力先を変更 (OpenTween.exe と同じ場所に ErrorLogs フォルダが作成されます)
+        /// * FIX: スペースが含まれているURLをブラウザで開こうとするとURLが分断されて複数のタブが開いてしまう問題を修正 (thx @5px!)
+        /// * FIX: 画面更新時にInvalidOperationExceptionのエラーが発生する不具合を修正
+        /// * FIX: 関連発言表示が非公開アカウントのツイートに対して機能しない問題を修正
+        /// * FIX: 言語設定が英語の状態でリスト管理 [残りの文字列は切り詰められました]&quot;; に類似しているローカライズされた文字列を検索します。
         /// </summary>
         internal static string ChangeLog {
             get {
@@ -2197,6 +2196,15 @@ namespace OpenTween.Properties {
         }
         
         /// <summary>
+        ///   類似画像を検索 に類似しているローカライズされた文字列を検索します。
+        /// </summary>
+        internal static string SearchSimilarImageText {
+            get {
+                return ResourceManager.GetString("SearchSimilarImageText", resourceCulture);
+            }
+        }
+        
+        /// <summary>
         ///   [ユーザ・・・{0}]   に類似しているローカライズされた文字列を検索します。
         /// </summary>
         internal static string SetFiltersText1 {
index d2176cc..e84c817 100644 (file)
   <data name="DeleteMenuText2" xml:space="preserve">
     <value>Undo Retweet (&amp;D)</value>
   </data>
+  <data name="SearchSimilarImageText" xml:space="preserve">
+    <value>Search similar images</value>
+  </data>
 </root>
\ No newline at end of file
index a3aa0f8..e1dc9e8 100644 (file)
   <data name="BrowserStartFailed" xml:space="preserve">
     <value>ブラウザの起動に失敗しました。エラーコード: {0}</value>
   </data>
+  <data name="SearchSimilarImageText" xml:space="preserve">
+    <value>類似画像を検索</value>
+  </data>
 </root>
\ No newline at end of file
index 16459fe..475cbdd 100644 (file)
@@ -1,16 +1,23 @@
 更新履歴
 
-==== Ver 1.1.0-beta1(2013/xx/xx)
+==== Ver 1.1.1-beta1(2013/xx/xx)
  * 当バージョンから Twitter API v1.1 に対応しています
  * 旧 API v1 は太平洋標準時の 6/11 (Wed) に廃止される予定であると Twitter 社が予告しています
  * API v1.1 の使用に不都合がある場合は、ステータスバーのレートリミット表示をクリックすることで API v1 と切り替えることができます。
 
  * NEW: API v1.1 に対応
+ * NEW: サムネイル画像表示の右クリックメニューにGoogle画像検索を開くための項目を追加 (thx @moccos!)
+ * FIX: 画像投稿画面をキャンセルした場合にタイムライン表示に復帰できない不具合を修正 (thx @polka_roco_!)
+
+==== Ver 1.1.0(2013/05/15)
  * NEW: タブの表示位置を画面上部に変更可能に (thx @aokomoriuta!)
  * NEW: mobile.twitter.com/<スクリーン名>/status/<ステータスID> のURLも関連発言表示の対象に追加
  * NEW: Favstarなどサードパーティ製サービスのパーマリンクURLも関連発言表示の対象に追加
+ * CHG: エラーログの出力先を変更 (OpenTween.exe と同じ場所に ErrorLogs フォルダが作成されます)
  * FIX: スペースが含まれているURLをブラウザで開こうとするとURLが分断されて複数のタブが開いてしまう問題を修正 (thx @5px!)
  * FIX: 画面更新時にInvalidOperationExceptionのエラーが発生する不具合を修正
+ * FIX: 関連発言表示が非公開アカウントのツイートに対して機能しない問題を修正
+ * FIX: 言語設定が英語の状態でリスト管理の画面が翻訳されずに表示される問題を修正
 
 ==== Ver 1.0.9(2013/04/07)
  * CHG: APIレートリミット関連の実装を修正
index 25fd07b..ec54271 100644 (file)
@@ -3420,7 +3420,7 @@ namespace OpenTween
             {
                 foreach (var flt in this.BodyFilter)
                 {
-                    destination.BodyFilter.Add(string.Copy(flt));
+                    destination.BodyFilter.Add(flt);
                 }
             }
 
@@ -3428,7 +3428,7 @@ namespace OpenTween
             {
                 foreach (var flt in this.ExBodyFilter)
                 {
-                    destination.ExBodyFilter.Add(string.Copy(flt));
+                    destination.ExBodyFilter.Add(flt);
                 }
             }
 
index f93238b..c2e925f 100644 (file)
@@ -33,12 +33,20 @@ namespace OpenTween.Thumbnail.Services
     class SimpleThumbnailService : IThumbnailService
     {
         protected Regex regex;
-        protected string replacement;
+        protected string thumb_replacement;
+        protected string fullsize_replacement;
 
         public SimpleThumbnailService(string pattern, string replacement)
         {
             this.regex = new Regex(pattern, RegexOptions.IgnoreCase);
-            this.replacement = replacement;
+            this.thumb_replacement = replacement;
+        }
+
+        public SimpleThumbnailService(string pattern, string replacement, string file_replacement)
+        {
+            this.regex = new Regex(pattern, RegexOptions.IgnoreCase);
+            this.thumb_replacement = replacement;
+            this.fullsize_replacement = file_replacement;
         }
 
         public override ThumbnailInfo GetThumbnailInfo(string url, PostClass post)
@@ -51,14 +59,21 @@ namespace OpenTween.Thumbnail.Services
                 ImageUrl = url,
                 ThumbnailUrl = thumbnailUrl,
                 TooltipText = null,
+                FullSizeImageUrl = ReplaceUrl(url, this.fullsize_replacement)
             };
         }
 
         protected string ReplaceUrl(string url)
         {
+            return ReplaceUrl(url, this.thumb_replacement);
+        }
+
+        protected string ReplaceUrl(string url, string replacement)
+        {
+            if (replacement == null) return null;
             var match = this.regex.Match(url);
 
-            return match.Success ? match.Result(this.replacement) : null;
+            return match.Success ? match.Result(replacement) : null;
         }
     }
 }
index fa17947..8721b57 100644 (file)
@@ -48,25 +48,46 @@ namespace OpenTween.Thumbnail
                 new ImgAzyobuziNet(autoupdate: true),
 
                 // ImgUr
-                new SimpleThumbnailService(@"^http://(?:i\.)?imgur\.com/(\w+)(?:\..{3})?$", "http://img.imgur.com/${1}l.jpg"),
+                new SimpleThumbnailService(
+                    @"^http://(?:i\.)?imgur\.com/(\w+)(?:\..{3})?$",
+                    "http://img.imgur.com/${1}l.jpg",
+                    "http://img.imgur.com/${1}.jpg"),
 
                 // Twitpic
-                new SimpleThumbnailService(@"^http://(www\.)?twitpic\.com/(?<photoId>\w+)(/full/?)?$", "http://twitpic.com/show/thumb/${photoId}"),
+                new SimpleThumbnailService(
+                    @"^http://(www\.)?twitpic\.com/(?<photoId>\w+)(/full/?)?$",
+                    "http://twitpic.com/show/thumb/${photoId}",
+                    "http://twitpic.com/show/large/${photoId}"),
 
                 // yfrog
-                new SimpleThumbnailService(@"^http://yfrog\.com/(\w+)$", "${0}:small"),
+                new SimpleThumbnailService(
+                    @"^http://yfrog\.com/(\w+)$",
+                    "${0}:small",
+                    "${0}"),
 
                 // Lockerz
-                new SimpleThumbnailService(@"^http://(tweetphoto\.com/[0-9]+|pic\.gd/[a-z0-9]+|(lockerz|plixi)\.com/[ps]/[0-9]+)$", "http://api.plixi.com/api/tpapi.svc/imagefromurl?size=thumbnail&url=${0}"),
+                new SimpleThumbnailService(
+                    @"^http://(tweetphoto\.com/[0-9]+|pic\.gd/[a-z0-9]+|(lockerz|plixi)\.com/[ps]/[0-9]+)$",
+                    "http://api.plixi.com/api/tpapi.svc/imagefromurl?size=thumbnail&url=${0}",
+                    "http://api.plixi.com/api/tpapi.svc/imagefromurl?size=big&url=${0}"),
 
                 // MobyPicture
-                new SimpleThumbnailService(@"^http://moby\.to/(\w+)$", "http://mobypicture.com/?${1}:small"),
+                new SimpleThumbnailService(
+                    @"^http://moby\.to/(\w+)$",
+                    "http://mobypicture.com/?${1}:small",
+                    "http://mobypicture.com/?${1}:full"),
 
                 // 携帯百景
-                new SimpleThumbnailService(@"^http://movapic\.com/pic/(\w+)$", "http://image.movapic.com/pic/s_${1}.jpeg"),
+                new SimpleThumbnailService(
+                    @"^http://movapic\.com/pic/(\w+)$",
+                    "http://image.movapic.com/pic/s_${1}.jpeg",
+                    "http://image.movapic.com/pic/m_${1}.jpeg"),
 
                 // はてなフォトライフ
-                new SimpleThumbnailService(@"^http://f\.hatena\.ne\.jp/(([a-z])[a-z0-9_-]{1,30}[a-z0-9])/((\d{8})\d+)$", "http://img.f.hatena.ne.jp/images/fotolife/${2}/${1}/${4}/${3}_120.jpg"),
+                new SimpleThumbnailService(
+                    @"^http://f\.hatena\.ne\.jp/(([a-z])[a-z0-9_-]{1,30}[a-z0-9])/((\d{8})\d+)$",
+                    "http://img.f.hatena.ne.jp/images/fotolife/${2}/${1}/${4}/${3}_120.jpg",
+                    "http://img.f.hatena.ne.jp/images/fotolife/${2}/${1}/${4}/${3}.jpg"),
 
                 // PhotoShare
                 new SimpleThumbnailService(@"^http://(?:www\.)?bcphotoshare\.com/photos/\d+/(\d+)$", "http://images.bcphotoshare.com/storages/${1}/thumb180.jpg"),
@@ -75,10 +96,14 @@ namespace OpenTween.Thumbnail
                 new PhotoShareShortlink(@"^http://bctiny\.com/p(\w+)$"),
 
                 // img.ly
-                new SimpleThumbnailService(@"^http://img\.ly/(\w+)$", "http://img.ly/show/thumb/${1}"),
+                new SimpleThumbnailService(@"^http://img\.ly/(\w+)$",
+                    "http://img.ly/show/thumb/${1}",
+                    "http://img.ly/show/full/${1}"),
 
                 // Twitgoo
-                new SimpleThumbnailService(@"^http://twitgoo\.com/(\w+)$", "http://twitgoo.com/${1}/mini"),
+                new SimpleThumbnailService(@"^http://twitgoo\.com/(\w+)$",
+                    "http://twitgoo.com/${1}/mini",
+                    "http://twitgoo.com/${1}/img"),
 
                 // youtube
                 new Youtube(@"^http://(?:(www\.youtube\.com)|(youtu\.be))/(watch\?v=)?(?<videoid>([\w\-]+))", "http://i.ytimg.com/vi/${videoid}/default.jpg"),
@@ -87,7 +112,10 @@ namespace OpenTween.Thumbnail
                 new Nicovideo(@"^http://(?:(www|ext)\.nicovideo\.jp/watch|nico\.ms)/(?:sm|nm)?([0-9]+)(\?.+)?$", "http://www.nicovideo.jp/api/getthumbinfo/${id}"),
 
                 // ニコニコ静画
-                new SimpleThumbnailService(@"^http://(?:seiga\.nicovideo\.jp/seiga/|nico\.ms/)im(?<id>\d+)", "http://lohas.nicoseiga.jp/thumb/${id}q?"),
+                new SimpleThumbnailService(
+                    @"^http://(?:seiga\.nicovideo\.jp/seiga/|nico\.ms/)im(?<id>\d+)",
+                    "http://lohas.nicoseiga.jp/thumb/${id}q?",
+                    "http://lohas.nicoseiga.jp/thumb/${id}l?"),
 
                 // pixiv
                 new MetaThumbnailService(@"^http://www\.pixiv\.net/(member_illust|index)\.php\?(?=.*mode=(medium|big))(?=.*illust_id=(?<illustId>[0-9]+)).*$"),
@@ -96,7 +124,10 @@ namespace OpenTween.Thumbnail
                 new MetaThumbnailService(@"^http://www\.flickr\.com/.+$"),
 
                 // フォト蔵
-                new SimpleThumbnailService(@"^http://photozou\.jp/photo/show/(?<userId>[0-9]+)/(?<photoId>[0-9]+)", "http://photozou.jp/p/thumb/${photoId}"),
+                new SimpleThumbnailService(
+                    @"^http://photozou\.jp/photo/show/(?<userId>[0-9]+)/(?<photoId>[0-9]+)",
+                    "http://photozou.jp/p/thumb/${photoId}",
+                    "http://photozou.jp/p/img/${photoId}"),
 
                 // TwitVideo
                 new SimpleThumbnailService(@"^http://twitvideo\.jp/(\w+)$", "http://twitvideo.jp/img/thumb/${1}"),
@@ -123,10 +154,16 @@ namespace OpenTween.Thumbnail
                 new SimpleThumbnailService(@"^http://c[0-9]+\.cdn[0-9]+\.cloudfiles\.rackspacecloud\.com/[a-z_0-9]+", "${0}"),
 
                 // Instagram
-                new SimpleThumbnailService(@"^http://instagr\.am/p/.+/", "${0}media/?size=m"),
+                new SimpleThumbnailService(
+                    @"^http://instagr\.am/p/.+/",
+                    "${0}media/?size=m",
+                    "${0}media/?size=l"),
 
                 // pikubo
-                new SimpleThumbnailService(@"^http://pikubo\.me/([a-z0-9-_]+)", "http://pikubo.me/q/${1}"),
+                new SimpleThumbnailService(
+                    @"^http://pikubo\.me/([a-z0-9-_]+)",
+                    "http://pikubo.me/q/${1}",
+                    "http://pikubo.me/l/${1}"),
 
                 // Foursquare
                 new Services.Foursquare(@"^https?://(4sq|foursquare)\.com/.+"),
@@ -135,13 +172,22 @@ namespace OpenTween.Thumbnail
                 new Tinami(@"^http://www\.tinami\.com/view/(?<ContentId>\d+)$", "http://api.tinami.com/content/info?cont_id=${ContentId}&api_key=" + ApplicationSettings.TINAMIApiKey),
 
                 // pic.twitter.com
-                new SimpleThumbnailService(@"^https?://p\.twimg\.com/.*$", "${0}:thumb"),
+                new SimpleThumbnailService(
+                    @"^https?://p\.twimg\.com/.*$",
+                    "${0}:thumb",
+                    "${0}"),
 
                 // TwitrPix
-                new SimpleThumbnailService(@"^http://twitrpix\.com/(\w+)$", "http://img.twitrpix.com/thumb/${1}"),
+                new SimpleThumbnailService(
+                    @"^http://twitrpix\.com/(\w+)$",
+                    "http://img.twitrpix.com/thumb/${1}",
+                    "http://img.twitrpix.com/${1}"),
 
                 // Pckles
-                new SimpleThumbnailService(@"^https?://pckles\.com/\w+/\w+$", "${0}.resize.jpg"),
+                new SimpleThumbnailService(
+                    @"^https?://pckles\.com/\w+/\w+$",
+                    "${0}.resize.jpg",
+                    "${0}.jpg"),
 
                 // via.me
                 new ViaMe(@"^https?://via\.me/-(\w+)$", "http://via.me/api/v1/posts/$1"),
index a0e7dab..c1f9300 100644 (file)
@@ -31,5 +31,6 @@ namespace OpenTween.Thumbnail
         public string ImageUrl { get; set; }
         public string ThumbnailUrl { get; set; }
         public string TooltipText { get; set; }
+        public string FullSizeImageUrl { get; set; }
     }
 }
index 8b66a9c..d002583 100644 (file)
             this.ToolTip1.SetToolTip(this.tweetThumbnail1, resources.GetString("tweetThumbnail1.ToolTip"));
             this.tweetThumbnail1.ThumbnailLoading += new System.EventHandler(this.tweetThumbnail1_ThumbnailLoading);
             this.tweetThumbnail1.ThumbnailDoubleClick += new System.EventHandler<OpenTween.ThumbnailDoubleClickEventArgs>(this.tweetThumbnail1_ThumbnailDoubleClick);
+            this.tweetThumbnail1.ThumbnailImageSearchClick += new System.EventHandler<OpenTween.ThumbnailImageSearchEventArgs>(this.tweetThumbnail1_ThumbnailImageSearchClick);
             // 
             // MenuStrip1
             // 
index 4167ef7..9a50066 100644 (file)
@@ -5994,6 +5994,9 @@ namespace OpenTween
 
         private void CheckNewVersion(bool startup = false)
         {
+            if (ApplicationSettings.VersionInfoUrl == null)
+                return; // 更新チェック無効化
+
             if (string.IsNullOrEmpty(MyCommon.fileVersion))
             {
                 return;
@@ -10798,9 +10801,19 @@ namespace OpenTween
 
                 if (MyCommon._endingFlag) return;
 
-                //バージョンチェック(引数:起動時チェックの場合はtrue・・・チェック結果のメッセージを表示しない)
-                if (SettingDialog.StartupVersion)
-                    CheckNewVersion(true);
+                if (ApplicationSettings.VersionInfoUrl != null)
+                {
+                    //バージョンチェック(引数:起動時チェックの場合はtrue・・・チェック結果のメッセージを表示しない)
+                    if (SettingDialog.StartupVersion)
+                        CheckNewVersion(true);
+                }
+                else
+                {
+                    // ApplicationSetting.cs の設定により更新チェックが無効化されている場合
+                    this.VerUpMenuItem.Enabled = false;
+                    this.VerUpMenuItem.Available = false;
+                    this.ToolStripSeparator16.Available = false; // VerUpMenuItem の一つ上にあるセパレータ
+                }
 
                 // 取得失敗の場合は再試行する
                 if (!tw.GetFollowersSuccess && SettingDialog.StartupFollowers)
@@ -12423,6 +12436,8 @@ namespace OpenTween
             {
                 ImageSelectedPicture.Image = ImageSelectedPicture.InitialImage;
                 ImageSelectedPicture.Tag = MyCommon.UploadFileType.Invalid;
+                TimelinePanel.Visible = true;
+                TimelinePanel.Enabled = true;
                 ImageSelectionPanel.Visible = false;
                 ImageSelectionPanel.Enabled = false;
                 ((DetailsListView)ListTab.SelectedTab.Tag).Focus();
@@ -12480,6 +12495,8 @@ namespace OpenTween
         private void ImageCancelButton_Click(object sender, EventArgs e)
         {
             ImagefilePathText.CausesValidation = false;
+            TimelinePanel.Visible = true;
+            TimelinePanel.Enabled = true;
             ImageSelectionPanel.Visible = false;
             ImageSelectionPanel.Enabled = false;
             ((DetailsListView)ListTab.SelectedTab.Tag).Focus();
@@ -13261,6 +13278,11 @@ namespace OpenTween
             this.OpenThumbnailPicture(e.Thumbnail);
         }
 
+        private void tweetThumbnail1_ThumbnailImageSearchClick(object sender, ThumbnailImageSearchEventArgs e)
+        {
+            this.OpenUriAsync(e.ImageUrl);
+        }
+
         private void OpenThumbnailPicture(ThumbnailInfo thumbnail)
         {
             this.OpenUriAsync(Uri.EscapeUriString(thumbnail.ImageUrl));
index 6649932..033f172 100644 (file)
@@ -43,6 +43,7 @@ namespace OpenTween
 
         public event EventHandler ThumbnailLoading;
         public event EventHandler<ThumbnailDoubleClickEventArgs> ThumbnailDoubleClick;
+        public event EventHandler<ThumbnailImageSearchEventArgs> ThumbnailImageSearchClick;
 
         public ThumbnailInfo Thumbnail
         {
@@ -79,6 +80,7 @@ namespace OpenTween
 
                             picbox.Tag = thumb;
                             picbox.LoadAsync(thumb.ThumbnailUrl);
+                            picbox.ContextMenu = CreateContextMenu(thumb);
 
                             var tooltipText = thumb.TooltipText;
                             if (!string.IsNullOrEmpty(tooltipText))
@@ -105,6 +107,48 @@ namespace OpenTween
             return this.task;
         }
 
+        private ContextMenu CreateContextMenu(ThumbnailInfo thumb)
+        {
+            var contextMenu = new ContextMenu();
+            contextMenu.MenuItems.Add(CreateImageSearchMenuItem(thumb));
+            return contextMenu;
+        }
+
+        private MenuItem CreateImageSearchMenuItem(ThumbnailInfo thumb)
+        {
+            var item = new MenuItem();
+            item.Text = Properties.Resources.SearchSimilarImageText;
+            string search_targe_url =
+                thumb.FullSizeImageUrl != null
+                    ? thumb.FullSizeImageUrl
+                    : thumb.ThumbnailUrl != null
+                        ? thumb.ThumbnailUrl
+                        : null;
+
+            if (search_targe_url != null)
+            {
+                item.Click += (sender, e) =>
+                {
+                    string uri = GetImageSearchUri(search_targe_url);
+                    if (this.ThumbnailImageSearchClick != null)
+                    {
+                        this.ThumbnailImageSearchClick(this, new ThumbnailImageSearchEventArgs(uri));
+                    }
+                };
+            }
+            else
+            {
+                item.Enabled = false;
+            }
+
+            return item;
+        }
+
+        private string GetImageSearchUri(string image_uri)
+        {
+            return @"https://www.google.com/searchbyimage?image_url=" + Uri.EscapeDataString(image_uri);
+        }
+
         protected virtual List<ThumbnailInfo> GetThumbailInfo(PostClass post)
         {
             return ThumbnailGenerator.GetThumbnails(post);
@@ -230,4 +274,14 @@ namespace OpenTween
             this.Thumbnail = thumbnail;
         }
     }
+
+    public class ThumbnailImageSearchEventArgs : EventArgs
+    {
+        public string ImageUrl { get; private set; }
+
+        public ThumbnailImageSearchEventArgs(string url)
+        {
+            this.ImageUrl = url;
+        }
+    }
 }
index 4faef7c..58396a1 100644 (file)
@@ -2530,27 +2530,30 @@ namespace OpenTween
             return CreatePostsFromJson(content, MyCommon.WORKERTYPE.List, tab, read, count, ref tab.OldestId);
         }
 
-
-        private PostClass CheckReplyToPost(List<PostClass> relPosts)
+        /// <summary>
+        /// startStatusId からリプライ先の発言を辿る。発言は posts 以外からは検索しない。
+        /// </summary>
+        /// <returns>posts の中から検索されたリプライチェインの末端</returns>
+        internal static PostClass FindTopOfReplyChain(IDictionary<Int64, PostClass> posts, Int64 startStatusId)
         {
-            var tmpPost = relPosts[0];
-            PostClass lastPost = null;
-            while (tmpPost != null)
-            {
-                if (tmpPost.InReplyToStatusId == 0) return null;
-                lastPost = tmpPost;
-                var replyToPost = from p in relPosts
-                                  where p.StatusId == tmpPost.InReplyToStatusId
-                                  select p;
-                tmpPost = replyToPost.FirstOrDefault();
-            }
-            return lastPost;
+            if (!posts.ContainsKey(startStatusId))
+                throw new ArgumentException("startStatusId (" + startStatusId + ") が posts の中から見つかりませんでした。");
+
+            var nextPost = posts[startStatusId];
+            while (nextPost.InReplyToStatusId != 0)
+            {
+                if (!posts.ContainsKey(nextPost.InReplyToStatusId))
+                    break;
+                nextPost = posts[nextPost.InReplyToStatusId];
+            }
+
+            return nextPost;
         }
 
         public string GetRelatedResult(bool read, TabClass tab)
         {
             var rslt = "";
-            var relPosts = new List<PostClass>();
+            var relPosts = new Dictionary<Int64, PostClass>();
             if (tab.RelationTargetPost.TextFromApi.Contains("@") && tab.RelationTargetPost.InReplyToStatusId == 0)
             {
                 //検索結果対応
@@ -2566,23 +2569,89 @@ namespace OpenTween
                     tab.RelationTargetPost = p;
                 }
             }
-            relPosts.Add(tab.RelationTargetPost.Clone());
-            var tmpPost = relPosts[0];
+            relPosts.Add(tab.RelationTargetPost.StatusId, tab.RelationTargetPost.Clone());
+
+            // 一周目: 非公式な related_results API を使用してリプライチェインを辿る
+            var nextPost = relPosts[tab.RelationTargetPost.StatusId];
+            var loopCount = 1;
             do
             {
-                rslt = this.GetRelatedResultsApi(read, tmpPost, tab, relPosts);
+                rslt = this.GetRelatedResultsApi(nextPost, relPosts);
                 if (!string.IsNullOrEmpty(rslt)) break;
-                tmpPost = CheckReplyToPost(relPosts);
-            } while (tmpPost != null);
+                nextPost = FindTopOfReplyChain(relPosts, nextPost.StatusId);
+            } while (nextPost.InReplyToStatusId != 0 && loopCount++ <= 5);
+
+            // 二周目: in_reply_to_status_id を使用してリプライチェインを辿る
+            nextPost = FindTopOfReplyChain(relPosts, tab.RelationTargetPost.StatusId);
+            loopCount = 1;
+            while (nextPost.InReplyToStatusId != 0 && loopCount++ <= 20)
+            {
+                var inReplyToId = nextPost.InReplyToStatusId;
+
+                var inReplyToPost = TabInformations.GetInstance()[inReplyToId];
+                if (inReplyToPost != null)
+                {
+                    inReplyToPost = inReplyToPost.Clone();
+                }
+                else
+                {
+                    var errorText = this.GetStatusApi(read, inReplyToId, ref inReplyToPost);
+                    if (!string.IsNullOrEmpty(errorText))
+                    {
+                        rslt = errorText;
+                        break;
+                    }
+                }
+
+                relPosts.Add(inReplyToPost.StatusId, inReplyToPost);
+
+                nextPost = FindTopOfReplyChain(relPosts, nextPost.StatusId);
+            }
+
+            //MRTとかに対応のためツイート内にあるツイートを指すURLを取り込む
+            var text = tab.RelationTargetPost.Text;
+            var ma = Twitter.StatusUrlRegex.Matches(text).Cast<Match>()
+                .Concat(Twitter.ThirdPartyStatusUrlRegex.Matches(text).Cast<Match>());
+            foreach (var _match in ma)
+            {
+                Int64 _statusId;
+                if (Int64.TryParse(_match.Groups["StatusId"].Value, out _statusId))
+                {
+                    if (relPosts.ContainsKey(_statusId))
+                        continue;
+
+                    PostClass p = null;
+                    var _post = TabInformations.GetInstance()[_statusId];
+                    if (_post == null)
+                    {
+                        this.GetStatusApi(read, _statusId, ref p);
+                    }
+                    else
+                    {
+                        p = _post.Clone();
+                    }
+
+                    if (p != null)
+                        relPosts.Add(p.StatusId, p);
+                }
+            }
+
+            relPosts.Values.ToList().ForEach(p =>
+            {
+                if (p.IsMe && !read && this._readOwnPost)
+                    p.IsRead = true;
+                else
+                    p.IsRead = read;
+
+                p.RelTabName = tab.TabName;
+                TabInformations.GetInstance().AddPost(p);
+            });
 
-            relPosts.ForEach(p => TabInformations.GetInstance().AddPost(p));
             return rslt;
         }
 
-        private string GetRelatedResultsApi(bool read,
-                                             PostClass post,
-                                             TabClass tab,
-                                             List<PostClass> relatedPosts)
+        private string GetRelatedResultsApi(PostClass post,
+                                            IDictionary<Int64, PostClass> relatedPosts)
         {
             if (Twitter.AccountState != MyCommon.ACCOUNT_STATE.Valid) return "";
 
@@ -2635,100 +2704,18 @@ namespace OpenTween
                 return "Invalid Json!";
             }
 
-            var targetItem = post;
-            if (targetItem == null)
-            {
-                return "";
-            }
-            else
-            {
-                targetItem = targetItem.Clone();
-            }
-            targetItem.RelTabName = tab.TabName;
-            TabInformations.GetInstance().AddPost(targetItem);
-
-            PostClass replyToItem = null;
-            var replyToUserName = targetItem.InReplyToUser;
-            if (targetItem.InReplyToStatusId > 0 && TabInformations.GetInstance()[targetItem.InReplyToStatusId] != null)
-            {
-                replyToItem = TabInformations.GetInstance()[targetItem.InReplyToStatusId].Clone();
-                replyToItem.IsRead = read;
-                if (replyToItem.IsMe && !read && _readOwnPost) replyToItem.IsRead = true;
-                replyToItem.RelTabName = tab.TabName;
-            }
-
-            var replyAdded = false;
             foreach (var relatedData in items)
             {
                 foreach (var result in relatedData.Results)
                 {
                     var item = CreatePostsFromStatusData(result.Status);
                     if (item == null) continue;
-                    if (targetItem.InReplyToStatusId == item.StatusId)
-                    {
-                        replyToItem = null;
-                        replyAdded = true;
-                    }
-                    item.IsRead = read;
-                    if (item.IsMe && !read && _readOwnPost) item.IsRead = true;
-                    if (tab != null) item.RelTabName = tab.TabName;
                     //非同期アイコン取得&StatusDictionaryに追加
-                    relatedPosts.Add(item);
-                }
-            }
-            if (replyToItem != null)
-            {
-                relatedPosts.Add(replyToItem);
-            }
-            else if (targetItem.InReplyToStatusId > 0 && !replyAdded)
-            {
-                PostClass p = null;
-                var rslt = "";
-                rslt = GetStatusApi(read, targetItem.InReplyToStatusId, ref p);
-                if (string.IsNullOrEmpty(rslt))
-                {
-                    p.IsRead = read;
-                    p.RelTabName = tab.TabName;
-                    relatedPosts.Add(p);
+                    if (!relatedPosts.ContainsKey(item.StatusId))
+                        relatedPosts.Add(item.StatusId, item);
                 }
-                return rslt;
             }
 
-            //発言者・返信先ユーザーの直近10発言取得
-            //var rslt = this.GetUserTimelineApi(read, 10, "", tab);
-            //if (!string.IsNullOrEmpty(rslt)) return rslt;
-            //if (!string.IsNullOrEmpty(replyToUserName))
-            //    rslt = this.GetUserTimelineApi(read, 10, replyToUserName, tab);
-            //}
-            //return rslt;
-
-            //MRTとかに対応のためツイート内にあるツイートを指すURLを取り込む
-            var text = tab.RelationTargetPost.Text;
-            var ma = Twitter.StatusUrlRegex.Matches(text).Cast<Match>()
-                .Concat(Twitter.ThirdPartyStatusUrlRegex.Matches(text).Cast<Match>());
-            foreach (var _match in ma)
-            {
-                Int64 _statusId;
-                if (Int64.TryParse(_match.Groups["StatusId"].Value, out _statusId))
-                {
-                    PostClass p = null;
-                    var _post = TabInformations.GetInstance()[_statusId];
-                    if (_post == null)
-                    {
-                        var rslt = this.GetStatusApi(read, _statusId, ref p);
-                    }
-                    else
-                    {
-                        p = _post.Clone();
-                    }
-                    if (p != null)
-                    {
-                        p.IsRead = read;
-                        p.RelTabName = tab.TabName;
-                        relatedPosts.Add(p);
-                    }
-                }
-            }
             return "";
         }
 
@@ -4219,7 +4206,7 @@ namespace OpenTween
                 var mS = Regex.Match(post.Source, ">(?<source>.+)<");
                 if (mS.Success)
                 {
-                    post.SourceHtml = string.Copy(ShortUrl.Resolve(PreProcessUrl(post.Source), false));
+                    post.SourceHtml = ShortUrl.Resolve(PreProcessUrl(post.Source), false);
                     post.Source = WebUtility.HtmlDecode(mS.Result("${source}"));
                 }
                 else
@@ -4240,7 +4227,7 @@ namespace OpenTween
                 }
                 else
                 {
-                    post.SourceHtml = string.Copy(post.Source);
+                    post.SourceHtml = post.Source;
                 }
             }
         }
index d22372d..71f2528 100644 (file)
@@ -85,6 +85,7 @@ namespace OpenTween
             }
         }
         #endregion
+
         #region "タスクトレイアイコンのクリック"
         // 指定されたクラス名およびウィンドウ名と一致するトップレベルウィンドウのハンドルを取得します
         [DllImport("user32.dll", CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
@@ -492,12 +493,6 @@ namespace OpenTween
         }
         #endregion
 
-        //画面をブリンクするためのWin32API。起動時に10ページ読み取りごとに継続確認メッセージを表示する際の通知強調用
-        [DllImport("user32.dll")]
-        private static extern int FlashWindow(
-            IntPtr hwnd,
-            bool bInvert);
-
         #region "画面ブリンク用"
         public static bool FlashMyWindow(IntPtr hwnd,
             FlashSpecification flashType,
@@ -551,11 +546,6 @@ namespace OpenTween
         private const Int32 FLASHW_TIMERNOFG = 0xC;
         #endregion
 
-        [DllImport("user32.dll")]
-        public static extern bool ValidateRect(
-            IntPtr hwnd,
-            IntPtr rect);
-
         #region "スクリーンセーバー起動中か判定"
         [DllImport("user32", CharSet = CharSet.Auto)]
         private static extern int SystemParametersInfo(
@@ -566,14 +556,12 @@ namespace OpenTween
         // returns non-zero value if function succeeds
 
         //スクリーンセーバーが起動中かを取得する定数
-        private const int SPI_GETSCREENSAVERRUNNING = 0x61;
+        private const int SPI_GETSCREENSAVERRUNNING = 0x0072;
 
         public static bool IsScreenSaverRunning()
         {
-            var ret = 0;
             var isRunning = false;
-
-            ret = SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, ref isRunning, 0);
+            SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, ref isRunning, 0);
             return isRunning;
         }
         #endregion