private void setListViewSubItemsTags(ListViewItem item, FullMergeRequestKey fmk) { Debug.Assert(item.ListView == this); Debug.Assert(!isSummaryItem(item)); MergeRequest mr = fmk.MergeRequest; string author = String.Format("{0}\n({1}{2})", mr.Author.Name, Constants.AuthorLabelPrefix, mr.Author.Username); IEnumerable <string> groupedLabels = GitLabClient.Helpers.GroupLabels(fmk, Program.ServiceManager.GetUnimportantSuffices(), _getCurrentUser(fmk.ProjectKey.HostName)); Dictionary <bool, string> labels = new Dictionary <bool, string> { [false] = StringUtils.JoinSubstringsLimited(groupedLabels, MaxListViewRows, MoreListViewRowsHint), [true] = StringUtils.JoinSubstrings(groupedLabels) }; MergeRequestKey mrk = new MergeRequestKey(fmk.ProjectKey, mr.IId); setSubItemTag(item, "IId", new ListViewSubItemInfo(x => mr.IId.ToString(), () => mr.Web_Url)); setSubItemTag(item, "Author", new ListViewSubItemInfo(x => author, () => String.Empty)); setSubItemTag(item, "Title", new ListViewSubItemInfo(x => mr.Title, () => String.Empty)); setSubItemTag(item, "Labels", new ListViewSubItemInfo(x => labels[x], () => String.Empty)); setSubItemTag(item, "Size", new ListViewSubItemInfo(x => getSize(mrk), () => String.Empty)); setSubItemTag(item, "Jira", new ListViewSubItemInfo(x => getJiraTask(mr), () => getJiraTaskUrl(mr))); setSubItemTag(item, "TotalTime", new ListViewSubItemInfo(x => getTotalTimeText(mrk, mr.Author), () => String.Empty)); setSubItemTag(item, "SourceBranch", new ListViewSubItemInfo(x => mr.Source_Branch, () => String.Empty)); setSubItemTag(item, "TargetBranch", new ListViewSubItemInfo(x => mr.Target_Branch, () => String.Empty)); setSubItemTag(item, "State", new ListViewSubItemInfo(x => mr.State, () => String.Empty)); setSubItemTag(item, "Resolved", new ListViewSubItemInfo(x => getDiscussionCount(mrk), () => String.Empty)); setSubItemTag(item, "RefreshTime", new ListViewSubItemInfo(x => getRefreshed(mrk, x), () => String.Empty)); setSubItemTag(item, "Activities", new ListViewSubItemInfo(x => getActivities(mr.Created_At, mrk, x), () => String.Empty)); }
public int Compare(object x, object y) { ListViewItem item1 = x as ListViewItem; ListViewItem item2 = y as ListViewItem; FullMergeRequestKey key1 = (FullMergeRequestKey)item1.Tag; FullMergeRequestKey key2 = (FullMergeRequestKey)item2.Tag; if (key1.MergeRequest == null && key2.MergeRequest == null) { return(0); } else if (key1.MergeRequest == null && key2.MergeRequest != null) { return(-1); } else if (key1.MergeRequest != null && key2.MergeRequest == null) { return(1); } Debug.Assert(key1.MergeRequest != null && key2.MergeRequest != null); int id1 = key1.MergeRequest.Id; int id2 = key2.MergeRequest.Id; if (id1 > id2) { return(-1); } if (id1 < id2) { return(1); } return(0); }
private bool isMuted(FullMergeRequestKey fmk) { if (isSummaryKey(fmk)) { return(getMatchingFilterProjectItems(fmk.ProjectKey).Any(key => isMuted(key))); } return(_mutedMergeRequests .Any(mrk => mrk.Key.IId == fmk.MergeRequest.IId && mrk.Key.ProjectKey.Equals(fmk.ProjectKey))); }
/////////////////////////////////////////////////////////////////////////////////////////////////// private void onSingleSearchMergeRequestLoaded(FullMergeRequestKey fmk) { if (!isSearchMode()) { // because this callback updates controls shared between Live and Search tabs return; } onSingleMergeRequestLoadedCommon(fmk, _searchDataCache); }
private Color getMergeRequestColor(FullMergeRequestKey fmk, Color defaultColor, bool ignoreMuted) { IEnumerable <FullMergeRequestKey> mergeRequests = isSummaryKey(fmk) ? getMatchingFilterProjectItems(fmk.ProjectKey) : new List <FullMergeRequestKey> { fmk }; mergeRequests = ignoreMuted ? excludeMuted(mergeRequests) : mergeRequests; return(getMergeRequestCollectionColor(mergeRequests) ?? defaultColor); }
private ListViewItem createListViewMergeRequestItem(FullMergeRequestKey fmk) { ListViewGroup group = Groups[fmk.ProjectKey.ProjectName]; string[] subitems = Enumerable.Repeat(String.Empty, Columns.Count).ToArray(); ListViewItem item = new ListViewItem(subitems, group) { Tag = fmk }; return(item); }
/// <summary> /// Convert a difference between two states into a list of merge request updates splitted in new/updated/closed /// </summary> private IEnumerable <UserEvents.MergeRequestEvent> getMergeRequestUpdates( TwoListDifference <MergeRequestWithProject> diff, IInternalCache oldDetails, IInternalCache newDetails) { List <UserEvents.MergeRequestEvent> updates = new List <UserEvents.MergeRequestEvent>(); foreach (MergeRequestWithProject mergeRequest in diff.SecondOnly) { FullMergeRequestKey fmk = new FullMergeRequestKey(mergeRequest.Project, mergeRequest.MergeRequest); updates.Add(new UserEvents.MergeRequestEvent( fmk, UserEvents.MergeRequestEvent.Type.AddedMergeRequest, null)); } foreach (MergeRequestWithProject mergeRequest in diff.FirstOnly) { FullMergeRequestKey fmk = new FullMergeRequestKey(mergeRequest.Project, mergeRequest.MergeRequest); updates.Add(new UserEvents.MergeRequestEvent( fmk, UserEvents.MergeRequestEvent.Type.RemovedMergeRequest, null)); } foreach (Tuple <MergeRequestWithProject, MergeRequestWithProject> mrPair in diff.Common) { MergeRequest mergeRequest1 = mrPair.Item1.MergeRequest; MergeRequest mergeRequest2 = mrPair.Item2.MergeRequest; Debug.Assert(mergeRequest1.Id == mergeRequest2.Id); MergeRequestKey mergeRequestKey = new MergeRequestKey(mrPair.Item2.Project, mergeRequest2.IId); IEnumerable <Version> oldVersions = oldDetails.GetVersions(mergeRequestKey); IEnumerable <Version> newVersions = newDetails.GetVersions(mergeRequestKey); bool labelsUpdated = !Enumerable.SequenceEqual(mergeRequest1.Labels, mergeRequest2.Labels); bool commitsUpdated = newVersions.Count() > oldVersions.Count(); MergeRequestApprovalConfiguration oldApprovals = oldDetails.GetApprovals(mergeRequestKey); MergeRequestApprovalConfiguration newApprovals = newDetails.GetApprovals(mergeRequestKey); bool detailsUpdated = areMergeRequestsDifferentInDetails(mergeRequest1, mergeRequest2) || areApprovalsDifferent(oldApprovals, newApprovals); if (labelsUpdated || commitsUpdated || detailsUpdated) { FullMergeRequestKey fmk = new FullMergeRequestKey( mergeRequestKey.ProjectKey, mergeRequest2); updates.Add(new UserEvents.MergeRequestEvent( fmk, UserEvents.MergeRequestEvent.Type.UpdatedMergeRequest, new UserEvents.MergeRequestEvent.UpdateScope(commitsUpdated, labelsUpdated, detailsUpdated))); } } return(updates); }
private void onLiveMergeRequestSelectionChanged(FullMergeRequestKey fmk) { Debug.Assert(fmk.MergeRequest != null && fmk.MergeRequest.IId != 0); Trace.TraceInformation(String.Format( "[MainForm.Workflow] User requested to change merge request to IId {0}", fmk.MergeRequest.IId.ToString())); onSingleMergeRequestLoaded(fmk); IMergeRequestCache cache = _liveDataCache.MergeRequestCache; MergeRequestKey mrk = new MergeRequestKey(fmk.ProjectKey, fmk.MergeRequest.IId); GitLabSharp.Entities.Version latestVersion = cache.GetLatestVersion(mrk); onComparableEntitiesLoaded(latestVersion, fmk.MergeRequest, cache.GetCommits(mrk), cache.GetVersions(mrk)); }
/////////////////////////////////////////////////////////////////////////////////////////////////// private void fillListViewSearchMergeRequests(ProjectKey projectKey, IEnumerable <MergeRequest> mergeRequests) { listViewFoundMergeRequests.BeginUpdate(); foreach (MergeRequest mergeRequest in mergeRequests) { FullMergeRequestKey fmk = new FullMergeRequestKey(projectKey, mergeRequest); ListViewItem item = createListViewMergeRequestItem(listViewFoundMergeRequests, fmk); listViewFoundMergeRequests.Items.Add(item); setListViewSubItemsTags(item, fmk); } recalcRowHeightForMergeRequestListView(listViewFoundMergeRequests); listViewFoundMergeRequests.EndUpdate(); }
private bool checkIfMergeRequestCanBeEdited() { string hostname = getHostName(); User currentUser = getCurrentUser(); FullMergeRequestKey item = getListView(EDataCacheType.Live).GetSelectedMergeRequest().Value; if (hostname == String.Empty || currentUser == null || item.MergeRequest == null) { Debug.Assert(false); MessageBox.Show("Cannot modify a merge request", "Internal error", MessageBoxButtons.OK, MessageBoxIcon.Error); Trace.TraceError("Unexpected application state." + "hostname is empty string={0}, currentUser is null={1}, item.MergeRequest is null={2}", hostname == String.Empty, currentUser == null, item.MergeRequest == null); return(false); } return(true); }
async private Task closeMergeRequestAsync(string hostname, FullMergeRequestKey item) { MergeRequestKey mrk = new MergeRequestKey(item.ProjectKey, item.MergeRequest.IId); string message = "Do you really want to close (cancel) merge request? It will not be merged to the target branch."; if (MessageBox.Show(message, "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { GitLabInstance gitLabInstance = new GitLabInstance(hostname, Program.Settings); await MergeRequestEditHelper.CloseMergeRequest(gitLabInstance, _modificationNotifier, mrk); string statusMessage = String.Format("Merge Request !{0} has been closed", mrk.IId); labelWorkflowStatus.Text = statusMessage; Trace.TraceInformation("[MainForm] {0}", statusMessage); requestUpdates(null, new int[] { Constants.NewOrClosedMergeRequestRefreshListTimerInterval }); } else { Trace.TraceInformation("[MainForm] User declined to close a merge request"); } }
async private Task closeMergeRequestAsync(FullMergeRequestKey item) { MergeRequestKey mrk = new MergeRequestKey(item.ProjectKey, item.MergeRequest.IId); string message = "Do you really want to close (cancel) merge request? It will not be merged to the target branch."; if (MessageBox.Show(message, "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { await MergeRequestEditHelper.CloseMergeRequest(mrk, _shortcuts); string statusMessage = String.Format("Merge Request !{0} has been closed", mrk.IId); addOperationRecord(statusMessage); requestUpdates(EDataCacheType.Live, null, new int[] { Program.Settings.NewOrClosedMergeRequestRefreshListDelayMs }); } else { Trace.TraceInformation("[MainForm] User declined to close a merge request"); } }
private void acceptMergeRequest(FullMergeRequestKey item) { DataCache dataCache = getDataCache(EDataCacheType.Live); MergeRequestKey mrk = new MergeRequestKey(item.ProjectKey, item.MergeRequest.IId); bool doesMatchTag(object tag) => tag != null && ((MergeRequestKey)(tag)).Equals(mrk); Form formExisting = WinFormsHelpers.FindFormByTag("AcceptMergeRequestForm", doesMatchTag); if (formExisting != null) { formExisting.Activate(); return; } AcceptMergeRequestForm form = new AcceptMergeRequestForm( mrk, getCommitStorage(mrk.ProjectKey, false)?.Path, () => { addOperationRecord(String.Format("Merge Request !{0} has been merged successfully", mrk.IId)); requestUpdates(EDataCacheType.Live, null, new int[] { Program.Settings.NewOrClosedMergeRequestRefreshListDelayMs }); }, showDiscussionsFormAsync, () => dataCache, async() => { await checkForUpdatesAsync(dataCache, mrk, DataCacheUpdateKind.MergeRequest); return(dataCache); }, () => _shortcuts.GetMergeRequestAccessor(mrk.ProjectKey.ProjectName)) { Tag = mrk }; form.Show(); }
async private Task applyChangesToMergeRequestAsync(DataCache dataCache, string hostname, User currentUser, FullMergeRequestKey item, IEnumerable <User> fullUserList) { MergeRequestKey mrk = new MergeRequestKey(item.ProjectKey, item.MergeRequest.IId); string noteText = await MergeRequestEditHelper.GetLatestSpecialNote(dataCache.DiscussionCache, mrk); MergeRequestPropertiesForm form = new EditMergeRequestPropertiesForm(hostname, _shortcuts.GetProjectAccessor(), currentUser, item.ProjectKey, item.MergeRequest, noteText, fullUserList); if (form.ShowDialog() != DialogResult.OK) { Trace.TraceInformation("[MainForm] User declined to modify a merge request"); return; } ApplyMergeRequestChangesParameters parameters = new ApplyMergeRequestChangesParameters(form.Title, form.AssigneeUsername, form.Description, form.TargetBranch, form.DeleteSourceBranch, form.Squash, form.IsHighPriority); bool modified = await MergeRequestEditHelper.ApplyChangesToMergeRequest( item.ProjectKey, item.MergeRequest, parameters, noteText, form.SpecialNote, currentUser, _shortcuts); string statusMessage = modified ? String.Format("Merge Request !{0} has been modified", mrk.IId) : String.Format("No changes have been made to Merge Request !{0}", mrk.IId); addOperationRecord(statusMessage); if (modified) { requestUpdates(EDataCacheType.Live, mrk, new int[] { Program.Settings.OneShotUpdateFirstChanceDelayMs, Program.Settings.OneShotUpdateSecondChanceDelayMs }); } }
private Color getDiscussionCountColor(FullMergeRequestKey fmk, bool isSelected) { if (isSummaryKey(fmk)) { return(Color.Black); } DiscussionCount dc = _dataCache?.DiscussionCache?.GetDiscussionCount( new MergeRequestKey(fmk.ProjectKey, fmk.MergeRequest.IId)) ?? default(DiscussionCount); if (dc.Status != DiscussionCount.EStatus.Ready || dc.Resolvable == null || dc.Resolved == null) { return(Color.Black); } if (dc.Resolvable.Value == dc.Resolved.Value) { return(isSelected ? Color.SpringGreen : Color.Green); } Debug.Assert(dc.Resolvable.Value > dc.Resolved.Value); return(isSelected ? Color.Orange : Color.Red); }
private void drawEllipseForIId(Graphics g, StringFormat format, Rectangle bounds, FullMergeRequestKey fmk, Font font) { int longestIId = getMatchingFilterMergeRequests() .OrderBy(mrk => mrk.MergeRequest.IId) .LastOrDefault().MergeRequest?.IId ?? 0; SizeF textSize = g.MeasureString(longestIId.ToString(), font, bounds.Width, format); float ellipseWidth = (float)(textSize.Height - 0.30 * textSize.Height); // 30% less float ellipseHeight = ellipseWidth; float ellipsePaddingX = 5; float ellipseOffsetX = textSize.Width; float ellipseX = ellipseOffsetX + ellipsePaddingX; float ellipseY = (textSize.Height - ellipseHeight) / 2; if (bounds.Width > ellipseX + ellipseWidth) { using (Brush ellipseBrush = new SolidBrush(getMergeRequestColor(fmk, Color.Transparent, false))) { RectangleF ellipseRect = new RectangleF( bounds.X + ellipseX, bounds.Y + ellipseY, ellipseWidth, ellipseHeight); g.FillEllipse(ellipseBrush, ellipseRect); } } }
async private Task applyChangesToMergeRequestAsync(string hostname, User currentUser, FullMergeRequestKey item) { MergeRequestKey mrk = new MergeRequestKey(item.ProjectKey, item.MergeRequest.IId); string noteText = await MergeRequestEditHelper.GetLatestSpecialNote(_liveDataCache.DiscussionCache, mrk); MergeRequestPropertiesForm form = new EditMergeRequestPropertiesForm(hostname, getProjectAccessor(), currentUser, item.ProjectKey, item.MergeRequest, noteText); if (form.ShowDialog() != DialogResult.OK) { Trace.TraceInformation("[MainForm] User declined to modify a merge request"); return; } ApplyMergeRequestChangesParameters parameters = new ApplyMergeRequestChangesParameters(form.Title, form.AssigneeUsername, form.Description, form.TargetBranch, form.DeleteSourceBranch, form.Squash); GitLabInstance gitLabInstance = new GitLabInstance(hostname, Program.Settings); bool modified = await MergeRequestEditHelper.ApplyChangesToMergeRequest(gitLabInstance, _modificationNotifier, item.ProjectKey, item.MergeRequest, parameters, noteText, form.SpecialNote, currentUser); string statusMessage = modified ? String.Format("Merge Request !{0} has been modified", mrk.IId) : String.Format("No changes have been made to Merge Request !{0}", mrk.IId); labelWorkflowStatus.Text = statusMessage; Trace.TraceInformation("[MainForm] {0}", statusMessage); if (modified) { requestUpdates(mrk, new int[] { 100, Program.Settings.OneShotUpdateFirstChanceDelayMs, Program.Settings.OneShotUpdateSecondChanceDelayMs }); } }
private void muteMergeRequestFor(FullMergeRequestKey fmk, TimeSpan timeSpan) { MergeRequestKey mrk = new MergeRequestKey(fmk.ProjectKey, fmk.MergeRequest.IId); _mutedMergeRequests[mrk] = DateTime.Now + timeSpan; }
private bool unmuteMergeRequest(FullMergeRequestKey fmk) { MergeRequestKey mrk = new MergeRequestKey(fmk.ProjectKey, fmk.MergeRequest.IId); return(unmuteMergeRequest(mrk)); }
private static bool isSummaryKey(FullMergeRequestKey fmk) { return(fmk.MergeRequest == null); }
internal bool SelectMergeRequest(MergeRequestKey?mrk, bool exact) { if (!mrk.HasValue) { if (Items.Count < 1) { return(false); } Items[0].Selected = true; ensureSelectionIsVisible(); return(true); } if (isGroupCollapsed(mrk.Value.ProjectKey)) { setGroupCollapsing(mrk.Value.ProjectKey, false); } foreach (ListViewItem item in Items) { if (isSummaryItem(item)) { continue; } FullMergeRequestKey key = (FullMergeRequestKey)(item.Tag); if (mrk.Value.ProjectKey.Equals(key.ProjectKey) && mrk.Value.IId == key.MergeRequest.IId) { item.Selected = true; ensureSelectionIsVisible(); return(true); } } if (exact) { return(false); } // selected an item from the proper group foreach (ListViewGroup group in Groups) { if (mrk.Value.ProjectKey.MatchProject(group.Name) && group.Items.Count > 0) { group.Items[0].Selected = true; ensureSelectionIsVisible(); return(true); } } // select whatever foreach (ListViewGroup group in Groups) { if (group.Items.Count > 0) { group.Items[0].Selected = true; ensureSelectionIsVisible(); return(true); } } return(false); }
protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e) { base.OnDrawSubItem(e); if (e.Item.ListView == null) { return; // is being removed } int iidColumnIndex = getColumnByTag("IId").Index; int labelsColumnIndex = getColumnByTag("Labels").Index; int?resolvedCountColumnIndex = getColumnByTag("Resolved")?.Index; int?totalTimeColumnIndex = getColumnByTag("TotalTime")?.Index; int?titleColumnIndex = getColumnByTag("Title")?.Index; int?sourceBranchColumnIndex = getColumnByTag("SourceBranch")?.Index; int?targetBranchColumnIndex = getColumnByTag("TargetBranch")?.Index; int?jiraColumnIndex = getColumnByTag("Jira")?.Index; int?authorColumnIndex = getColumnByTag("Author")?.Index; bool isIIdColumnItem = e.ColumnIndex == iidColumnIndex; bool isLabelsColumnItem = e.ColumnIndex == labelsColumnIndex; bool isResolvedColumnItem = resolvedCountColumnIndex.HasValue && e.ColumnIndex == resolvedCountColumnIndex.Value; bool isTotalTimeColumnItem = totalTimeColumnIndex.HasValue && e.ColumnIndex == totalTimeColumnIndex.Value; bool isTitleColumnItem = titleColumnIndex.HasValue && e.ColumnIndex == titleColumnIndex.Value; bool isSourceBranchColumnItem = sourceBranchColumnIndex.HasValue && e.ColumnIndex == sourceBranchColumnIndex.Value; bool isTargetBranchColumnItem = targetBranchColumnIndex.HasValue && e.ColumnIndex == targetBranchColumnIndex.Value; bool isJiraColumnItem = jiraColumnIndex.HasValue && e.ColumnIndex == jiraColumnIndex.Value; bool isAuthorColumnItem = authorColumnIndex.HasValue && e.ColumnIndex == authorColumnIndex.Value; bool isWrappableColumnItem = isTitleColumnItem || isSourceBranchColumnItem || isTargetBranchColumnItem || isJiraColumnItem || isAuthorColumnItem; bool needWordWrap = isWrappableColumnItem && Program.Settings.WordWrapLongRows; StringFormatFlags formatFlags = needWordWrap ? StringFormatFlags.LineLimit : StringFormatFlags.NoWrap; StringFormat format = new StringFormat { Trimming = StringTrimming.EllipsisCharacter, FormatFlags = formatFlags }; Rectangle bounds = e.Bounds; if (e.ColumnIndex == 0 && e.Item.ListView.Columns[0].DisplayIndex != 0) { bounds = WinFormsHelpers.GetFirstColumnCorrectRectangle(e.Item.ListView, e.Item); } bool isSelected = e.Item.Selected; FullMergeRequestKey fmk = (FullMergeRequestKey)(e.Item.Tag); Color backgroundColor = getMergeRequestColor(fmk, Color.Transparent, true); WinFormsHelpers.FillRectangle(e, bounds, backgroundColor, isSelected); string text = ((ListViewSubItemInfo)(e.SubItem.Tag)).Text; bool isClickable = ((ListViewSubItemInfo)(e.SubItem.Tag)).Clickable; if (isIIdColumnItem) { FontStyle fontStyle = isClickable ? FontStyle.Underline : FontStyle.Regular; using (Font font = new Font(e.Item.ListView.Font, fontStyle)) { e.Graphics.DrawString(text, font, Brushes.Blue, bounds, format); if (isMuted(fmk)) { drawEllipseForIId(e.Graphics, format, bounds, fmk, font); } } } else if (isClickable) { using (Font font = new Font(e.Item.ListView.Font, FontStyle.Underline)) { Brush brush = Brushes.Blue; e.Graphics.DrawString(text, font, brush, bounds, format); } } else if (isSelected && isLabelsColumnItem) { using (Brush brush = new SolidBrush(getMergeRequestColor(fmk, SystemColors.Window, true))) { e.Graphics.DrawString(text, e.Item.ListView.Font, brush, bounds, format); } } else if (isResolvedColumnItem) { using (Brush brush = new SolidBrush(getDiscussionCountColor(fmk, isSelected))) { e.Graphics.DrawString(text, e.Item.ListView.Font, brush, bounds, format); } } else if (isTotalTimeColumnItem) { Brush brush = text == Constants.NotAllowedTimeTrackingText ? Brushes.Gray : Brushes.Black; e.Graphics.DrawString(text, e.Item.ListView.Font, brush, bounds, format); } else { Brush textBrush = isSelected ? SystemBrushes.HighlightText : SystemBrushes.ControlText; e.Graphics.DrawString(text, e.Item.ListView.Font, textBrush, bounds, format); } }
internal void UpdateItems() { IMergeRequestCache mergeRequestCache = _dataCache?.MergeRequestCache; if (mergeRequestCache == null) { return; } IEnumerable <ProjectKey> projectKeys = Groups.Cast <ListViewGroup>().Select(x => (ProjectKey)x.Tag); BeginUpdate(); // Add missing merge requests and update existing ones foreach (ProjectKey projectKey in projectKeys) { if (isGroupCollapsed(projectKey)) { continue; } foreach (FullMergeRequestKey fmk in getAllProjectItems(projectKey)) { ListViewItem item = Items.Cast <ListViewItem>().FirstOrDefault( x => ((FullMergeRequestKey)x.Tag).Equals(fmk)); // item=`null` if not found if (item == null) { item = createListViewMergeRequestItem(fmk); Items.Add(item); } else { item.Tag = fmk; } setListViewSubItemsTags(item, fmk); } } // Delete summary items from groups that are no longer collapsed for (int index = Items.Count - 1; index >= 0; --index) { FullMergeRequestKey fmk = (FullMergeRequestKey)Items[index].Tag; if (!isGroupCollapsed(Items[index].Group) && isSummaryItem(Items[index])) { Items.RemoveAt(index); } } // Remove normal items from collapsed groups for (int index = Items.Count - 1; index >= 0; --index) { if (isGroupCollapsed(Items[index].Group)) { Items.RemoveAt(index); } } // Create summary items foreach (ListViewGroup group in Groups) { if (isGroupCollapsed(group)) { string[] subitems = Enumerable.Repeat(String.Empty, Columns.Count).ToArray(); FullMergeRequestKey fmk = new FullMergeRequestKey(getGroupProjectKey(group), null); ListViewItem item = createListViewMergeRequestItem(fmk); Items.Add(item); setListViewSubItemsTagsForSummary(item); } } // Remove deleted merge requests for (int index = Items.Count - 1; index >= 0; --index) { FullMergeRequestKey fmk = (FullMergeRequestKey)Items[index].Tag; if (!isGroupCollapsed(fmk.ProjectKey) && !getAllProjectItems(fmk.ProjectKey).Any(x => x.MergeRequest.IId == fmk.MergeRequest.IId)) { Items.RemoveAt(index); } } // Hide filtered ones for (int index = Items.Count - 1; index >= 0; --index) { FullMergeRequestKey fmk = (FullMergeRequestKey)Items[index].Tag; bool isCollapsed = isGroupCollapsed(fmk.ProjectKey); bool removeItem = false; if (isCollapsed) { bool isThereAnyMatchingItem = getMatchingFilterProjectItems(fmk.ProjectKey).Any(); removeItem = !isThereAnyMatchingItem; } else { bool doesItemMatchFilter = doesMatchFilter(fmk.MergeRequest); removeItem = !doesItemMatchFilter; } if (removeItem) { Items.RemoveAt(index); } } // update a number of MR which is probably displayed _suppressSelectionChange = true; try { Groups.Cast <ListViewGroup>().ToList().ForEach(group => updateGroupCaption(group)); } finally { _suppressSelectionChange = false; } recalcRowHeightForMergeRequestListView(); EndUpdate(); }