/// <summary> /// Adds an item to the queue. The new item is added at queueIndex /// which is the most recent position to which the user has tracked /// (usually the end of the array if no tracking has occurred). If /// queueIndex is in the middle of the array, we remove all items /// to the right (from queueIndex+1 onwards) in order to define a /// new 'head' position. This produces the expected results when tracking /// from the new item inserted back to the most recent item. /// </summary> /// <param name="item">Item to be added</param> public void AddToQueue(Address item) { while (_queueIndex + 1 < _array.Count) { _array.RemoveAt(_queueIndex + 1); } if (_array.Count == _maxItems) { _array.RemoveAt(0); --_queueIndex; } if (_array.Count > 0) { Address itemAddress = _array[_array.Count - 1]; if (itemAddress == item) { return; } } _array.Add(item); ++_queueIndex; }
/// <summary> /// Set the specified address by navigating to the folder referenced by /// the address. /// </summary> /// <param name="address">The address to be set</param> public void SetAddress(Address address) { if (SelectAddress(address)) { return; } if (JoinMissingForum(address)) { return; } Process.Start(address.SchemeAndQuery); }
/// <summary> /// Display the folder referenced by the given node, passing through the address and options. /// </summary> public bool SelectViewForFolder(TreeNode node, Address address, FolderOptions options) { FolderBase folder = (FolderBase)node.Tag; return SelectView(folder.ViewForFolder, folder, address, options); }
/// <summary> /// Find the specified folder in the tree and if found, select it. If it is /// already selected, invoke the view with the specified address. /// </summary> /// <param name="folder">The folder to select</param> /// <param name="address">The address to pass to the view</param> private void SetSelection(FolderBase folder, Address address) { if (folder != null) { TreeNode node = NodeForFolder(folder, frmList.Nodes); if (node != null && node.IsSelected) { SelectViewForFolder(node, address, 0); } else { _lastAddress = address; SelectFolder(node, 0); } } }
/// <summary> /// Display the selected view with the given folder, passing through the address and options. /// </summary> /// <param name="requestedView">The ID of the type of the view requested</param> /// <param name="folder">The folder to be displayed in the view</param> /// <param name="address">The address of the item within the folder to be selected</param> /// <param name="options">Options controlling the folder selection</param> /// <returns>True if the view was successfully selected, false otherwise</returns> private bool SelectView(AppView requestedView, FolderBase folder, Address address, FolderOptions options) { ViewBaseView newView = _allViews[requestedView]; if (newView != _currentView) { if (_currentView != null) { _currentView.Visible = false; frmSplitContainer.Panel2.Controls.Remove(_currentView); } if (newView != null) { frmSplitContainer.Panel2.Controls.Add(newView); _currentView = newView; SetSubviewSize(); newView.Visible = true; newView.Update(); } } ShowSearchBar(SearchBarVisibility.FastHide); if (folder != null) { string placeholder = folder.AllowsScopedSearch ? string.Format(Resources.SearchForTextIn, folder.Name) : Resources.Search; MainForm.SetSearchFieldPlaceholder(placeholder); SetTopicName(folder.FullName); } return (_currentView != null) && _currentView.ViewFromFolder(folder, address, options); }
/// <summary> /// Select a folder based on the address of the node. /// </summary> /// <param name="address">Address of the node</param> /// <returns>True if we found and selected the folder, false if it was not found</returns> private bool SelectAddress(Address address) { FolderBase selection = FolderFromAddress(address.SchemeAndQuery); if (selection != null) { SetSelection(selection, address); } return selection != null; }
/// <summary> /// Return the message that corresponds to a given CIX address if possible, or null if /// the input does not reference a valid message. /// </summary> public CIXMessage MessageFromAddress(string addressString) { Address address = new Address(addressString); int messageID; if (address.Scheme != null && Int32.TryParse(address.Data, out messageID)) { address = NormaliseAddress(address); string[] splitAddress = address.Query.Split(new[] {'/'}); if (splitAddress.Length == 2) { Folder forum = CIX.FolderCollection.Get(-1, splitAddress[0]); Folder topic = CIX.FolderCollection.Get(forum.ID, splitAddress[1]); return topic.Messages.MessageByID(messageID); } } return null; }
/// <summary> /// Display this view with the specified folder and options /// </summary> public override bool ViewFromFolder(FolderBase folder, Address address, FolderOptions flags) { if (_welcomePage == null) { FillCanvas(); } CIX.RefreshOnlineUsers(); FolderCollection.RefreshInterestingThreads(); return true; }
/// <summary> /// Removes an item from the tail of the queue as long as the queue is not empty and returns the backtrack data. /// </summary> /// <param name="item">Ref of the string to be set with the backtrack data</param> /// <returns>True if an item was returned, false otherwise</returns> public bool PreviousItemAtQueue(ref Address item) { if (_queueIndex > 0) { item = _array[--_queueIndex]; return true; } return false; }
/// <summary> /// Removes an item from the tail of the queue as long as the queue is not empty and returns the backtrack data. /// </summary> /// <param name="item">Ref of the string to be set with the backtrack data</param> /// <returns>True if an item was returned, false otherwise</returns> public bool NextItemAtQueue(ref Address item) { if (_queueIndex < _array.Count - 1) { item = _array[++_queueIndex]; return true; } return false; }
/// <summary> /// Display the specified topic folder in the thread list. /// </summary> /// <param name="folder">The folder whose topic is to be displayed</param> /// <param name="address"></param> /// <param name="options">Folder display flags</param> public override bool ViewFromFolder(FolderBase folder, Address address, FolderOptions options) { if (folder.ViewForFolder == AppView.AppViewTopic) { if ((_currentFolder != folder) || options.HasFlag(FolderOptions.ClearFilter)) { _currentFolder = folder; _currentFilterString = null; _isFiltering = false; _isTopicFolder = IsTopicFolder(); tsvMessages.SelectedIndices.Clear(); ShowMessage(null); if (FoldersTree.MainForm.RunEvent(EventID.FolderSelected, _isTopicFolder ? ((TopicFolder) folder).Folder : null)) { if (_isTopicFolder) { // Attempt to make topic switches cleaner by removing the old messages from display // when switching to a new topic will involve a delay caused by loading the messages // from the DB, sorting, etc. if (!((TopicFolder)_currentFolder).Folder.HasMessages && _messages != null && _messages.Count > 0) { _messages = new List<CIXMessage>(); InitialiseList(); RedrawAllItems(); } } SortConversations(); } UpdateFromFlags(); } // Load this topic from the server only if we're empty. if (_messages != null && _messages.Count == 0) { if (address != null && address.Scheme == "cix") { Int32.TryParse(address.Data, out _lastIndex); } folder.Refresh(); return false; } if (options.HasFlag(FolderOptions.ClearFilter)) { options &= ~FolderOptions.ClearFilter; _currentFilterString = null; _isFiltering = false; } if (address != null && address.Scheme == "cix") { int selectedID; Int32.TryParse(address.Data, out selectedID); if (!GoToMessage(selectedID)) { SetInitialSelection(); } if (address.Unread) { SelectedMessage.MarkUnread(); } } else if (options == 0) { SetInitialSelection(); } else { int row = SelectedRow; if (row < 0 || options.HasFlag(FolderOptions.Reset)) { row = -1; } else { CIXMessage selectedMessage = SelectedMessage; if (selectedMessage != null && selectedMessage.Unread) { selectedMessage.MarkRead(); } } if (!FirstUnreadAfterRow(row, options)) { return false; } } ActiveControl = tsvMessages; } return true; }
/// <summary> /// Display the directory for the specified CategoryFolder /// </summary> public override bool ViewFromFolder(FolderBase folder, Address address, FolderOptions options) { if (folder != _currentFolder) { _currentFolder = folder; SortConversations(); } // If an address is specified then it refers to a conversation ID that // needs to be selected. If it is not found, the first message is selected // instead. if (address != null && address.Scheme == "cixmailbox") { int selectedID; Int32.TryParse(address.Data, out selectedID); int selectedIndex; for (selectedIndex = 0; selectedIndex < _conversations.Count; ++selectedIndex) { InboxConversation conversation = _conversations[selectedIndex]; if (conversation.RemoteID == selectedID) break; } if (selectedIndex == _conversations.Count) { selectedIndex = 0; } SelectedRow = selectedIndex; if (address.Unread) { SelectedMessage.MarkUnread(); } return true; } // If options are specified then search for the next unread // in the list otherwise set the initial selection to something // useful. if (options == 0 && SelectedRow == -1) { SetInitialSelection(); } else { int row = inboxConversations.SearchRow; if (row < 0 || options.HasFlag(FolderOptions.Reset)) { row = 0; } else if (_conversations.Count > 0) { InboxConversation conversation = _conversations[row]; if (conversation.UnreadCount > 0) { conversation.MarkRead(); } } if (!FirstUnreadAfterRow(row, options)) { inboxConversations.SearchRow = 0; return false; } } FoldersTree.SetTopicName(_currentFolder.FullName); ActiveControl = inboxConversations; inboxConversations.Focus(); return true; }
/// <summary> /// Display the page for the specified forum. /// </summary> public override bool ViewFromFolder(FolderBase folder, Address address, FolderOptions flags) { if (folder is TopicFolder) { _currentFolder = folder as TopicFolder; _thisForum = CIX.DirectoryCollection.ForumByName(_currentFolder.Name); FoldersTree.SetTopicName(folder.Name); CIX.DirectoryCollection.RefreshForum(folder.Name); FillCanvas(); } return true; }
/// <summary> /// Display the directory for the specified CategoryFolder /// </summary> public override bool ViewFromFolder(FolderBase folder, Address address, FolderOptions flags) { CategoryFolder category = folder as CategoryFolder; if (category != null) { if (flags.HasFlag(FolderOptions.ClearFilter)) { _currentFilterString = null; } _currentCategory = category; _items = ItemsForView(); SortItems(); } return true; }
/// <summary> /// Invoke the Join dialog to join the forum specified by the address. /// This only works for cix: addresses. Others are ignored. /// </summary> /// <param name="address">The forum or forum/topic address</param> /// <returns>True if we displayed the Join Forum dialog, false otherwise</returns> private static bool JoinMissingForum(Address address) { if (address.Scheme == "cix") { string[] splitAddress = address.Query.Split(new[] {'/'}); if (splitAddress.Length > 0) { JoinForum joinForum = new JoinForum(splitAddress[0]); joinForum.ShowDialog(); return true; } } return false; }
/// <summary> /// Recursively locate the folder whose address corresponds to the given address /// under the specified tree node collection. /// </summary> /// <param name="address">Address to match</param> /// <param name="nodes">Tree nodes to search</param> /// <returns>The FolderBase of the folder with the given address, or null if it was not found</returns> private FolderBase FolderFromAddress(string address, IEnumerable nodes) { foreach (TreeNode node in nodes) { FolderBase folder = node.Tag as FolderBase; if (folder != null && folder.Address == address) { return folder; } if (node.Nodes.Count > 0) { FolderBase subFolder = FolderFromAddress(address, node.Nodes); if (subFolder != null) { return subFolder; } } } // Not found but possibly hidden if we're filtering by recent so parse off // the parent folder and look for that, then unhide the topic. Address addr = new Address(address); if (addr.Scheme == "cix" && addr.Query != null) { string[] splitAddress = addr.Query.Split(new[] {'\\'}); if (splitAddress.Length == 2) { Folder forum = CIX.FolderCollection.Get(-1, splitAddress[0]); Folder topic = CIX.FolderCollection.Get(forum.ID, splitAddress[1]); if (topic != null && !topic.IsRecent) { topic.IsRecent = true; FolderBase forumFolder = FolderWithID(forum.ID, _forumsTree.Nodes); ReloadForumTreeFromNode(forumFolder); return FolderWithID(topic.ID, _forumsTree.Nodes); } } } return null; }
/// <summary> /// Refresh the view for the folder at the given node. /// </summary> /// <param name="node">The node of the folder to refresh</param> /// <param name="options">Options to be passed to the view</param> private void RefreshFolder(TreeNode node, FolderOptions options) { if (node != null) { SelectViewForFolder(node, _lastAddress, options); _lastAddress = null; } }
/// <summary> /// Display this view with the specified folder and options /// </summary> public virtual bool ViewFromFolder(FolderBase folder, Address address, FolderOptions flags) { return true; }
/// <summary> /// Normalise the query in the address so that the full address is specified. /// </summary> private Address NormaliseAddress(Address address) { if (address.Scheme != null && address.Scheme == "cix") { if (string.IsNullOrEmpty(address.Query)) { string oldAddress = address.Data; TreeNode node = FoldersTree.SelectedNode; if (node != null) { FolderBase folder = (FolderBase)node.Tag; string newAddress = folder.Address; address = new Address(newAddress) { Data = oldAddress }; } } // Special case the cix:/topic convention here because it requires us to // know the forum from the selection which is only possible when we have // the UI from which to determine the selection. else if (address.Query.StartsWith("/", StringComparison.Ordinal)) { TreeNode node = FoldersTree.SelectedNode; if (node != null) { FolderBase folder = (FolderBase)node.Tag; if (folder is TopicFolder && !((TopicFolder)folder).Folder.IsRootFolder) { Folder forum = ((TopicFolder)folder).Folder.ParentFolder; address.Query = string.Format("{0}{1}", forum.Name, address.Query); } } } } return address; }