using System.Net;
using System.Net.Http;
using System.Reflection;
+using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using OpenTween.Connection;
using OpenTween.Models;
using OpenTween.OpenTweenCustomControl;
+using OpenTween.Setting;
using OpenTween.Thumbnail;
namespace OpenTween
//設定ファイル関連
//private SettingToConfig _cfg; //旧
- private SettingLocal _cfgLocal;
+ internal SettingLocal _cfgLocal;
private SettingCommon _cfgCommon;
//twitter解析部
private GrowlHelper gh = new GrowlHelper(Application.ProductName);
//サブ画面インスタンス
- private SearchWordDialog SearchDialog = new SearchWordDialog(); //検索画面インスタンス
+ internal SearchWordDialog SearchDialog = new SearchWordDialog(); //検索画面インスタンス
private OpenURL UrlDialog = new OpenURL();
public AtIdSupplement AtIdSupl; //@id補助
public AtIdSupplement HashSupl; //Hashtag補助
private bool osResumed = false;
//////////////////////////////////////////////////////////////////////////////////////////////////////////
- private string _postBrowserStatusText = "";
-
private bool _colorize = false;
private System.Timers.Timer TimerTimeline = new System.Timers.Timer();
- private ImageListViewItem displayItem;
-
private string recommendedStatusFooter;
//URL短縮のUndo用
private Stack<Tuple<TabPage, PostClass>> selectPostChains = new Stack<Tuple<TabPage, PostClass>>(); //ポスト選択履歴
//検索処理タイプ
- private enum SEARCHTYPE
+ internal enum SEARCHTYPE
{
DialogSearch,
NextSearch,
//Win32Api.SetProxy(HttpConnection.ProxyType.Specified, "127.0.0.1", 8080, "user", "pass")
- new InternetSecurityManager(PostBrowser);
- this.PostBrowser.AllowWebBrowserDrop = false; // COMException を回避するため、ActiveX の初期化が終わってから設定する
-
MyCommon.TwitterApiInfo.AccessLimitUpdated += TwitterApiStatus_AccessLimitUpdated;
Microsoft.Win32.SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
//Twitter用通信クラス初期化
Networking.DefaultTimeout = TimeSpan.FromSeconds(this._cfgCommon.DefaultTimeOut);
+ Networking.UploadImageTimeout = TimeSpan.FromSeconds(this._cfgCommon.UploadImageTimeout);
Networking.SetWebProxy(this._cfgLocal.ProxyType,
this._cfgLocal.ProxyAddress, this._cfgLocal.ProxyPort,
this._cfgLocal.ProxyUser, this._cfgLocal.ProxyPassword);
ImageSelector.Initialize(tw, this.tw.Configuration, _cfgCommon.UseImageServiceName, _cfgCommon.UseImageService);
//ハッシュタグ/@id関連
- AtIdSupl = new AtIdSupplement(SettingAtIdList.Load().AtIdList, "@");
+ AtIdSupl = new AtIdSupplement(SettingManager.AtIdList.AtIdList, "@");
HashSupl = new AtIdSupplement(_cfgCommon.HashTags, "#");
HashMgr = new HashtagManage(HashSupl,
_cfgCommon.HashTags.ToArray(),
//アイコンリスト作成
this.IconCache = new ImageCache();
+ this.tweetDetailsView.IconCache = this.IconCache;
//フォント&文字色&背景色保持
_fntUnread = this._cfgLocal.FontUnread;
this.StatusText.Multiline = false; // _cfgLocal.StatusMultiline の設定は後で反映される
this.SplitContainer2.Panel2MinSize = this.StatusText.Height;
- // NameLabel のフォントを OTBaseForm.GlobalFont に変更
- this.NameLabel.Font = this.ReplaceToGlobalFont(this.NameLabel.Font);
-
// 必要であれば、発言一覧と発言詳細部・入力欄の上下を入れ替える
SplitContainer1.IsPanelInverted = !this._cfgCommon.StatusAreaAtBottom;
UnreadStripMenuItem.Enabled = false;
}
- //発言詳細部の初期化
- NameLabel.Text = "";
- DateTimeLabel.Text = "";
- SourceLinkLabel.Text = "";
-
//リンク先URL表示部の初期化(画面左下)
StatusLabelUrl.Text = "";
//状態表示部の初期化(画面右下)
detailHtmlFormatHeader = detailHtmlFormatHeader
.Replace("%FONT_FAMILY%", _fntDetail.Name)
.Replace("%FONT_SIZE%", _fntDetail.Size.ToString())
- .Replace("%FONT_COLOR%", _clDetail.R.ToString() + "," + _clDetail.G.ToString() + "," + _clDetail.B.ToString())
- .Replace("%LINK_COLOR%", _clDetailLink.R.ToString() + "," + _clDetailLink.G.ToString() + "," + _clDetailLink.B.ToString())
- .Replace("%BG_COLOR%", _clDetailBackcolor.R.ToString() + "," + _clDetailBackcolor.G.ToString() + "," + _clDetailBackcolor.B.ToString())
+ .Replace("%FONT_COLOR%", $"{_clDetail.R},{_clDetail.G},{_clDetail.B}")
+ .Replace("%LINK_COLOR%", $"{_clDetailLink.R},{_clDetailLink.G},{_clDetailLink.B}")
+ .Replace("%BG_COLOR%", $"{_clDetailBackcolor.R},{_clDetailBackcolor.G},{_clDetailBackcolor.B}")
.Replace("%BG_REPLY_COLOR%", $"{_clAtTo.R}, {_clAtTo.G}, {_clAtTo.B}");
}
private void LoadConfig()
{
- _cfgCommon = SettingCommon.Load();
- SettingCommon.Instance = this._cfgCommon;
- if (_cfgCommon.UserAccounts == null || _cfgCommon.UserAccounts.Count == 0)
- {
- _cfgCommon.UserAccounts = new List<UserAccount>();
- if (!string.IsNullOrEmpty(_cfgCommon.UserName))
- {
- UserAccount account = new UserAccount();
- account.Username = _cfgCommon.UserName;
- account.UserId = _cfgCommon.UserId;
- account.Token = _cfgCommon.Token;
- account.TokenSecret = _cfgCommon.TokenSecret;
-
- _cfgCommon.UserAccounts.Add(account);
- }
- }
+ SettingManager.LoadAll();
- _cfgLocal = SettingLocal.Load();
+ this._cfgCommon = SettingManager.Common;
+ this._cfgLocal = SettingManager.Local;
// v1.2.4 以前の設定には ScaleDimension の項目がないため、現在の DPI と同じとして扱う
if (_cfgLocal.ScaleDimension.IsEmpty)
_cfgLocal.ScaleDimension = this.CurrentAutoScaleDimensions;
- var tabsSetting = SettingTabs.Load().Tabs;
- foreach (var tabSetting in tabsSetting)
+ var tabSettings = SettingManager.Tabs;
+ foreach (var tabSetting in tabSettings.Tabs)
{
TabModel tab;
switch (tabSetting.TabType)
private void RefreshTimeline()
{
+ var curTabModel = this._statuses.Tabs[this._curTab.Text];
+
// 現在表示中のタブのスクロール位置を退避
- var curListScroll = this.SaveListViewScroll(this._curList, this._statuses.Tabs[this._curTab.Text]);
+ var curListScroll = this.SaveListViewScroll(this._curList, curTabModel);
// 各タブのリスト上の選択位置などを退避
var listSelections = this.SaveListViewSelection();
if (MyCommon._endingFlag) return;
- //リストに反映&選択状態復元
- try
+ // リストに反映&選択状態復元
+ foreach (var tabPage in this.ListTab.TabPages.Cast<TabPage>())
{
- foreach (TabPage tab in ListTab.TabPages)
+ var listView = (DetailsListView)tabPage.Tag;
+ var tabModel = this._statuses.Tabs[tabPage.Text];
+
+ if (listView.VirtualListSize != tabModel.AllCount || isDelete)
{
- DetailsListView lst = (DetailsListView)tab.Tag;
- TabModel tabInfo = _statuses.Tabs[tab.Text];
- if (isDelete || lst.VirtualListSize != tabInfo.AllCount)
+ using (ControlTransaction.Update(listView))
{
- using (ControlTransaction.Update(lst))
- {
- if (lst.Equals(_curList))
- {
- this.PurgeListViewItemCache();
- }
- try
- {
- lst.VirtualListSize = tabInfo.AllCount; //リスト件数更新
- }
- catch (Exception)
- {
- //アイコン描画不具合あり?
- }
+ if (listView == this._curList)
+ this.PurgeListViewItemCache();
- // 選択位置などを復元
- this.RestoreListViewSelection(lst, tabInfo, listSelections[tabInfo.TabName]);
+ try
+ {
+ // リスト件数更新
+ listView.VirtualListSize = tabModel.AllCount;
+ }
+ catch (NullReferenceException ex)
+ {
+ // WinForms 内部で ListView.set_TopItem が発生させている例外
+ // https://ja.osdn.net/ticket/browse.php?group_id=6526&tid=36588
+ MyCommon.TraceOut(ex, $"TabType: {tabModel.TabType}, Count: {tabModel.AllCount}, ListSize: {listView.VirtualListSize}");
}
+
+ // 選択位置などを復元
+ this.RestoreListViewSelection(listView, tabModel, listSelections[tabModel.TabName]);
}
- if (tabInfo.UnreadCount > 0)
- if (this._cfgCommon.TabIconDisp)
- if (tab.ImageIndex == -1) tab.ImageIndex = 0; //タブアイコン
}
- if (!this._cfgCommon.TabIconDisp) ListTab.Refresh();
}
- catch (Exception)
+
+ if (addCount > 0)
{
- //ex.Data["Msg"] = "Ref1, UseAPI=" + SettingDialog.UseAPI.ToString();
- //throw;
+ if (this._cfgCommon.TabIconDisp)
+ {
+ foreach (var tabPage in this.ListTab.TabPages.Cast<TabPage>())
+ {
+ var tabModel = this._statuses.Tabs[tabPage.Text];
+ if (tabModel.UnreadCount > 0 && tabPage.ImageIndex != 0)
+ tabPage.ImageIndex = 0; // 未読アイコン
+ }
+ }
+ else
+ {
+ this.ListTab.Refresh();
+ }
}
// スクロール位置を復元
- this.RestoreListViewScroll(this._curList, this._statuses.Tabs[this._curTab.Text], curListScroll);
+ this.RestoreListViewScroll(this._curList, curTabModel, curListScroll);
//新着通知
NotifyNewPosts(notifyPosts, soundFile, addCount, newMentionOrDm);
if (listScroll.ScrollLockMode == ScrollLockMode.FixedToItem)
{
- var topItem = listView.TopItem;
- if (topItem != null)
- listScroll.TopItemStatusId = tab.GetStatusIdAt(topItem.Index);
+ var topItemIndex = listView.TopItem?.Index ?? -1;
+ if (topItemIndex != -1 && topItemIndex < tab.AllCount)
+ listScroll.TopItemStatusId = tab.GetStatusIdAt(topItemIndex);
}
return listScroll;
var listView = (DetailsListView)tabPage.Tag;
var tab = _statuses.Tabs[tabPage.Text];
- ListViewSelection listStatus;
- if (listView.VirtualListSize != 0)
- {
- listStatus = new ListViewSelection
- {
- SelectedStatusIds = this.GetSelectedStatusIds(listView, tab),
- FocusedStatusId = this.GetFocusedStatusId(listView, tab),
- SelectionMarkStatusId = this.GetSelectionMarkStatusId(listView, tab),
- };
- }
- else
- {
- listStatus = new ListViewSelection
- {
- SelectedStatusIds = new long[0],
- SelectionMarkStatusId = null,
- FocusedStatusId = null,
- };
- }
-
- listsDict[tab.TabName] = listStatus;
+ listsDict[tab.TabName] = this.SaveListViewSelection(listView, tab);
}
return listsDict;
}
+ /// <summary>
+ /// <see cref="ListView"/> の選択状態を <see cref="ListViewSelection"/> として返します
+ /// </summary>
+ private ListViewSelection SaveListViewSelection(DetailsListView listView, TabModel tab)
+ {
+ if (listView.VirtualListSize == 0)
+ {
+ return new ListViewSelection
+ {
+ SelectedStatusIds = new long[0],
+ SelectionMarkStatusId = null,
+ FocusedStatusId = null,
+ };
+ }
+
+ return new ListViewSelection
+ {
+ SelectedStatusIds = this.GetSelectedStatusIds(listView, tab),
+ FocusedStatusId = this.GetFocusedStatusId(listView, tab),
+ SelectionMarkStatusId = this.GetSelectionMarkStatusId(listView, tab),
+ };
+ }
+
private long[] GetSelectedStatusIds(DetailsListView listView, TabModel tab)
{
var selectedIndices = listView.SelectedIndices;
private long? GetFocusedStatusId(DetailsListView listView, TabModel tab)
{
- var focusedItem = listView.FocusedItem;
+ var index = listView.FocusedItem?.Index ?? -1;
- return focusedItem != null ? tab.GetStatusIdAt(focusedItem.Index) : (long?)null;
+ return index != -1 && index < tab.AllCount ? tab.GetStatusIdAt(index) : (long?)null;
}
private long? GetSelectionMarkStatusId(DetailsListView listView, TabModel tab)
{
- var selectionMarkIndex = listView.SelectionMark;
+ var index = listView.SelectionMark;
- return selectionMarkIndex != -1 ? tab.GetStatusIdAt(selectionMarkIndex) : (long?)null;
+ return index != -1 && index < tab.AllCount ? tab.GetStatusIdAt(index) : (long?)null;
}
/// <summary>
}
/// <summary>
- /// <see cref="SaveListViewStatus"/> によって保存された選択状態を復元します
+ /// <see cref="SaveListViewSelection"/> によって保存された選択状態を復元します
/// </summary>
private void RestoreListViewSelection(DetailsListView listView, TabModel tab, ListViewSelection listSelection)
{
p.Report(errMsg);
this._myStatusError = true;
}
+ catch (UnauthorizedAccessException ex)
+ {
+ // アップロード対象のファイルが開けなかった場合など
+ errMsg = $"Err:{ex.Message}(PostMessage)";
+ p.Report(errMsg);
+ this._myStatusError = true;
+ }
finally
{
// 使い終わった MediaItem は破棄する
!errMsg.StartsWith("OK:", StringComparison.Ordinal) &&
!errMsg.StartsWith("Warn:", StringComparison.Ordinal))
{
+ var message = string.Format(Properties.Resources.StatusUpdateFailed, errMsg, status.status);
+
var ret = MessageBox.Show(
- string.Format(
- "{0} ---> [ " + errMsg + " ]" + Environment.NewLine +
- "\"" + status.status + "\"" + Environment.NewLine +
- "{1}",
- Properties.Resources.StatusUpdateFailed1,
- Properties.Resources.StatusUpdateFailed2),
+ message,
"Failed to update status",
MessageBoxButtons.RetryCancel,
MessageBoxIcon.Question);
var progress = new Progress<string>(x => this.StatusLabel.Text = x);
await this.RetweetAsyncInternal(progress, this.workerCts.Token, statusIds);
+
+ if (this._cfgCommon.PostAndGet && !this.tw.UserStreamActive)
+ await this.GetHomeTimelineAsync();
}
catch (WebApiException ex)
{
p.Report("Posting...");
- var retweetTasks = from statusId in statusIds
- select this.tw.PostRetweet(statusId, read);
-
- await Task.WhenAll(retweetTasks)
- .ConfigureAwait(false);
+ foreach (var statusId in statusIds)
+ {
+ await this.tw.PostRetweet(statusId, read).ConfigureAwait(false);
+ }
if (ct.IsCancellationRequested)
return;
if (this._postTimestamps[i] < oneHour)
this._postTimestamps.RemoveAt(i);
}
-
- if (this._cfgCommon.PostAndGet && !this.tw.UserStreamActive)
- await this.GetHomeTimelineAsync();
}
private async Task RefreshFollowerIdsAsync()
{
// 表示上の列の位置から ColumnHeader を求める
var col = this._curList.Columns.Cast<ColumnHeader>()
- .Where(x => x.DisplayIndex == columnIndex)
- .FirstOrDefault();
+ .FirstOrDefault(x => x.DisplayIndex == columnIndex);
if (col == null)
return;
FavorareMenuItem.Enabled = true;
ShowRelatedStatusesMenuItem.Enabled = true; //PublicSearchの時問題出るかも
- if (_curPost.IsMe)
+ if (!_curPost.CanRetweetBy(this.twitterApi.CurrentUserId))
{
- ReTweetStripMenuItem.Enabled = false; //公式RTは無効に
- ReTweetUnofficialStripMenuItem.Enabled = true;
- QuoteStripMenuItem.Enabled = true;
- FavoriteRetweetContextMenu.Enabled = false; //公式RTは無効に
- FavoriteRetweetUnofficialContextMenu.Enabled = true;
+ ReTweetStripMenuItem.Enabled = false;
+ ReTweetUnofficialStripMenuItem.Enabled = false;
+ QuoteStripMenuItem.Enabled = false;
+ FavoriteRetweetContextMenu.Enabled = false;
+ FavoriteRetweetUnofficialContextMenu.Enabled = false;
}
else
{
- if (_curPost.IsProtect)
- {
- ReTweetStripMenuItem.Enabled = false;
- ReTweetUnofficialStripMenuItem.Enabled = false;
- QuoteStripMenuItem.Enabled = false;
- FavoriteRetweetContextMenu.Enabled = false;
- FavoriteRetweetUnofficialContextMenu.Enabled = false;
- }
- else
- {
- ReTweetStripMenuItem.Enabled = true;
- ReTweetUnofficialStripMenuItem.Enabled = true;
- QuoteStripMenuItem.Enabled = true;
- FavoriteRetweetContextMenu.Enabled = true;
- FavoriteRetweetUnofficialContextMenu.Enabled = true;
- }
+ ReTweetStripMenuItem.Enabled = true;
+ ReTweetUnofficialStripMenuItem.Enabled = true;
+ QuoteStripMenuItem.Enabled = true;
+ FavoriteRetweetContextMenu.Enabled = true;
+ FavoriteRetweetUnofficialContextMenu.Enabled = true;
}
}
//if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType != MyCommon.TabUsageType.Favorites)
}
else
{
- if (post.RetweetedId != null && post.UserId == this.tw.UserId)
- // 他人に RT された自分のツイート
- await this.twitterApi.StatusesDestroy(post.RetweetedId.Value)
- .IgnoreResponse();
- else
- // 自分のツイート or 自分が RT したツイート
+ if (post.RetweetedByUserId == this.tw.UserId)
+ {
+ // 自分が RT したツイート (自分が RT した自分のツイートも含む)
+ // => RT を取り消し
await this.twitterApi.StatusesDestroy(post.StatusId)
.IgnoreResponse();
+ }
+ else
+ {
+ if (post.UserId == this.tw.UserId)
+ {
+ if (post.RetweetedId != null)
+ // 他人に RT された自分のツイート
+ // => RT 元の自分のツイートを削除
+ await this.twitterApi.StatusesDestroy(post.RetweetedId.Value)
+ .IgnoreResponse();
+ else
+ // 自分のツイート
+ // => ツイートを削除
+ await this.twitterApi.StatusesDestroy(post.StatusId)
+ .IgnoreResponse();
+ }
+ }
}
}
catch (WebApiException ex)
TwitterApiConnection.RestApiHost = this._cfgCommon.TwitterApiHost;
Networking.DefaultTimeout = TimeSpan.FromSeconds(this._cfgCommon.DefaultTimeOut);
+ Networking.UploadImageTimeout = TimeSpan.FromSeconds(this._cfgCommon.UploadImageTimeout);
Networking.SetWebProxy(this._cfgLocal.ProxyType,
this._cfgLocal.ProxyAddress, this._cfgLocal.ProxyPort,
this._cfgLocal.ProxyUser, this._cfgLocal.ProxyPassword);
}
}
- private async void PostBrowser_Navigated(object sender, WebBrowserNavigatedEventArgs e)
- {
- if (e.Url.AbsoluteUri != "about:blank")
- {
- await this.DispSelectedPost();
- await this.OpenUriInBrowserAsync(e.Url.OriginalString);
- }
- }
-
- private async void PostBrowser_Navigating(object sender, WebBrowserNavigatingEventArgs e)
- {
- if (e.Url.Scheme == "data")
- {
- StatusLabelUrl.Text = PostBrowser.StatusText.Replace("&", "&&");
- }
- else if (e.Url.AbsoluteUri != "about:blank")
- {
- e.Cancel = true;
- // Ctrlを押しながらリンクを開いた場合は、設定と逆の動作をするフラグを true としておく
- await this.OpenUriAsync( e.Url, MyCommon.IsKeyDown( Keys.Control ) );
- }
- }
-
public void AddNewTabForSearch(string searchWord)
{
//同一検索条件のタブが既に存在すれば、そのタブアクティブにして終了
this.ListTab.Controls.Add(_tabPage);
_tabPage.Location = new Point(4, 4);
- _tabPage.Name = "CTab" + cnt.ToString();
+ _tabPage.Name = "CTab" + cnt;
_tabPage.Size = new Size(380, 260);
_tabPage.TabIndex = 2 + cnt;
_tabPage.Text = tab.TabName;
_listCustom.HideSelection = false;
_listCustom.Location = new Point(0, 0);
_listCustom.Margin = new Padding(0);
- _listCustom.Name = "CList" + Environment.TickCount.ToString();
+ _listCustom.Name = "CList" + Environment.TickCount;
_listCustom.ShowItemToolTips = true;
_listCustom.Size = new Size(380, 260);
_listCustom.UseCompatibleStateImageBehavior = false;
{
DetailsListView lst = (DetailsListView)tp.Tag;
var count = _statuses.Tabs[tp.Text].AllCount;
- if (lst.VirtualListSize != count)
- {
- lst.VirtualListSize = count;
- }
+ lst.VirtualListSize = count;
}
return true;
if (!this._cfgCommon.TabMouseLock && e.Button == MouseButtons.Left && _tabDrag)
{
string tn = "";
- Rectangle dragEnableRectangle = new Rectangle((int)(_tabMouseDownPoint.X - (SystemInformation.DragSize.Width / 2)), (int)(_tabMouseDownPoint.Y - (SystemInformation.DragSize.Height / 2)), SystemInformation.DragSize.Width, SystemInformation.DragSize.Height);
+ Rectangle dragEnableRectangle = new Rectangle(_tabMouseDownPoint.X - (SystemInformation.DragSize.Width / 2), _tabMouseDownPoint.Y - (SystemInformation.DragSize.Height / 2), SystemInformation.DragSize.Width, SystemInformation.DragSize.Height);
if (!dragEnableRectangle.Contains(e.Location))
{
//タブが多段の場合にはMouseDownの前の段階で選択されたタブの段が変わっているので、このタイミングでカーソルの位置からタブを判定出来ない。
_isColumnChanged = false;
}
- private void PostBrowser_StatusTextChanged(object sender, EventArgs e)
- {
- try
- {
- if (PostBrowser.StatusText.StartsWith("http", StringComparison.Ordinal)
- || PostBrowser.StatusText.StartsWith("ftp", StringComparison.Ordinal)
- || PostBrowser.StatusText.StartsWith("data", StringComparison.Ordinal))
- {
- StatusLabelUrl.Text = PostBrowser.StatusText.Replace("&", "&&");
- }
- if (string.IsNullOrEmpty(PostBrowser.StatusText))
- {
- SetStatusLabelUrl();
- }
- }
- catch (Exception)
- {
- }
- }
-
private void StatusText_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == '@')
if (e.KeyCode == Keys.Space || e.KeyCode == Keys.ProcessKey)
{
bool isSpace = false;
- foreach (char c in StatusText.Text.ToCharArray())
+ foreach (char c in StatusText.Text)
{
if (c == ' ' || c == ' ')
{
{
StatusText.ForeColor = _clInputFont;
}
+
+ this.StatusText.AccessibleDescription = string.Format(Properties.Resources.StatusText_AccessibleDescription, pLen);
+
if (string.IsNullOrEmpty(StatusText.Text))
{
this.inReplyTo = null;
//文字数カウント
var remainCount = this.tw.GetTextLengthRemain(statusText);
- if (this.ImageSelector.Visible && !string.IsNullOrEmpty(this.ImageSelector.ServiceName))
+ var uploadService = this.ImageSelector.SelectedService;
+ if (this.ImageSelector.Visible && uploadService != null)
{
- remainCount -= this.tw.Configuration.CharactersReservedPerMedia;
+ // TODO: ImageSelector で選択中の画像の枚数が mediaCount 引数に渡るようにする
+ remainCount -= uploadService.GetReservedTextLength(1);
}
return remainCount;
return;
var listCache = this._listItemCache;
- if (listCache != null && listCache.IsSupersetOf(e.StartIndex, e.EndIndex))
+ if (listCache?.TargetList == sender && listCache.IsSupersetOf(e.StartIndex, e.EndIndex))
{
// If the newly requested cache is a subset of the old cache,
// no need to rebuild everything, so do nothing.
private void MyList_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
var listCache = this._listItemCache;
- if (listCache != null && listCache.TargetList == sender)
+ if (listCache?.TargetList == sender)
{
ListViewItem item;
PostClass cacheItemPost;
//if (Post.IsMark) mk.Append("♪");
//if (Post.IsProtect) mk.Append("Ю");
//if (Post.InReplyToStatusId != null) mk.Append("⇒");
- if (Post.FavoritedCount > 0) mk.Append("+" + Post.FavoritedCount.ToString());
+ if (Post.FavoritedCount > 0) mk.Append("+" + Post.FavoritedCount);
ImageListViewItem itm;
if (Post.RetweetedId == null)
{
string[] sitem= {"",
Post.Nickname,
- Post.IsDeleted ? "(DELETED)" : Post.TextSingleLine,
+ Post.IsDeleted ? "(DELETED)" : Post.AccessibleText,
Post.CreatedAt.ToString(this._cfgCommon.DateTimeFormat),
Post.ScreenName,
"",
{
string[] sitem = {"",
Post.Nickname,
- Post.IsDeleted ? "(DELETED)" : Post.TextSingleLine,
+ Post.IsDeleted ? "(DELETED)" : Post.AccessibleText,
Post.CreatedAt.ToString(this._cfgCommon.DateTimeFormat),
Post.ScreenName + Environment.NewLine + "(RT:" + Post.RetweetedBy + ")",
"",
itm = new ImageListViewItem(sitem, this.IconCache, Post.ImageUrl);
}
itm.StateIndex = Post.StateIndex;
+ itm.Tag = Post;
bool read = Post.IsRead;
//未読管理していなかったら既読として扱う
if (e.ColumnIndex > 0)
{
//アイコン以外の列
+ var post = (PostClass)e.Item.Tag;
+
RectangleF rct = e.Bounds;
rct.Width = e.Header.Width;
int fontHeight = e.Item.Font.Height;
using (Font fnt = new Font(e.Item.Font, FontStyle.Bold))
{
TextRenderer.DrawText(e.Graphics,
- e.Item.SubItems[2].Text,
+ post.IsDeleted ? "(DELETED)" : post.TextSingleLine,
e.Item.Font,
Rectangle.Round(rct),
color,
TextFormatFlags.NoPrefix);
}
}
- else if (drawLineCount == 1)
- {
- TextRenderer.DrawText(e.Graphics,
- e.SubItem.Text,
- e.Item.Font,
- Rectangle.Round(rct),
- color,
- TextFormatFlags.SingleLine |
- TextFormatFlags.EndEllipsis |
- TextFormatFlags.GlyphOverhangPadding |
- TextFormatFlags.NoPrefix |
- TextFormatFlags.VerticalCenter);
- }
else
{
- TextRenderer.DrawText(e.Graphics,
- e.SubItem.Text,
- e.Item.Font,
- Rectangle.Round(rct),
- color,
- TextFormatFlags.WordBreak |
- TextFormatFlags.EndEllipsis |
- TextFormatFlags.GlyphOverhangPadding |
- TextFormatFlags.NoPrefix);
+ string text;
+ if (e.ColumnIndex != 2)
+ text = e.SubItem.Text;
+ else
+ text = post.IsDeleted ? "(DELETED)" : post.TextSingleLine;
+
+ if (drawLineCount == 1)
+ {
+ TextRenderer.DrawText(e.Graphics,
+ text,
+ e.Item.Font,
+ Rectangle.Round(rct),
+ color,
+ TextFormatFlags.SingleLine |
+ TextFormatFlags.EndEllipsis |
+ TextFormatFlags.GlyphOverhangPadding |
+ TextFormatFlags.NoPrefix |
+ TextFormatFlags.VerticalCenter);
+ }
+ else
+ {
+ TextRenderer.DrawText(e.Graphics,
+ text,
+ e.Item.Font,
+ Rectangle.Round(rct),
+ color,
+ TextFormatFlags.WordBreak |
+ TextFormatFlags.EndEllipsis |
+ TextFormatFlags.GlyphOverhangPadding |
+ TextFormatFlags.NoPrefix);
+ }
}
//if (e.ColumnIndex == 6) this.DrawListViewItemStateIcon(e, rct);
}
// }
//}
- private void DoTabSearch(string searchWord, bool caseSensitive, bool useRegex, SEARCHTYPE searchType)
+ internal void DoTabSearch(string searchWord, bool caseSensitive, bool useRegex, SEARCHTYPE searchType)
{
var tab = this._statuses.Tabs[this._curTab.Text];
/// <summary>発言検索に使用するメソッドを生成します</summary>
/// <exception cref="ArgumentException">
- /// <paramref name="useRegex"/> が true かつ、<paramref name="query"> が不正な正規表現な場合
+ /// <paramref name="useRegex"/> が true かつ、<paramref name="query"/> が不正な正規表現な場合
/// </exception>
private Func<string, bool> CreateSearchComparer(string query, bool useRegex, bool caseSensitive)
{
private void JumpUnreadMenuItem_Click(object sender, EventArgs e)
{
int bgnIdx = ListTab.TabPages.IndexOf(_curTab);
- int idx = -1;
- DetailsListView lst = null;
if (ImageSelector.Enabled)
return;
+ TabModel foundTab = null;
+ int foundIndex = 0;
+
+ DetailsListView lst = null;
+
//現在タブから最終タブまで探索
for (int i = bgnIdx; i < ListTab.TabPages.Count; i++)
{
- //未読Index取得
- idx = _statuses.Tabs[ListTab.TabPages[i].Text].NextUnreadIndex;
- if (idx > -1)
+ var tabPage = this.ListTab.TabPages[i];
+ var tab = this._statuses.Tabs[tabPage.Text];
+ var unreadIndex = tab.NextUnreadIndex;
+
+ if (unreadIndex != -1)
{
ListTab.SelectedIndex = i;
- lst = (DetailsListView)ListTab.TabPages[i].Tag;
- //_curTab = ListTab.TabPages[i];
+ foundTab = tab;
+ foundIndex = unreadIndex;
+ lst = (DetailsListView)tabPage.Tag;
break;
}
}
//未読みつからず&現在タブが先頭ではなかったら、先頭タブから現在タブの手前まで探索
- if (idx == -1 && bgnIdx > 0)
+ if (foundTab == null && bgnIdx > 0)
{
for (int i = 0; i < bgnIdx; i++)
{
- idx = _statuses.Tabs[ListTab.TabPages[i].Text].NextUnreadIndex;
- if (idx > -1)
+ var tabPage = this.ListTab.TabPages[i];
+ var tab = this._statuses.Tabs[tabPage.Text];
+ var unreadIndex = tab.NextUnreadIndex;
+
+ if (unreadIndex != -1)
{
ListTab.SelectedIndex = i;
- lst = (DetailsListView)ListTab.TabPages[i].Tag;
- //_curTab = ListTab.TabPages[i];
+ foundTab = tab;
+ foundIndex = unreadIndex;
+ lst = (DetailsListView)tabPage.Tag;
break;
}
}
}
- //全部調べたが未読見つからず→先頭タブの最新発言へ
- if (idx == -1)
+ if (foundTab == null)
{
+ //全部調べたが未読見つからず→先頭タブの最新発言へ
ListTab.SelectedIndex = 0;
- lst = (DetailsListView)ListTab.TabPages[0].Tag;
- //_curTab = ListTab.TabPages[0];
+ var tabPage = this.ListTab.TabPages[0];
+ var tab = this._statuses.Tabs[tabPage.Text];
+
+ if (tab.AllCount == 0)
+ return;
+
if (_statuses.SortOrder == SortOrder.Ascending)
- idx = lst.VirtualListSize - 1;
+ foundIndex = tab.AllCount - 1;
else
- idx = 0;
+ foundIndex = 0;
+
+ lst = (DetailsListView)tabPage.Tag;
}
- if (lst.VirtualListSize > 0 && idx > -1 && lst.VirtualListSize > idx)
+ SelectListItem(lst, foundIndex);
+
+ if (_statuses.SortMode == ComparerMode.Id)
{
- SelectListItem(lst, idx);
- if (_statuses.SortMode == ComparerMode.Id)
+ if (_statuses.SortOrder == SortOrder.Ascending && lst.Items[foundIndex].Position.Y > lst.ClientSize.Height - _iconSz - 10 ||
+ _statuses.SortOrder == SortOrder.Descending && lst.Items[foundIndex].Position.Y < _iconSz + 10)
{
- if (_statuses.SortOrder == SortOrder.Ascending && lst.Items[idx].Position.Y > lst.ClientSize.Height - _iconSz - 10 ||
- _statuses.SortOrder == SortOrder.Descending && lst.Items[idx].Position.Y < _iconSz + 10)
- {
- MoveTop();
- }
- else
- {
- lst.EnsureVisible(idx);
- }
+ MoveTop();
}
else
{
- lst.EnsureVisible(idx);
+ lst.EnsureVisible(foundIndex);
}
}
+ else
+ {
+ lst.EnsureVisible(foundIndex);
+ }
+
lst.Focus();
}
{
SetMainWindowTitle();
}
- if (!StatusLabelUrl.Text.StartsWith("http")) SetStatusLabelUrl();
+ if (!StatusLabelUrl.Text.StartsWith("http", StringComparison.OrdinalIgnoreCase))
+ SetStatusLabelUrl();
foreach (TabPage tb in ListTab.TabPages)
{
if (_statuses.Tabs[tb.Text].UnreadCount == 0)
return detailHtmlFormatHeader + orgdata + detailHtmlFormatFooter;
}
- private async void DisplayItemImage_Downloaded(object sender, EventArgs e)
- {
- if (sender.Equals(displayItem))
- {
- this.ClearUserPicture();
-
- var img = displayItem.Image;
- try
- {
- if (img != null)
- img = await img.CloneAsync();
-
- UserPicture.Image = img;
- }
- catch (Exception)
- {
- UserPicture.ShowErrorImage();
- }
- }
- }
-
private Task DispSelectedPost()
{
return this.DispSelectedPost(false);
if (!forceupdate && this._curPost.Equals(oldDisplayPost))
return;
- if (displayItem != null)
+ var loadTasks = new List<Task>
{
- displayItem.ImageDownloaded -= this.DisplayItemImage_Downloaded;
- displayItem = null;
- }
- displayItem = (ImageListViewItem)_curList.Items[_curList.SelectedIndices[0]];
- displayItem.ImageDownloaded += this.DisplayItemImage_Downloaded;
+ this.tweetDetailsView.ShowPostDetails(this._curPost),
+ };
- using (ControlTransaction.Update(this.TableLayoutPanel1))
- {
- SourceLinkLabel.Text = this._curPost.Source;
- SourceLinkLabel.Tag = this._curPost.SourceUri;
- SourceLinkLabel.TabStop = false; // Text を更新すると勝手に true にされる
+ this.SplitContainer3.Panel2Collapsed = true;
- string nameText;
- if (_curPost.IsDm)
- {
- if (_curPost.IsOwl)
- nameText = "DM FROM <- ";
- else
- nameText = "DM TO -> ";
- }
- else
- {
- nameText = "";
- }
- nameText += _curPost.ScreenName + "/" + _curPost.Nickname;
- if (_curPost.RetweetedId != null)
- nameText += " (RT:" + _curPost.RetweetedBy + ")";
+ if (this._cfgCommon.PreviewEnable)
+ {
+ var oldTokenSource = Interlocked.Exchange(ref this.thumbnailTokenSource, new CancellationTokenSource());
+ oldTokenSource?.Cancel();
- NameLabel.Text = nameText;
- NameLabel.Tag = _curPost.ScreenName;
+ var token = this.thumbnailTokenSource.Token;
+ loadTasks.Add(this.tweetThumbnail1.ShowThumbnailAsync(_curPost, token));
+ }
- var nameForeColor = SystemColors.ControlText;
- if (_curPost.IsOwl && (this._cfgCommon.OneWayLove || _curPost.IsDm))
- nameForeColor = this._clOWL;
- if (_curPost.RetweetedId != null)
- nameForeColor = this._clRetweet;
- if (_curPost.IsFav)
- nameForeColor = this._clFav;
- NameLabel.ForeColor = nameForeColor;
+ try
+ {
+ await Task.WhenAll(loadTasks);
+ }
+ catch (OperationCanceledException) { }
+ }
- this.ClearUserPicture();
+ private async void MatomeMenuItem_Click(object sender, EventArgs e)
+ {
+ await this.OpenApplicationWebsite();
+ }
- if (!string.IsNullOrEmpty(_curPost.ImageUrl))
- {
- var image = IconCache.TryGetFromCache(_curPost.ImageUrl);
- try
- {
- UserPicture.Image = image?.Clone();
- }
- catch (Exception)
- {
- UserPicture.ShowErrorImage();
- }
- }
+ private async Task OpenApplicationWebsite()
+ {
+ await this.OpenUriInBrowserAsync(ApplicationSettings.WebsiteUrl);
+ }
- DateTimeLabel.Text = _curPost.CreatedAt.ToString();
- }
+ private async void ShortcutKeyListMenuItem_Click(object sender, EventArgs e)
+ {
+ await this.OpenUriInBrowserAsync(ApplicationSettings.ShortcutKeyUrl);
+ }
- if (DumpPostClassToolStripMenuItem.Checked)
+ private async void ListTab_KeyDown(object sender, KeyEventArgs e)
+ {
+ if (ListTab.SelectedTab != null)
{
- StringBuilder sb = new StringBuilder(512);
-
- sb.Append("-----Start PostClass Dump<br>");
- sb.AppendFormat("TextFromApi : {0}<br>", _curPost.TextFromApi);
- sb.AppendFormat("(PlainText) : <xmp>{0}</xmp><br>", _curPost.TextFromApi);
- sb.AppendFormat("StatusId : {0}<br>", _curPost.StatusId.ToString());
- //sb.AppendFormat("ImageIndex : {0}<br>", _curPost.ImageIndex.ToString());
- sb.AppendFormat("ImageUrl : {0}<br>", _curPost.ImageUrl);
- sb.AppendFormat("InReplyToStatusId : {0}<br>", _curPost.InReplyToStatusId.ToString());
- sb.AppendFormat("InReplyToUser : {0}<br>", _curPost.InReplyToUser);
- sb.AppendFormat("IsDM : {0}<br>", _curPost.IsDm.ToString());
- sb.AppendFormat("IsFav : {0}<br>", _curPost.IsFav.ToString());
- sb.AppendFormat("IsMark : {0}<br>", _curPost.IsMark.ToString());
- sb.AppendFormat("IsMe : {0}<br>", _curPost.IsMe.ToString());
- sb.AppendFormat("IsOwl : {0}<br>", _curPost.IsOwl.ToString());
- sb.AppendFormat("IsProtect : {0}<br>", _curPost.IsProtect.ToString());
- sb.AppendFormat("IsRead : {0}<br>", _curPost.IsRead.ToString());
- sb.AppendFormat("IsReply : {0}<br>", _curPost.IsReply.ToString());
-
- foreach (string nm in _curPost.ReplyToList)
+ if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType == MyCommon.TabUsageType.PublicSearch)
{
- sb.AppendFormat("ReplyToList : {0}<br>", nm);
+ Control pnl = ListTab.SelectedTab.Controls["panelSearch"];
+ if (pnl.Controls["comboSearch"].Focused ||
+ pnl.Controls["comboLang"].Focused ||
+ pnl.Controls["buttonSearch"].Focused) return;
}
- sb.AppendFormat("ScreenName : {0}<br>", _curPost.ScreenName);
- sb.AppendFormat("NickName : {0}<br>", _curPost.Nickname);
- sb.AppendFormat("Text : {0}<br>", _curPost.Text);
- sb.AppendFormat("(PlainText) : <xmp>{0}</xmp><br>", _curPost.Text);
- sb.AppendFormat("CreatedAt : {0}<br>", _curPost.CreatedAt.ToString());
- sb.AppendFormat("Source : {0}<br>", _curPost.Source);
- sb.AppendFormat("UserId : {0}<br>", _curPost.UserId);
- sb.AppendFormat("FilterHit : {0}<br>", _curPost.FilterHit);
- sb.AppendFormat("RetweetedBy : {0}<br>", _curPost.RetweetedBy);
- sb.AppendFormat("RetweetedId : {0}<br>", _curPost.RetweetedId);
+ if (e.Control || e.Shift || e.Alt)
+ this._anchorFlag = false;
- sb.AppendFormat("Media.Count : {0}<br>", _curPost.Media.Count);
- if (_curPost.Media.Count > 0)
+ Task asyncTask;
+ if (CommonKeyDown(e.KeyData, FocusedControl.ListTab, out asyncTask))
{
- for (int i = 0; i < _curPost.Media.Count; i++)
- {
- var info = _curPost.Media[i];
- sb.AppendFormat("Media[{0}].Url : {1}<br>", i, info.Url);
- sb.AppendFormat("Media[{0}].VideoUrl : {1}<br>", i, info.VideoUrl ?? "---");
- }
+ e.Handled = true;
+ e.SuppressKeyPress = true;
}
- sb.Append("-----End PostClass Dump<br>");
- PostBrowser.DocumentText = detailHtmlFormatHeader + sb.ToString() + detailHtmlFormatFooter;
- return;
+ if (asyncTask != null)
+ await asyncTask;
}
+ }
- var loadTasks = new List<Task>();
-
- // 同じIDのツイートであれば WebBrowser とサムネイルの更新を行わない
- // (同一ツイートの RT は文面が同じであるため同様に更新しない)
- if (_curPost.StatusId != oldDisplayPost.StatusId)
- {
- using (ControlTransaction.Update(this.PostBrowser))
- {
- this.PostBrowser.DocumentText =
- this.createDetailHtml(_curPost.IsDeleted ? "(DELETED)" : _curPost.Text);
-
- this.PostBrowser.Document.Window.ScrollTo(0, 0);
- }
-
- this.SplitContainer3.Panel2Collapsed = true;
-
- if (this._cfgCommon.PreviewEnable)
- {
- var oldTokenSource = Interlocked.Exchange(ref this.thumbnailTokenSource, new CancellationTokenSource());
- oldTokenSource?.Cancel();
-
- var token = this.thumbnailTokenSource.Token;
- loadTasks.Add(this.tweetThumbnail1.ShowThumbnailAsync(_curPost, token));
- }
-
- loadTasks.Add(this.AppendQuoteTweetAsync(this._curPost));
- }
-
- try
- {
- await Task.WhenAll(loadTasks);
- }
- catch (OperationCanceledException) { }
- }
-
- /// <summary>
- /// 発言詳細欄のツイートURLを展開する
- /// </summary>
- private async Task AppendQuoteTweetAsync(PostClass post)
- {
- var quoteStatusIds = post.QuoteStatusIds;
- if (quoteStatusIds.Length == 0 && post.InReplyToStatusId == null)
- return;
-
- // 「読み込み中」テキストを表示
- var loadingQuoteHtml = quoteStatusIds.Select(x => FormatQuoteTweetHtml(x, Properties.Resources.LoadingText, isReply: false));
-
- var loadingReplyHtml = string.Empty;
- if (post.InReplyToStatusId != null)
- loadingReplyHtml = FormatQuoteTweetHtml(post.InReplyToStatusId.Value, Properties.Resources.LoadingText, isReply: true);
-
- var body = post.Text + string.Concat(loadingQuoteHtml) + loadingReplyHtml;
-
- using (ControlTransaction.Update(this.PostBrowser))
- this.PostBrowser.DocumentText = this.createDetailHtml(body);
-
- // 引用ツイートを読み込み
- var loadTweetTasks = quoteStatusIds.Select(x => this.CreateQuoteTweetHtml(x, isReply: false)).ToList();
-
- if (post.InReplyToStatusId != null)
- loadTweetTasks.Add(this.CreateQuoteTweetHtml(post.InReplyToStatusId.Value, isReply: true));
-
- var quoteHtmls = await Task.WhenAll(loadTweetTasks);
-
- // 非同期処理中に表示中のツイートが変わっていたらキャンセルされたものと扱う
- if (this._curPost != post || this._curPost.IsDeleted)
- return;
-
- body = post.Text + string.Concat(quoteHtmls);
-
- using (ControlTransaction.Update(this.PostBrowser))
- this.PostBrowser.DocumentText = this.createDetailHtml(body);
- }
-
- private async Task<string> CreateQuoteTweetHtml(long statusId, bool isReply)
- {
- PostClass post = this._statuses[statusId];
- if (post == null)
- {
- try
- {
- post = await this.tw.GetStatusApi(false, statusId)
- .ConfigureAwait(false);
- }
- catch (WebApiException ex)
- {
- return FormatQuoteTweetHtml(statusId, WebUtility.HtmlEncode($"Err:{ex.Message}(GetStatus)"), isReply);
- }
-
- post.IsRead = true;
- if (!this._statuses.AddQuoteTweet(post))
- return FormatQuoteTweetHtml(statusId, "This Tweet is unavailable.", isReply);
- }
-
- return FormatQuoteTweetHtml(post, isReply);
- }
-
- internal static string FormatQuoteTweetHtml(PostClass post, bool isReply)
- {
- var innerHtml = "<p>" + StripLinkTagHtml(post.Text) + "</p>" +
- " — " + WebUtility.HtmlEncode(post.Nickname) +
- " (@" + WebUtility.HtmlEncode(post.ScreenName) + ") " +
- WebUtility.HtmlEncode(post.CreatedAt.ToString());
-
- return FormatQuoteTweetHtml(post.StatusId, innerHtml, isReply);
- }
-
- internal static string FormatQuoteTweetHtml(long statusId, string innerHtml, bool isReply)
- {
- var blockClassName = "quote-tweet";
-
- if (isReply)
- blockClassName += " reply";
-
- return "<a class=\"quote-tweet-link\" href=\"//opentween/status/" + statusId + "\">" +
- $"<blockquote class=\"{blockClassName}\">{innerHtml}</blockquote>" +
- "</a>";
- }
-
- /// <summary>
- /// 指定されたHTMLからリンクを除去します
- /// </summary>
- internal static string StripLinkTagHtml(string html)
- {
- // a 要素はネストされていない前提の正規表現パターン
- return Regex.Replace(html, @"<a[^>]*>(.*?)</a>", "$1");
- }
-
- private async void MatomeMenuItem_Click(object sender, EventArgs e)
- {
- await this.OpenApplicationWebsite();
- }
-
- private async Task OpenApplicationWebsite()
- {
- await this.OpenUriInBrowserAsync(ApplicationSettings.WebsiteUrl);
- }
-
- private async void ShortcutKeyListMenuItem_Click(object sender, EventArgs e)
- {
- await this.OpenUriInBrowserAsync(ApplicationSettings.ShortcutKeyUrl);
- }
-
- private async void ListTab_KeyDown(object sender, KeyEventArgs e)
- {
- if (ListTab.SelectedTab != null)
- {
- if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType == MyCommon.TabUsageType.PublicSearch)
- {
- Control pnl = ListTab.SelectedTab.Controls["panelSearch"];
- if (pnl.Controls["comboSearch"].Focused ||
- pnl.Controls["comboLang"].Focused ||
- pnl.Controls["buttonSearch"].Focused) return;
- }
-
- if (e.Control || e.Shift || e.Alt)
- this._anchorFlag = false;
-
- Task asyncTask;
- if (CommonKeyDown(e.KeyData, FocusedControl.ListTab, out asyncTask))
- {
- e.Handled = true;
- e.SuppressKeyPress = true;
- }
-
- if (asyncTask != null)
- await asyncTask;
- }
- }
-
- private ShortcutCommand[] shortcutCommands = new ShortcutCommand[0];
+ private ShortcutCommand[] shortcutCommands = new ShortcutCommand[0];
private void InitializeShortcuts()
{
.Do(() => this.doShowUserStatus(_curPost.ScreenName, ShowInputDialog: false)),
ShortcutCommand.Create(Keys.Alt | Keys.Up)
- .Do(() => this.ScrollDownPostBrowser(forward: false)),
+ .Do(() => this.tweetDetailsView.ScrollDownPostBrowser(forward: false)),
ShortcutCommand.Create(Keys.Alt | Keys.Down)
- .Do(() => this.ScrollDownPostBrowser(forward: true)),
+ .Do(() => this.tweetDetailsView.ScrollDownPostBrowser(forward: true)),
ShortcutCommand.Create(Keys.Alt | Keys.PageUp)
- .Do(() => this.PageDownPostBrowser(forward: false)),
+ .Do(() => this.tweetDetailsView.PageDownPostBrowser(forward: false)),
ShortcutCommand.Create(Keys.Alt | Keys.PageDown)
- .Do(() => this.PageDownPostBrowser(forward: true)),
+ .Do(() => this.tweetDetailsView.PageDownPostBrowser(forward: true)),
// 別タブの同じ書き込みへ(ALT+←/→)
ShortcutCommand.Create(Keys.Alt | Keys.Right)
ShortcutCommand.Create(Keys.Alt | Keys.Shift | Keys.T)
.OnlyWhen(() => this.ExistCurrentPost)
- .Do(() => this.doTranslation(_curPost.TextFromApi)),
+ .Do(() => this.tweetDetailsView.DoTranslation()),
ShortcutCommand.Create(Keys.Alt | Keys.Shift | Keys.R)
.Do(() => this.doReTweetUnofficial()),
};
}
- private bool CommonKeyDown(Keys keyData, FocusedControl focusedOn, out Task asyncTask)
+ internal bool CommonKeyDown(Keys keyData, FocusedControl focusedOn, out Task asyncTask)
{
// Task を返す非同期処理があれば asyncTask に代入する
asyncTask = null;
return false;
}
- private void ScrollDownPostBrowser(bool forward)
- {
- var doc = PostBrowser.Document;
- if (doc == null) return;
-
- var tags = doc.GetElementsByTagName("html");
- if (tags.Count > 0)
- {
- if (forward)
- tags[0].ScrollTop += this._fntDetail.Height;
- else
- tags[0].ScrollTop -= this._fntDetail.Height;
- }
- }
-
- private void PageDownPostBrowser(bool forward)
- {
- var doc = PostBrowser.Document;
- if (doc == null) return;
-
- var tags = doc.GetElementsByTagName("html");
- if (tags.Count > 0)
- {
- if (forward)
- tags[0].ScrollTop += PostBrowser.ClientRectangle.Height - this._fntDetail.Height;
- else
- tags[0].ScrollTop -= PostBrowser.ClientRectangle.Height - this._fntDetail.Height;
- }
- }
-
private void GoNextTab(bool forward)
{
int idx = ListTab.SelectedIndex;
foreach (int idx in _curList.SelectedIndices)
{
PostClass post = _statuses.Tabs[_curTab.Text][idx];
- if (post.IsProtect)
- {
- IsProtected = true;
- continue;
- }
if (post.IsDeleted) continue;
if (!isDm)
{
private void CopyIdUri()
{
- string clstr = "";
- StringBuilder sb = new StringBuilder();
- if (this._curTab == null) return;
- if (this._statuses.GetTabByName(this._curTab.Text) == null) return;
- if (this._statuses.GetTabByName(this._curTab.Text).TabType == MyCommon.TabUsageType.DirectMessage) return;
+ if (this._curTab == null)
+ return;
+
+ var tab = this._statuses.GetTabByName(this._curTab.Text);
+ if (tab == null || tab is DirectMessagesTabModel)
+ return;
+
+ var copyUrls = new List<string>();
foreach (int idx in _curList.SelectedIndices)
{
- var post = _statuses.Tabs[_curTab.Text][idx];
- sb.Append(MyCommon.GetStatusUrl(post));
- sb.Append(Environment.NewLine);
+ var post = tab[idx];
+ copyUrls.Add(MyCommon.GetStatusUrl(post));
}
- if (sb.Length > 0)
+
+ if (copyUrls.Count == 0)
+ return;
+
+ try
{
- clstr = sb.ToString();
- try
- {
- Clipboard.SetDataObject(clstr, false, 5, 100);
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message);
- }
+ Clipboard.SetDataObject(string.Join(Environment.NewLine, copyUrls), false, 5, 100);
+ }
+ catch (ExternalException ex)
+ {
+ MessageBox.Show(ex.Message);
}
}
private void GoSamePostToAnotherTab(bool left)
{
- if (_curList.VirtualListSize == 0) return;
- int fIdx = 0;
- int toIdx = 0;
- int stp = 1;
- long targetId = 0;
+ if (this._curList.SelectedIndices.Count == 0)
+ return;
+
+ var tab = this._statuses.Tabs[this._curTab.Text];
+
+ // Directタブは対象外(見つかるはずがない)
+ if (tab.TabType == MyCommon.TabUsageType.DirectMessage)
+ return;
- if (_statuses.Tabs[_curTab.Text].TabType == MyCommon.TabUsageType.DirectMessage) return; // Directタブは対象外(見つかるはずがない)
- if (_curList.SelectedIndices.Count == 0) return; //未選択も処理しない
+ var selectedIndex = this._curList.SelectedIndices[0];
+ var selectedStatusId = tab.GetStatusIdAt(selectedIndex);
- targetId = GetCurTabPost(_curList.SelectedIndices[0]).StatusId;
+ int fIdx, toIdx, stp;
if (left)
{
stp = 1;
}
- bool found = false;
for (int tabidx = fIdx; tabidx != toIdx; tabidx += stp)
{
- if (_statuses.Tabs[ListTab.TabPages[tabidx].Text].TabType == MyCommon.TabUsageType.DirectMessage) continue; // Directタブは対象外
- for (int idx = 0; idx < ((DetailsListView)ListTab.TabPages[tabidx].Tag).VirtualListSize; idx++)
+ var targetTab = this._statuses.Tabs[this.ListTab.TabPages[tabidx].Text];
+
+ // Directタブは対象外
+ if (targetTab.TabType == MyCommon.TabUsageType.DirectMessage)
+ continue;
+
+ var foundIndex = targetTab.IndexOf(selectedStatusId);
+ if (foundIndex != -1)
{
- if (_statuses.Tabs[ListTab.TabPages[tabidx].Text][idx].StatusId == targetId)
- {
- ListTab.SelectedIndex = tabidx;
- SelectListItem(_curList, idx);
- _curList.EnsureVisible(idx);
- found = true;
- break;
- }
+ ListTab.SelectedIndex = tabidx;
+ SelectListItem(_curList, foundIndex);
+ _curList.EnsureVisible(foundIndex);
+ return;
}
- if (found) break;
}
}
private void GoPost(bool forward)
{
- if (_curList.SelectedIndices.Count == 0 || _curPost == null) return;
- int fIdx = 0;
- int toIdx = 0;
- int stp = 1;
+ if (_curList.SelectedIndices.Count == 0 || _curPost == null)
+ return;
+
+ var tab = this._statuses.Tabs[this._curTab.Text];
+ var selectedIndex = this._curList.SelectedIndices[0];
+
+ int fIdx, toIdx, stp;
if (forward)
{
- fIdx = _curList.SelectedIndices[0] + 1;
- if (fIdx > _curList.VirtualListSize - 1) return;
- toIdx = _curList.VirtualListSize;
+ fIdx = selectedIndex + 1;
+ if (fIdx > tab.AllCount - 1) return;
+ toIdx = tab.AllCount;
stp = 1;
}
else
{
- fIdx = _curList.SelectedIndices[0] - 1;
+ fIdx = selectedIndex - 1;
if (fIdx < 0) return;
toIdx = -1;
stp = -1;
}
for (int idx = fIdx; idx != toIdx; idx += stp)
{
- if (_statuses.Tabs[_curTab.Text][idx].RetweetedId == null)
+ var post = tab[idx];
+ if (post.RetweetedId == null)
{
- if (_statuses.Tabs[_curTab.Text][idx].ScreenName == name)
+ if (post.ScreenName == name)
{
SelectListItem(_curList, idx);
_curList.EnsureVisible(idx);
}
else
{
- if (_statuses.Tabs[_curTab.Text][idx].RetweetedBy == name)
+ if (post.RetweetedBy == name)
{
SelectListItem(_curList, idx);
_curList.EnsureVisible(idx);
private void GoRelPost(bool forward)
{
- if (_curList.SelectedIndices.Count == 0) return;
+ if (this._curList.SelectedIndices.Count == 0)
+ return;
+
+ var tab = this._statuses.Tabs[this._curTab.Text];
+ var selectedIndex = this._curList.SelectedIndices[0];
+
+ int fIdx, toIdx, stp;
- int fIdx = 0;
- int toIdx = 0;
- int stp = 1;
if (forward)
{
- fIdx = _curList.SelectedIndices[0] + 1;
- if (fIdx > _curList.VirtualListSize - 1) return;
- toIdx = _curList.VirtualListSize;
+ fIdx = selectedIndex + 1;
+ if (fIdx > tab.AllCount - 1) return;
+ toIdx = tab.AllCount;
stp = 1;
}
else
{
- fIdx = _curList.SelectedIndices[0] - 1;
+ fIdx = selectedIndex - 1;
if (fIdx < 0) return;
toIdx = -1;
stp = -1;
for (int idx = fIdx; idx != toIdx; idx += stp)
{
- PostClass post = _statuses.Tabs[_curTab.Text][idx];
+ var post = tab[idx];
if (post.ScreenName == _anchorPost.ScreenName ||
post.RetweetedBy == _anchorPost.ScreenName ||
post.ScreenName == _anchorPost.RetweetedBy ||
catch (WebApiException ex)
{
this.StatusLabel.Text = $"Err:{ex.Message}(GetStatus)";
- await this.OpenUriInBrowserAsync("https://twitter.com/" + inReplyToUser + "/statuses/" + inReplyToId.ToString());
+ await this.OpenUriInBrowserAsync(MyCommon.GetStatusUrl(inReplyToUser, inReplyToId));
return;
}
inReplyPost = inReplyToPosts.FirstOrDefault();
if (inReplyPost == null)
{
- await this.OpenUriInBrowserAsync("https://twitter.com/" + inReplyToUser + "/statuses/" + inReplyToId.ToString());
+ await this.OpenUriInBrowserAsync(MyCommon.GetStatusUrl(inReplyToUser, inReplyToId));
return;
}
}
if (_ignoreConfigSave || !this._cfgCommon.UseAtIdSupplement && AtIdSupl == null) return;
ModifySettingAtId = false;
- SettingAtIdList cfgAtId = new SettingAtIdList(AtIdSupl.GetItemList());
- cfgAtId.Save();
+ SettingManager.AtIdList.AtIdList = this.AtIdSupl.GetItemList();
+ SettingManager.SaveAtIdList();
}
private void SaveConfigsCommon()
_cfgCommon.UseImageService = ImageSelector.ServiceIndex;
_cfgCommon.UseImageServiceName = ImageSelector.ServiceName;
- _cfgCommon.Save();
+ SettingManager.SaveCommon();
}
}
_cfgLocal.FontInputFont = _fntInputFont;
if (_ignoreConfigSave) return;
- _cfgLocal.Save();
+ SettingManager.SaveLocal();
}
}
private void SaveConfigsTabs()
{
- var tabsSetting = new SettingTabs();
+ var tabSettingList = new List<SettingTabs.SettingTabItem>();
var tabs = this.ListTab.TabPages.Cast<TabPage>()
.Select(x => this._statuses.Tabs[x.Text])
if (listTab != null)
tabSetting.ListInfo = listTab.ListInfo;
- tabsSetting.Tabs.Add(tabSetting);
+ tabSettingList.Add(tabSetting);
}
- tabsSetting.Save();
+ SettingManager.Tabs.Tabs = tabSettingList;
+ SettingManager.SaveTabs();
}
private async void OpenURLFileMenuItem_Click(object sender, EventArgs e)
if (post.IsProtect) protect = "Protect";
sw.WriteLine(post.Nickname + "\t" +
"\"" + post.TextFromApi.Replace("\n", "").Replace("\"", "\"\"") + "\"" + "\t" +
- post.CreatedAt.ToString() + "\t" +
+ post.CreatedAt + "\t" +
post.ScreenName + "\t" +
- post.StatusId.ToString() + "\t" +
+ post.StatusId + "\t" +
post.ImageUrl + "\t" +
"\"" + post.Text.Replace("\n", "").Replace("\"", "\"\"") + "\"" + "\t" +
protect);
if (post.IsProtect) protect = "Protect";
sw.WriteLine(post.Nickname + "\t" +
"\"" + post.TextFromApi.Replace("\n", "").Replace("\"", "\"\"") + "\"" + "\t" +
- post.CreatedAt.ToString() + "\t" +
+ post.CreatedAt + "\t" +
post.ScreenName + "\t" +
- post.StatusId.ToString() + "\t" +
+ post.StatusId + "\t" +
post.ImageUrl + "\t" +
"\"" + post.Text.Replace("\n", "").Replace("\"", "\"\"") + "\"" + "\t" +
protect);
this.TopMost = this._cfgCommon.AlwaysTop;
}
- private async void PostBrowser_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
- {
- Task asyncTask;
- bool KeyRes = CommonKeyDown(e.KeyData, FocusedControl.PostBrowser, out asyncTask);
- if (KeyRes)
- {
- e.IsInputKey = true;
- }
- else
- {
- if (Enum.IsDefined(typeof(Shortcut), (Shortcut)e.KeyData))
- {
- var shortcut = (Shortcut)e.KeyData;
- switch (shortcut)
- {
- case Shortcut.CtrlA:
- case Shortcut.CtrlC:
- case Shortcut.CtrlIns:
- // 既定の動作を有効にする
- break;
- default:
- // その他のショートカットキーは無効にする
- e.IsInputKey = true;
- break;
- }
- }
- }
-
- if (asyncTask != null)
- await asyncTask;
- }
- public bool TabRename(ref string tabName)
+ public bool TabRename(string origTabName, out string newTabName)
{
//タブ名変更
- string newTabText = null;
+ newTabName = null;
using (InputTabName inputName = new InputTabName())
{
- inputName.TabName = tabName;
+ inputName.TabName = origTabName;
inputName.ShowDialog();
if (inputName.DialogResult == DialogResult.Cancel) return false;
- newTabText = inputName.TabName;
+ newTabName = inputName.TabName;
}
this.TopMost = this._cfgCommon.AlwaysTop;
- if (!string.IsNullOrEmpty(newTabText))
+ if (!string.IsNullOrEmpty(newTabName))
{
//新タブ名存在チェック
for (int i = 0; i < ListTab.TabCount; i++)
{
- if (ListTab.TabPages[i].Text == newTabText)
+ if (ListTab.TabPages[i].Text == newTabName)
{
- string tmp = string.Format(Properties.Resources.Tabs_DoubleClickText1, newTabText);
+ string tmp = string.Format(Properties.Resources.Tabs_DoubleClickText1, newTabName);
MessageBox.Show(tmp, Properties.Resources.Tabs_DoubleClickText2, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return false;
}
}
- //タブ名を変更
- for (int i = 0; i < ListTab.TabCount; i++)
- {
- if (ListTab.TabPages[i].Text == tabName)
- {
- ListTab.TabPages[i].Text = newTabText;
- break;
- }
- }
- _statuses.RenameTab(tabName, newTabText);
+
+ var tabPage = this.ListTab.TabPages.Cast<TabPage>()
+ .FirstOrDefault(x => x.Text == origTabName);
+
+ // タブ名を変更
+ if (tabPage != null)
+ tabPage.Text = newTabName;
+
+ _statuses.RenameTab(origTabName, newTabName);
SaveConfigsCommon();
SaveConfigsTabs();
- _rclickTabName = newTabText;
- tabName = newTabText;
+ _rclickTabName = newTabName;
return true;
}
else
private void ListTab_DoubleClick(object sender, MouseEventArgs e)
{
- string tn = ListTab.SelectedTab.Text;
- TabRename(ref tn);
+ string _;
+ TabRename(this.ListTab.SelectedTab.Text, out _);
}
private void ListTab_MouseDown(object sender, MouseEventArgs e)
{
if (this._cfgCommon.TabMouseLock) return;
- Point cpos = new Point(e.X, e.Y);
if (e.Button == MouseButtons.Left)
{
for (int i = 0; i < ListTab.TabPages.Count; i++)
if (_statuses == null) return;
if (_statuses.Tabs == null) return;
- TabModel tb = _statuses.Tabs[_rclickTabName];
- if (tb == null) return;
+ TabModel tb;
+ if (!this._statuses.Tabs.TryGetValue(this._rclickTabName, out tb))
+ return;
NotifyDispMenuItem.Checked = tb.Notify;
this.NotifyTbMenuItem.Checked = tb.Notify;
private void IDRuleMenuItem_Click(object sender, EventArgs e)
{
- string tabName;
-
//未選択なら処理終了
if (_curList.SelectedIndices.Count == 0) return;
+ var tab = this._statuses.Tabs[this._curTab.Text];
+ var screenNameArray = this._curList.SelectedIndices.Cast<int>()
+ .Select(x => tab[x])
+ .Select(x => x.RetweetedId != null ? x.RetweetedBy : x.ScreenName)
+ .ToArray();
+
+ this.AddFilterRuleByScreenName(screenNameArray);
+
+ if (screenNameArray.Length != 0)
+ {
+ List<string> atids = new List<string>();
+ foreach (var screenName in screenNameArray)
+ {
+ atids.Add("@" + screenName);
+ }
+ int cnt = AtIdSupl.ItemCount;
+ AtIdSupl.AddRangeItem(atids.ToArray());
+ if (AtIdSupl.ItemCount != cnt) ModifySettingAtId = true;
+ }
+ }
+
+ private void SourceRuleMenuItem_Click(object sender, EventArgs e)
+ {
+ if (this._curList.SelectedIndices.Count == 0)
+ return;
+
+ var tab = this._statuses.Tabs[this._curTab.Text];
+ var sourceArray = this._curList.SelectedIndices.Cast<int>()
+ .Select(x => tab[x].Source).ToArray();
+
+ this.AddFilterRuleBySource(sourceArray);
+ }
+
+ public void AddFilterRuleByScreenName(params string[] screenNameArray)
+ {
//タブ選択(or追加)
+ string tabName;
if (!SelectTab(out tabName)) return;
var tab = (FilterTabModel)this._statuses.Tabs[tabName];
mk = false;
}
- List<string> ids = new List<string>();
- foreach (int idx in _curList.SelectedIndices)
+ foreach (var screenName in screenNameArray)
{
- PostClass post = _statuses.Tabs[_curTab.Text][idx];
- if (!ids.Contains(post.ScreenName))
+ tab.AddFilter(new PostFilterRule
{
- PostFilterRule fc = new PostFilterRule();
- ids.Add(post.ScreenName);
- if (post.RetweetedId == null)
- {
- fc.FilterName = post.ScreenName;
- }
- else
- {
- fc.FilterName = post.RetweetedBy;
- }
- fc.UseNameField = true;
- fc.MoveMatches = mv;
- fc.MarkMatches = mk;
- fc.UseRegex = false;
- fc.FilterByUrl = false;
- tab.AddFilter(fc);
- }
- }
- if (ids.Count != 0)
- {
- List<string> atids = new List<string>();
- foreach (string id in ids)
- {
- atids.Add("@" + id);
- }
- int cnt = AtIdSupl.ItemCount;
- AtIdSupl.AddRangeItem(atids.ToArray());
- if (AtIdSupl.ItemCount != cnt) ModifySettingAtId = true;
+ FilterName = screenName,
+ UseNameField = true,
+ MoveMatches = mv,
+ MarkMatches = mk,
+ UseRegex = false,
+ FilterByUrl = false,
+ });
}
this.ApplyPostFilters();
SaveConfigsTabs();
}
- private void SourceRuleMenuItem_Click(object sender, EventArgs e)
+ public void AddFilterRuleBySource(params string[] sourceArray)
{
- if (this._curList.SelectedIndices.Count == 0)
- return;
-
// タブ選択ダイアログを表示(or追加)
string tabName;
if (!this.SelectTab(out tabName))
return;
- var currentTab = this._statuses.Tabs[this._curTab.Text];
var filterTab = (FilterTabModel)this._statuses.Tabs[tabName];
bool mv;
}
// 振り分けルールに追加するSource
- var sources = new HashSet<string>();
-
- foreach (var idx in this._curList.SelectedIndices.Cast<int>())
+ foreach (var source in sourceArray)
{
- var post = currentTab[idx];
- var filterSource = post.Source;
-
- if (sources.Add(filterSource))
+ filterTab.AddFilter(new PostFilterRule
{
- var filter = new PostFilterRule
- {
- FilterSource = filterSource,
- MoveMatches = mv,
- MarkMatches = mk,
- UseRegex = false,
- FilterByUrl = false,
- };
- filterTab.AddFilter(filter);
- }
+ FilterSource = source,
+ MoveMatches = mv,
+ MarkMatches = mk,
+ UseRegex = false,
+ FilterByUrl = false,
+ });
}
this.ApplyPostFilters();
private async void OpenURLMenuItem_Click(object sender, EventArgs e)
{
- var linkElements = this.PostBrowser.Document.Links.Cast<HtmlElement>()
- .Where(x => x.GetAttribute("className") != "tweet-quote-link") // 引用ツイートで追加されたリンクを除く
- .ToArray();
+ var linkElements = this.tweetDetailsView.GetLinkElements();
if (linkElements.Length > 0)
{
{
if (tb.Text == tabName)
{
- tb.ImageIndex = -1;
((DetailsListView)tb.Tag).VirtualListSize = 0;
+ tb.ImageIndex = -1;
break;
}
}
StatusLabel.Text = text;
}
- private static StringBuilder ur = new StringBuilder(64);
-
private void SetNotifyIconText()
{
+ var ur = new StringBuilder(64);
+
// タスクトレイアイコンのツールチップテキスト書き換え
// Tween [未読/@]
ur.Remove(0, ur.Length);
if (_statuses.ContainsKey(_curPost.InReplyToStatusId.Value))
{
PostClass repPost = _statuses[_curPost.InReplyToStatusId.Value];
- MessageBox.Show(repPost.ScreenName + " / " + repPost.Nickname + " (" + repPost.CreatedAt.ToString() + ")" + Environment.NewLine + repPost.TextFromApi);
+ MessageBox.Show($"{repPost.ScreenName} / {repPost.Nickname} ({repPost.CreatedAt})" + Environment.NewLine + repPost.TextFromApi);
}
else
{
{
if (tb == null || !tb.Contains(_curPost.InReplyToStatusId.Value)) break;
PostClass repPost = _statuses[_curPost.InReplyToStatusId.Value];
- MessageBox.Show(repPost.ScreenName + " / " + repPost.Nickname + " (" + repPost.CreatedAt.ToString() + ")" + Environment.NewLine + repPost.TextFromApi);
+ MessageBox.Show($"{repPost.ScreenName} / {repPost.Nickname} ({repPost.CreatedAt})" + Environment.NewLine + repPost.TextFromApi);
return;
}
await this.OpenUriInBrowserAsync(MyCommon.GetStatusUrl(_curPost.InReplyToUser, _curPost.InReplyToStatusId.Value));
await this.doRepliedStatusOpen();
}
- /// <summary>
- /// UserPicture.Image に設定されている画像を破棄します。
- /// </summary>
- private void ClearUserPicture()
- {
- if (this.UserPicture.Image != null)
- {
- var oldImage = this.UserPicture.Image;
- this.UserPicture.Image = null;
- oldImage.Dispose();
- }
- }
-
- private void ContextMenuUserPicture_Opening(object sender, CancelEventArgs e)
- {
- //発言詳細のアイコン右クリック時のメニュー制御
- if (_curList.SelectedIndices.Count > 0 && _curPost != null)
- {
- string name = _curPost.ImageUrl;
- if (name != null && name.Length > 0)
- {
- int idx = name.LastIndexOf('/');
- if (idx != -1)
- {
- name = Path.GetFileName(name.Substring(idx));
- if (name.Contains("_normal.") || name.EndsWith("_normal", StringComparison.Ordinal))
- {
- name = name.Replace("_normal", "");
- this.IconNameToolStripMenuItem.Text = name;
- this.IconNameToolStripMenuItem.Enabled = true;
- }
- else
- {
- this.IconNameToolStripMenuItem.Enabled = false;
- this.IconNameToolStripMenuItem.Text = Properties.Resources.ContextMenuStrip3_OpeningText1;
- }
- }
- else
- {
- this.IconNameToolStripMenuItem.Enabled = false;
- this.IconNameToolStripMenuItem.Text = Properties.Resources.ContextMenuStrip3_OpeningText1;
- }
-
- this.ReloadIconToolStripMenuItem.Enabled = true;
-
- if (this.IconCache.TryGetFromCache(_curPost.ImageUrl) != null)
- {
- this.SaveIconPictureToolStripMenuItem.Enabled = true;
- }
- else
- {
- this.SaveIconPictureToolStripMenuItem.Enabled = false;
- }
- }
- else
- {
- this.IconNameToolStripMenuItem.Enabled = false;
- this.ReloadIconToolStripMenuItem.Enabled = false;
- this.SaveIconPictureToolStripMenuItem.Enabled = false;
- this.IconNameToolStripMenuItem.Text = Properties.Resources.ContextMenuStrip3_OpeningText1;
- }
- }
- else
- {
- this.IconNameToolStripMenuItem.Enabled = false;
- this.ReloadIconToolStripMenuItem.Enabled = false;
- this.SaveIconPictureToolStripMenuItem.Enabled = false;
- this.IconNameToolStripMenuItem.Text = Properties.Resources.ContextMenuStrip3_OpeningText2;
- }
- if (NameLabel.Tag != null)
- {
- string id = (string)NameLabel.Tag;
- if (id == tw.Username)
- {
- FollowToolStripMenuItem.Enabled = false;
- UnFollowToolStripMenuItem.Enabled = false;
- ShowFriendShipToolStripMenuItem.Enabled = false;
- ShowUserStatusToolStripMenuItem.Enabled = true;
- SearchPostsDetailNameToolStripMenuItem.Enabled = true;
- SearchAtPostsDetailNameToolStripMenuItem.Enabled = false;
- ListManageUserContextToolStripMenuItem3.Enabled = true;
- }
- else
- {
- FollowToolStripMenuItem.Enabled = true;
- UnFollowToolStripMenuItem.Enabled = true;
- ShowFriendShipToolStripMenuItem.Enabled = true;
- ShowUserStatusToolStripMenuItem.Enabled = true;
- SearchPostsDetailNameToolStripMenuItem.Enabled = true;
- SearchAtPostsDetailNameToolStripMenuItem.Enabled = true;
- ListManageUserContextToolStripMenuItem3.Enabled = true;
- }
- }
- else
- {
- FollowToolStripMenuItem.Enabled = false;
- UnFollowToolStripMenuItem.Enabled = false;
- ShowFriendShipToolStripMenuItem.Enabled = false;
- ShowUserStatusToolStripMenuItem.Enabled = false;
- SearchPostsDetailNameToolStripMenuItem.Enabled = false;
- SearchAtPostsDetailNameToolStripMenuItem.Enabled = false;
- ListManageUserContextToolStripMenuItem3.Enabled = false;
- }
- }
-
- private async void IconNameToolStripMenuItem_Click(object sender, EventArgs e)
- {
- if (_curPost == null) return;
- string name = _curPost.ImageUrl;
- await this.OpenUriInBrowserAsync(name.Remove(name.LastIndexOf("_normal"), 7)); // "_normal".Length
- }
-
- private async void ReloadIconToolStripMenuItem_Click(object sender, EventArgs e)
- {
- if (this._curPost == null) return;
-
- await this.UserPicture.SetImageFromTask(async () =>
- {
- var imageUrl = this._curPost.ImageUrl;
-
- var image = await this.IconCache.DownloadImageAsync(imageUrl, force: true)
- .ConfigureAwait(false);
-
- return await image.CloneAsync()
- .ConfigureAwait(false);
- });
- }
-
- private void SaveOriginalSizeIconPictureToolStripMenuItem_Click(object sender, EventArgs e)
- {
- if (_curPost == null) return;
- string name = _curPost.ImageUrl;
- name = Path.GetFileNameWithoutExtension(name.Substring(name.LastIndexOf('/')));
-
- this.SaveFileDialog1.FileName = name.Substring(0, name.Length - 8); // "_normal".Length + 1
-
- if (this.SaveFileDialog1.ShowDialog() == DialogResult.OK)
- {
- // STUB
- }
- }
-
- private void SaveIconPictureToolStripMenuItem_Click(object sender, EventArgs e)
- {
- if (_curPost == null) return;
- string name = _curPost.ImageUrl;
-
- this.SaveFileDialog1.FileName = name.Substring(name.LastIndexOf('/') + 1);
-
- if (this.SaveFileDialog1.ShowDialog() == DialogResult.OK)
- {
- try
- {
- using (Image orgBmp = new Bitmap(IconCache.TryGetFromCache(name).Image))
- {
- using (Bitmap bmp2 = new Bitmap(orgBmp.Size.Width, orgBmp.Size.Height))
- {
- using (Graphics g = Graphics.FromImage(bmp2))
- {
- g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
- g.DrawImage(orgBmp, 0, 0, orgBmp.Size.Width, orgBmp.Size.Height);
- }
- bmp2.Save(this.SaveFileDialog1.FileName);
- }
- }
- }
- catch (Exception)
- {
- //処理中にキャッシュアウトする可能性あり
- }
- }
- }
-
private void SplitContainer2_Panel2_Resize(object sender, EventArgs e)
{
var multiline = this.SplitContainer2.Panel2.Height > this.SplitContainer2.Panel2MinSize + 2;
{
string tmp = StatusText.SelectedText;
// httpから始まらない場合、ExcludeStringで指定された文字列で始まる場合は対象としない
- if (tmp.StartsWith("http"))
+ if (tmp.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
// 文字列が選択されている場合はその文字列について処理
//}
}
- private void SelectionCopyContextMenuItem_Click(object sender, EventArgs e)
- {
- //発言詳細で「選択文字列をコピー」
- string _selText = this.PostBrowser.GetSelectedText();
- try
- {
- Clipboard.SetDataObject(_selText, false, 5, 100);
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message);
- }
- }
-
- private async Task doSearchToolStrip(string url)
- {
- //発言詳細で「選択文字列で検索」(選択文字列取得)
- string _selText = this.PostBrowser.GetSelectedText();
-
- if (_selText != null)
- {
- if (url == Properties.Resources.SearchItem4Url)
- {
- //公式検索
- AddNewTabForSearch(_selText);
- return;
- }
-
- string tmp = string.Format(url, Uri.EscapeDataString(_selText));
- await this.OpenUriInBrowserAsync(tmp);
- }
- }
-
- private void SelectionAllContextMenuItem_Click(object sender, EventArgs e)
- {
- //発言詳細ですべて選択
- PostBrowser.Document.ExecCommand("SelectAll", false, null);
- }
-
- private async void SearchWikipediaContextMenuItem_Click(object sender, EventArgs e)
- {
- await this.doSearchToolStrip(Properties.Resources.SearchItem1Url);
- }
-
- private async void SearchGoogleContextMenuItem_Click(object sender, EventArgs e)
- {
- await this.doSearchToolStrip(Properties.Resources.SearchItem2Url);
- }
-
- private async void SearchPublicSearchContextMenuItem_Click(object sender, EventArgs e)
- {
- await this.doSearchToolStrip(Properties.Resources.SearchItem4Url);
- }
-
- private void UrlCopyContextMenuItem_Click(object sender, EventArgs e)
- {
- try
- {
- foreach (var link in this.PostBrowser.Document.Links.Cast<HtmlElement>())
- {
- if (link.GetAttribute("href") == this._postBrowserStatusText)
- {
- var linkStr = link.GetAttribute("title");
- if (string.IsNullOrEmpty(linkStr))
- linkStr = link.GetAttribute("href");
-
- Clipboard.SetDataObject(linkStr, false, 5, 100);
- return;
- }
- }
-
- Clipboard.SetDataObject(this._postBrowserStatusText, false, 5, 100);
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message);
- }
- }
-
- private void ContextMenuPostBrowser_Opening(object ender, CancelEventArgs e)
- {
- // URLコピーの項目の表示/非表示
- if (PostBrowser.StatusText.StartsWith("http", StringComparison.Ordinal))
- {
- this._postBrowserStatusText = PostBrowser.StatusText;
- string name = GetUserId();
- UrlCopyContextMenuItem.Enabled = true;
- if (name != null)
- {
- FollowContextMenuItem.Enabled = true;
- RemoveContextMenuItem.Enabled = true;
- FriendshipContextMenuItem.Enabled = true;
- ShowUserStatusContextMenuItem.Enabled = true;
- SearchPostsDetailToolStripMenuItem.Enabled = true;
- IdFilterAddMenuItem.Enabled = true;
- ListManageUserContextToolStripMenuItem.Enabled = true;
- SearchAtPostsDetailToolStripMenuItem.Enabled = true;
- }
- else
- {
- FollowContextMenuItem.Enabled = false;
- RemoveContextMenuItem.Enabled = false;
- FriendshipContextMenuItem.Enabled = false;
- ShowUserStatusContextMenuItem.Enabled = false;
- SearchPostsDetailToolStripMenuItem.Enabled = false;
- IdFilterAddMenuItem.Enabled = false;
- ListManageUserContextToolStripMenuItem.Enabled = false;
- SearchAtPostsDetailToolStripMenuItem.Enabled = false;
- }
-
- if (Regex.IsMatch(this._postBrowserStatusText, @"^https?://twitter.com/search\?q=%23"))
- UseHashtagMenuItem.Enabled = true;
- else
- UseHashtagMenuItem.Enabled = false;
- }
- else
- {
- this._postBrowserStatusText = "";
- UrlCopyContextMenuItem.Enabled = false;
- FollowContextMenuItem.Enabled = false;
- RemoveContextMenuItem.Enabled = false;
- FriendshipContextMenuItem.Enabled = false;
- ShowUserStatusContextMenuItem.Enabled = false;
- SearchPostsDetailToolStripMenuItem.Enabled = false;
- SearchAtPostsDetailToolStripMenuItem.Enabled = false;
- UseHashtagMenuItem.Enabled = false;
- IdFilterAddMenuItem.Enabled = false;
- ListManageUserContextToolStripMenuItem.Enabled = false;
- }
- // 文字列選択されていないときは選択文字列関係の項目を非表示に
- string _selText = this.PostBrowser.GetSelectedText();
- if (_selText == null)
- {
- SelectionSearchContextMenuItem.Enabled = false;
- SelectionCopyContextMenuItem.Enabled = false;
- SelectionTranslationToolStripMenuItem.Enabled = false;
- }
- else
- {
- SelectionSearchContextMenuItem.Enabled = true;
- SelectionCopyContextMenuItem.Enabled = true;
- SelectionTranslationToolStripMenuItem.Enabled = true;
- }
- //発言内に自分以外のユーザーが含まれてればフォロー状態全表示を有効に
- MatchCollection ma = Regex.Matches(this.PostBrowser.DocumentText, @"href=""https?://twitter.com/(#!/)?(?<ScreenName>[a-zA-Z0-9_]+)(/status(es)?/[0-9]+)?""");
- bool fAllFlag = false;
- foreach (Match mu in ma)
- {
- if (mu.Result("${ScreenName}").ToLowerInvariant() != tw.Username.ToLowerInvariant())
- {
- fAllFlag = true;
- break;
- }
- }
- this.FriendshipAllMenuItem.Enabled = fAllFlag;
-
- if (_curPost == null)
- TranslationToolStripMenuItem.Enabled = false;
- else
- TranslationToolStripMenuItem.Enabled = true;
-
- e.Cancel = false;
- }
-
- private void CurrentTabToolStripMenuItem_Click(object sender, EventArgs e)
- {
- //発言詳細の選択文字列で現在のタブを検索
- string _selText = this.PostBrowser.GetSelectedText();
-
- if (_selText != null)
- {
- var searchOptions = new SearchWordDialog.SearchOptions(
- SearchWordDialog.SearchType.Timeline,
- _selText,
- newTab: false,
- caseSensitive: false,
- useRegex: false);
-
- this.SearchDialog.ResultOptions = searchOptions;
-
- this.DoTabSearch(
- searchOptions.Query,
- searchOptions.CaseSensitive,
- searchOptions.UseRegex,
- SEARCHTYPE.NextSearch);
- }
- }
-
private void SplitContainer2_SplitterMoved(object sender, SplitterEventArgs e)
{
if (StatusText.Multiline) _mySpDis2 = StatusText.Height;
_curTab = _tab;
_curList = (DetailsListView)_tab.Tag;
+
if (_curList.SelectedIndices.Count > 0)
{
_curItemIndex = _curList.SelectedIndices[0];
private async void TweenMain_Shown(object sender, EventArgs e)
{
- try
- {
- using (ControlTransaction.Update(this.PostBrowser))
- {
- PostBrowser.Url = new Uri("about:blank");
- PostBrowser.DocumentText = ""; //発言詳細部初期化
- }
- }
- catch (Exception)
- {
- }
-
NotifyIcon1.Visible = true;
if (this.IsNetworkAvailable())
//公式RT
if (this.ExistCurrentPost)
{
- if (_curPost.IsProtect)
+ if (!_curPost.CanRetweetBy(this.twitterApi.CurrentUserId))
{
- MessageBox.Show("Protected.");
+ if (this._curPost.IsProtect)
+ MessageBox.Show("Protected.");
+
_DoFavRetweetFlags = false;
return;
}
}
else
{
- if (_curPost.IsDm || _curPost.IsMe)
- {
- _DoFavRetweetFlags = false;
- return;
- }
if (!this._cfgCommon.RetweetNoConfirm)
{
string Questiontext = Properties.Resources.RetweetQuestion1;
foreach (int idx in _curList.SelectedIndices)
{
PostClass post = GetCurTabPost(idx);
- if (!post.IsMe && !post.IsProtect && !post.IsDm)
+ if (post.CanRetweetBy(this.twitterApi.CurrentUserId))
statusIds.Add(post.StatusId);
}
private async void DumpPostClassToolStripMenuItem_Click(object sender, EventArgs e)
{
+ this.tweetDetailsView.DumpPostClass = this.DumpPostClassToolStripMenuItem.Checked;
+
if (_curPost != null)
await this.DispSelectedPost(true);
}
private void TabRenameMenuItem_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(_rclickTabName)) return;
- TabRename(ref _rclickTabName);
+
+ string _;
+ TabRename(_rclickTabName, out _);
}
private async void BitlyToolStripMenuItem_Click(object sender, EventArgs e)
await this.FollowCommand(id);
}
- private async Task FollowCommand(string id)
+ internal async Task FollowCommand(string id)
{
using (var inputName = new InputTabName())
{
await this.RemoveCommand(id, false);
}
- private async Task RemoveCommand(string id, bool skipInput)
+ internal async Task RemoveCommand(string id, bool skipInput)
{
if (!skipInput)
{
await this.ShowFriendship(id);
}
- private async Task ShowFriendship(string id)
+ internal async Task ShowFriendship(string id)
{
using (var inputName = new InputTabName())
{
MessageBox.Show(result);
}
- private async Task ShowFriendship(string[] ids)
+ internal async Task ShowFriendship(string[] ids)
{
foreach (string id in ids)
{
return !this.tw.Configuration.NonUsernamePaths.Contains(name.ToLowerInvariant());
}
- private string GetUserId()
- {
- Match m = Regex.Match(this._postBrowserStatusText, @"^https?://twitter.com/(#!/)?(?<ScreenName>[a-zA-Z0-9_]+)(/status(es)?/[0-9]+)?$");
- if (m.Success && IsTwitterId(m.Result("${ScreenName}")))
- return m.Result("${ScreenName}");
- else
- return null;
- }
-
- private async void FollowContextMenuItem_Click(object sender, EventArgs e)
- {
- string name = GetUserId();
- if (name != null)
- await this.FollowCommand(name);
- }
-
- private async void RemoveContextMenuItem_Click(object sender, EventArgs e)
- {
- string name = GetUserId();
- if (name != null)
- await this.RemoveCommand(name, false);
- }
-
- private async void FriendshipContextMenuItem_Click(object sender, EventArgs e)
- {
- string name = GetUserId();
- if (name != null)
- await this.ShowFriendship(name);
- }
-
- private async void FriendshipAllMenuItem_Click(object sender, EventArgs e)
- {
- MatchCollection ma = Regex.Matches(this.PostBrowser.DocumentText, @"href=""https?://twitter.com/(#!/)?(?<ScreenName>[a-zA-Z0-9_]+)(/status(es)?/[0-9]+)?""");
- List<string> ids = new List<string>();
- foreach (Match mu in ma)
- {
- if (mu.Result("${ScreenName}").ToLower() != tw.Username.ToLower())
- {
- ids.Add(mu.Result("${ScreenName}"));
- }
- }
-
- await this.ShowFriendship(ids.ToArray());
- }
-
- private async void ShowUserStatusContextMenuItem_Click(object sender, EventArgs e)
- {
- string name = GetUserId();
- if (name != null)
- await this.ShowUserStatus(name);
- }
-
- private void SearchPostsDetailToolStripMenuItem_Click(object sender, EventArgs e)
- {
- string name = GetUserId();
- if (name != null) AddNewTabForUserTimeline(name);
- }
-
- private void SearchAtPostsDetailToolStripMenuItem_Click(object sender, EventArgs e)
- {
- string name = GetUserId();
- if (name != null) AddNewTabForSearch("@" + name);
- }
-
private void IdeographicSpaceToSpaceToolStripMenuItem_Click(object sender, EventArgs e)
{
ModifySettingCommon = true;
for (int i = 2; i <= 100; i++)
{
if (!_statuses.ContainsTab(renamed)) break;
- renamed = TabName + i.ToString();
+ renamed = TabName + i;
}
tb.TabName = renamed;
for (int i = 1; i < int.MaxValue; i++)
{
if (!_statuses.ContainsTab(renamed)) break;
- renamed = tb.TabName + "(" + i.ToString() + ")";
+ renamed = tb.TabName + "(" + i + ")";
}
tb.TabName = renamed;
await this.doMoveToRTHome();
}
- private void IdFilterAddMenuItem_Click(object sender, EventArgs e)
+ private void ListManageUserContextToolStripMenuItem_Click(object sender, EventArgs e)
{
- string name = GetUserId();
- if (name != null)
- {
- string tabName;
-
- //未選択なら処理終了
- if (_curList.SelectedIndices.Count == 0) return;
-
- //タブ選択(or追加)
- if (!SelectTab(out tabName)) return;
-
- var tab = (FilterTabModel)this._statuses.Tabs[tabName];
-
- bool mv;
- bool mk;
- if (tab.TabType != MyCommon.TabUsageType.Mute)
- {
- this.MoveOrCopy(out mv, out mk);
- }
- else
- {
- // ミュートタブでは常に MoveMatches を true にする
- mv = true;
- mk = false;
- }
-
- PostFilterRule fc = new PostFilterRule();
- fc.FilterName = name;
- fc.UseNameField = true;
- fc.MoveMatches = mv;
- fc.MarkMatches = mk;
- fc.UseRegex = false;
- fc.FilterByUrl = false;
- tab.AddFilter(fc);
-
- this.ApplyPostFilters();
- SaveConfigsTabs();
- }
+ var screenName = this._curPost?.ScreenName;
+ if (screenName != null)
+ this.ListManageUserContext(screenName);
}
- private async void ListManageUserContextToolStripMenuItem_Click(object sender, EventArgs e)
+ public void ListManageUserContext(string screenName)
{
- string user;
-
- ToolStripMenuItem menuItem = (ToolStripMenuItem)sender;
-
- if (menuItem.Owner == this.ContextMenuPostBrowser)
- {
- user = GetUserId();
- if (user == null) return;
- }
- else if (this._curPost != null)
- {
- user = this._curPost.ScreenName;
- }
- else
- {
- return;
- }
-
- if (TabInformations.GetInstance().SubscribableLists.Count == 0)
- {
- try
- {
- using (var dialog = new WaitingDialog(Properties.Resources.ListsGetting))
- {
- var cancellationToken = dialog.EnableCancellation();
-
- var task = this.tw.GetListsApi();
- await dialog.WaitForAsync(this, task);
-
- cancellationToken.ThrowIfCancellationRequested();
- }
- }
- catch (OperationCanceledException) { return; }
- catch (WebApiException ex)
- {
- MessageBox.Show("Failed to get lists. (" + ex.Message + ")");
- return;
- }
- }
-
- using (MyLists listSelectForm = new MyLists(user, this.tw))
+ using (var listSelectForm = new MyLists(screenName, this.twitterApi))
{
listSelectForm.ShowDialog(this);
}
}
}
- private void UseHashtagMenuItem_Click(object sender, EventArgs e)
- {
- Match m = Regex.Match(this._postBrowserStatusText, @"^https?://twitter.com/search\?q=%23(?<hash>.+)$");
- if (m.Success)
- {
- HashMgr.SetPermanentHash("#" + Uri.UnescapeDataString(m.Result("${hash}")));
- HashStripSplitButton.Text = HashMgr.UseHash;
- HashToggleMenuItem.Checked = true;
- HashToggleToolStripMenuItem.Checked = true;
- //使用ハッシュタグとして設定
- ModifySettingCommon = true;
- }
- }
-
private void StatusLabel_DoubleClick(object sender, EventArgs e)
{
MessageBox.Show(StatusLabel.TextHistory, "Logs", MessageBoxButtons.OK, MessageBoxIcon.None);
HashToggleMenuItem_Click(null, null);
}
+ public void SetPermanentHashtag(string hashtag)
+ {
+ HashMgr.SetPermanentHash("#" + hashtag);
+ HashStripSplitButton.Text = HashMgr.UseHash;
+ HashToggleMenuItem.Checked = true;
+ HashToggleToolStripMenuItem.Checked = true;
+ //使用ハッシュタグとして設定
+ ModifySettingCommon = true;
+ }
+
private void MenuItemOperate_DropDownOpening(object sender, EventArgs e)
{
if (ListTab.SelectedTab == null) return;
this.OpenFavotterOpMenuItem.Enabled = true;
this.ShowRelatedStatusesMenuItem2.Enabled = true; //PublicSearchの時問題出るかも
- if (_curPost.IsMe)
+ if (!_curPost.CanRetweetBy(this.twitterApi.CurrentUserId))
{
- this.RtOpMenuItem.Enabled = false; //公式RTは無効に
- this.RtUnOpMenuItem.Enabled = true;
- this.QtOpMenuItem.Enabled = true;
- this.FavoriteRetweetMenuItem.Enabled = false; //公式RTは無効に
- this.FavoriteRetweetUnofficialMenuItem.Enabled = true;
+ this.RtOpMenuItem.Enabled = false;
+ this.RtUnOpMenuItem.Enabled = false;
+ this.QtOpMenuItem.Enabled = false;
+ this.FavoriteRetweetMenuItem.Enabled = false;
+ this.FavoriteRetweetUnofficialMenuItem.Enabled = false;
}
else
{
- if (_curPost.IsProtect)
- {
- this.RtOpMenuItem.Enabled = false;
- this.RtUnOpMenuItem.Enabled = false;
- this.QtOpMenuItem.Enabled = false;
- this.FavoriteRetweetMenuItem.Enabled = false;
- this.FavoriteRetweetUnofficialMenuItem.Enabled = false;
- }
- else
- {
- this.RtOpMenuItem.Enabled = true;
- this.RtUnOpMenuItem.Enabled = true;
- this.QtOpMenuItem.Enabled = true;
- this.FavoriteRetweetMenuItem.Enabled = true;
- this.FavoriteRetweetUnofficialMenuItem.Enabled = true;
- }
+ this.RtOpMenuItem.Enabled = true;
+ this.RtUnOpMenuItem.Enabled = true;
+ this.QtOpMenuItem.Enabled = true;
+ this.FavoriteRetweetMenuItem.Enabled = true;
+ this.FavoriteRetweetUnofficialMenuItem.Enabled = true;
}
}
}
}
- private Task ShowUserStatus(string id, bool ShowInputDialog)
+ internal Task ShowUserStatus(string id, bool ShowInputDialog)
{
return this.doShowUserStatus(id, ShowInputDialog);
}
- private Task ShowUserStatus(string id)
+ internal Task ShowUserStatus(string id)
{
return this.doShowUserStatus(id, true);
}
- private async void FollowToolStripMenuItem_Click(object sender, EventArgs e)
- {
- if (NameLabel.Tag != null)
- {
- string id = (string)NameLabel.Tag;
- if (id != tw.Username)
- {
- await this.FollowCommand(id);
- }
- }
- }
-
- private async void UnFollowToolStripMenuItem_Click(object sender, EventArgs e)
- {
- if (NameLabel.Tag != null)
- {
- string id = (string)NameLabel.Tag;
- if (id != tw.Username)
- {
- await this.RemoveCommand(id, false);
- }
- }
- }
-
- private async void ShowFriendShipToolStripMenuItem_Click(object sender, EventArgs e)
- {
- if (NameLabel.Tag != null)
- {
- string id = (string)NameLabel.Tag;
- if (id != tw.Username)
- {
- await this.ShowFriendship(id);
- }
- }
- }
-
- private async void ShowUserStatusToolStripMenuItem_Click(object sender, EventArgs e)
- {
- if (NameLabel.Tag != null)
- {
- string id = (string)NameLabel.Tag;
- await this.ShowUserStatus(id, false);
- }
- }
-
- private void SearchPostsDetailNameToolStripMenuItem_Click(object sender, EventArgs e)
- {
- if (NameLabel.Tag != null)
- {
- string id = (string)NameLabel.Tag;
- AddNewTabForUserTimeline(id);
- }
- }
-
- private void SearchAtPostsDetailNameToolStripMenuItem_Click(object sender, EventArgs e)
- {
- if (NameLabel.Tag != null)
- {
- string id = (string)NameLabel.Tag;
- AddNewTabForSearch("@" + id);
- }
- }
-
private async void ShowProfileMenuItem_Click(object sender, EventArgs e)
{
if (_curPost != null)
this.StatusText.Dock = DockStyle.Fill;
}
+ this.tweetDetailsView.Owner = this;
+
this.TimerTimeline.Elapsed += this.TimerTimeline_Elapsed;
this._hookGlobalHotkey.HotkeyPressed += _hookGlobalHotkey_HotkeyPressed;
this.gh.NotifyClicked += GrowlHelper_Callback;
}
}
- private void UserPicture_MouseEnter(object sender, EventArgs e)
- {
- this.UserPicture.Cursor = Cursors.Hand;
- }
-
- private void UserPicture_MouseLeave(object sender, EventArgs e)
- {
- this.UserPicture.Cursor = Cursors.Default;
- }
-
- private async void UserPicture_DoubleClick(object sender, EventArgs e)
- {
- if (NameLabel.Tag != null)
- {
- await this.OpenUriInBrowserAsync(MyCommon.TwitterUrl + NameLabel.Tag.ToString());
- }
- }
-
private void SplitContainer2_MouseDoubleClick(object sender, MouseEventArgs e)
{
this.MultiLineMenuItem.PerformClick();
ModifySettingCommon = true;
SaveConfigsAll(true);
- if (ImageSelector.ServiceName.Equals("Twitter"))
- this.StatusText_TextChanged(null, null);
+ this.StatusText_TextChanged(null, null);
}
}
/// </summary>
private void ProcClipboardFromStatusTextWhenCtrlPlusV()
{
- if (Clipboard.ContainsText())
- {
- // clipboardにテキストがある場合は貼り付け処理
- this.StatusText.Paste(Clipboard.GetText());
- }
- else if (Clipboard.ContainsImage())
+ try
{
- // 画像があるので投稿処理を行う
- if (MessageBox.Show(Properties.Resources.PostPictureConfirm3,
- Properties.Resources.PostPictureWarn4,
- MessageBoxButtons.OKCancel,
- MessageBoxIcon.Question,
- MessageBoxDefaultButton.Button2)
- == DialogResult.OK)
+ if (Clipboard.ContainsText())
+ {
+ // clipboardにテキストがある場合は貼り付け処理
+ this.StatusText.Paste(Clipboard.GetText());
+ }
+ else if (Clipboard.ContainsImage())
{
- // clipboardから画像を取得
- using (var image = Clipboard.GetImage())
+ // 画像があるので投稿処理を行う
+ if (MessageBox.Show(Properties.Resources.PostPictureConfirm3,
+ Properties.Resources.PostPictureWarn4,
+ MessageBoxButtons.OKCancel,
+ MessageBoxIcon.Question,
+ MessageBoxDefaultButton.Button2)
+ == DialogResult.OK)
{
- this.ImageSelector.BeginSelection(image);
+ // clipboardから画像を取得
+ using (var image = Clipboard.GetImage())
+ {
+ this.ImageSelector.BeginSelection(image);
+ }
}
}
}
+ catch (ExternalException ex)
+ {
+ MessageBox.Show(ex.Message);
+ }
}
#endregion
public bool ModifySettingLocal { get; set; }
public bool ModifySettingAtId { get; set; }
- private async void SourceLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
- {
- var sourceUri = (Uri)this.SourceLinkLabel.Tag;
- if (sourceUri != null && e.Button == MouseButtons.Left)
- {
- await this.OpenUriInBrowserAsync(sourceUri.AbsoluteUri);
- }
- }
-
- private void SourceLinkLabel_MouseEnter(object sender, EventArgs e)
- {
- var sourceUri = (Uri)this.SourceLinkLabel.Tag;
- if (sourceUri != null)
- {
- StatusLabelUrl.Text = MyCommon.ConvertToReadableUrl(sourceUri.AbsoluteUri);
- }
- }
-
- private void SourceLinkLabel_MouseLeave(object sender, EventArgs e)
- {
- SetStatusLabelUrl();
- }
-
private void MenuItemCommand_DropDownOpening(object sender, EventArgs e)
{
if (this.ExistCurrentPost && !_curPost.IsDm)
}
#region "Userstream"
- private void tw_PostDeleted(object sender, PostDeletedEventArgs e)
+ private async void tw_PostDeleted(object sender, PostDeletedEventArgs e)
{
try
{
if (InvokeRequired && !IsDisposed)
{
- Invoke((Action) (async () =>
- {
- this._statuses.RemovePostFromAllTabs(e.StatusId, setIsDeleted: true);
- if (_curTab != null && _statuses.Tabs[_curTab.Text].Contains(e.StatusId))
- {
- this.PurgeListViewItemCache();
- ((DetailsListView)_curTab.Tag).Update();
- if (_curPost != null && _curPost.StatusId == e.StatusId)
- await this.DispSelectedPost(true);
- }
- }));
+ await this.InvokeAsync(async () =>
+ {
+ this._statuses.RemovePostFromAllTabs(e.StatusId, setIsDeleted: true);
+ if (_curTab != null && _statuses.Tabs[_curTab.Text].Contains(e.StatusId))
+ {
+ this.PurgeListViewItemCache();
+ ((DetailsListView)_curTab.Tag).Update();
+ if (_curPost != null && _curPost.StatusId == e.StatusId)
+ await this.DispSelectedPost(true);
+ }
+ });
return;
}
}
_statuses.SetReadHomeTab(); //新着時未読クリア
}
- int rsltAddCount = _statuses.DistributePosts();
+ this._statuses.DistributePosts();
if (this._cfgCommon.UserstreamPeriod > 0) return;
}
}
- private void tw_UserStreamStarted(object sender, EventArgs e)
+ private async void tw_UserStreamStarted(object sender, EventArgs e)
{
try
{
if (InvokeRequired && !IsDisposed)
{
- Invoke((Action)(() => this.tw_UserStreamStarted(sender, e)));
+ await this.InvokeAsync(() => this.tw_UserStreamStarted(sender, e));
return;
}
}
StatusLabel.Text = "UserStream Started.";
}
- private void tw_UserStreamStopped(object sender, EventArgs e)
+ private async void tw_UserStreamStopped(object sender, EventArgs e)
{
try
{
if (InvokeRequired && !IsDisposed)
{
- Invoke((Action)(() => this.tw_UserStreamStopped(sender, e)));
+ await this.InvokeAsync(() => this.tw_UserStreamStopped(sender, e));
return;
}
}
}
}
- private void tw_UserStreamEventArrived(object sender, UserStreamEventReceivedEventArgs e)
+ private async void tw_UserStreamEventArrived(object sender, UserStreamEventReceivedEventArgs e)
{
try
{
if (InvokeRequired && !IsDisposed)
{
- Invoke((Action)(() => this.tw_UserStreamEventArrived(sender, e)));
+ await this.InvokeAsync(() => this.tw_UserStreamEventArrived(sender, e));
return;
}
}
title.Append("] by ");
if (!string.IsNullOrEmpty(ev.Username))
{
- title.Append(ev.Username.ToString());
+ title.Append(ev.Username);
}
else
{
await this.OpenUriInBrowserAsync(MyCommon.TwitterUrl + tw.Username);
}
- private async Task doTranslation(string str)
- {
- if (string.IsNullOrEmpty(str))
- return;
-
- var bing = new Bing();
- try
- {
- var translatedText = await bing.TranslateAsync(str,
- langFrom: null,
- langTo: this._cfgCommon.TranslateLanguage);
-
- this.PostBrowser.DocumentText = this.createDetailHtml(translatedText);
- }
- catch (HttpRequestException e)
- {
- this.StatusLabel.Text = "Err:" + e.Message;
- }
- catch (OperationCanceledException)
- {
- this.StatusLabel.Text = "Err:Timeout";
- }
- }
-
- private async void TranslationToolStripMenuItem_Click(object sender, EventArgs e)
- {
- if (!this.ExistCurrentPost)
- return;
-
- await this.doTranslation(this._curPost.TextFromApi);
- }
-
- private async void SelectionTranslationToolStripMenuItem_Click(object sender, EventArgs e)
- {
- var text = this.PostBrowser.GetSelectedText();
- await this.doTranslation(text);
- }
-
private bool ExistCurrentPost
{
get
await this.OpenUserAppointUrl();
}
- private void SourceCopyMenuItem_Click(object sender, EventArgs e)
- {
- string selText = SourceLinkLabel.Text;
- try
- {
- Clipboard.SetDataObject(selText, false, 5, 100);
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message);
- }
- }
-
- private void SourceUrlCopyMenuItem_Click(object sender, EventArgs e)
- {
- var sourceUri = (Uri)this.SourceLinkLabel.Tag;
- try
- {
- Clipboard.SetDataObject(sourceUri.AbsoluteUri, false, 5, 100);
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message);
- }
- }
-
- private void ContextMenuSource_Opening(object sender, CancelEventArgs e)
- {
- if (_curPost == null || !ExistCurrentPost || _curPost.IsDm)
- {
- SourceCopyMenuItem.Enabled = false;
- SourceUrlCopyMenuItem.Enabled = false;
- }
- else
- {
- SourceCopyMenuItem.Enabled = true;
- SourceUrlCopyMenuItem.Enabled = true;
- }
- }
-
- private void GrowlHelper_Callback(object sender, GrowlHelper.NotifyCallbackEventArgs e)
+ private async void GrowlHelper_Callback(object sender, GrowlHelper.NotifyCallbackEventArgs e)
{
if (Form.ActiveForm == null)
{
- this.BeginInvoke((Action) (() =>
+ await this.InvokeAsync(() =>
{
this.Visible = true;
if (this.WindowState == FormWindowState.Minimized) this.WindowState = FormWindowState.Normal;
{
if (!this.GoStatus(e.StatusId)) this.StatusText.Focus();
}
- }));
+ });
}
}
ModifySettingCommon = true;
}
+
+ private void tweetDetailsView_StatusChanged(object sender, TweetDetailsViewStatusChengedEventArgs e)
+ {
+ if (!string.IsNullOrEmpty(e.StatusText))
+ {
+ this.StatusLabelUrl.Text = e.StatusText;
+ }
+ else
+ {
+ this.SetStatusLabelUrl();
+ }
+ }
}
}