Exemplo n.º 1
0
        private void ExportToDocument <TModel>(string path, IReadOnlyList <ResGroupModel <TModel> > groups, IStatusProgress progress, CancellationToken cancellationToken) where TModel : IRowModel
        {
            if (groups.Count == 0)
            {
                throw new ArgumentException(ErrorsRes.TherIsNotFilesToExport, "groups");
            }

            progress.Report(StatusRes.ExportingToExcel);

            using (ExcelPackage package = new ExcelPackage())
            {
                /* Create the worksheet. */
                var workbook = package.Workbook;

                double totalRows      = groups.Sum(g => g.Tables.Sum(t => t.Rows.Count));
                int    rowIndexReport = 1;

                foreach (var group in groups)
                {
                    var        worksheet    = workbook.Worksheets.Add(group.GroupTitle);
                    ExcelStyle defaultStyle = worksheet.Cells[1, 1].Style;

                    int rowIndex = 1;

                    int columnsCount = groups.SelectMany(g => g.Tables.Select(t => t.Header.Columns.Count)).Max();

                    for (int i = 0; i < columnsCount; i++)
                    {
                        List <string> groupStrings = groups.SelectMany(g =>
                                                                       g.Tables.Select(t =>
                        {
                            string colTitle      = t.Header.Columns[i].Title;
                            int longestRowLength = t.Rows.Select(r => r.DataList[i].DataString).Max(str => str.Length);
                            string longestRow    = t.Rows.Select(r => r.DataList[i].DataString).First(str => str.Length == longestRowLength);

                            return(colTitle.Length > longestRow.Length ? colTitle : longestRow);
                        })
                                                                       )
                                                     .ToList();

                        int    longestStringLength = groupStrings.Max(s => s.Length);
                        string longestString       = groupStrings.Find(str => str.Length == longestStringLength);

                        worksheet.Column(i + 1).Width = (int)GetDefaultFontWidth(defaultStyle, longestString);
                    }

                    //Setting Columns
                    foreach (var resTableModel in group.Tables)
                    {
                        var headerCell = worksheet.Cells[rowIndex++, 1];

                        headerCell.Style.Font.Bold        = true;
                        headerCell.Style.Fill.PatternType = ExcelFillStyle.Solid;
                        headerCell.Style.Fill.BackgroundColor.SetColor(Color.LightGray);

                        headerCell.Value = resTableModel.TableTitle;

                        rowIndex++;

                        for (int columnIndex = 0; columnIndex < resTableModel.Header.Columns.Count; columnIndex++)
                        {
                            var languageHeader = worksheet.Cells[rowIndex, columnIndex + 1];

                            languageHeader.Style.Font.Bold        = true;
                            languageHeader.Style.Fill.PatternType = ExcelFillStyle.Solid;
                            languageHeader.Style.Fill.BackgroundColor.SetColor(Color.LightGray);

                            languageHeader.Value = resTableModel.Header.Columns[columnIndex].Title;
                        }

                        rowIndex++;

                        foreach (var tableRow in resTableModel.Rows)
                        {
                            for (int columnIndex = 0; columnIndex < tableRow.DataList.Count; columnIndex++)
                            {
                                var cell = tableRow.DataList[columnIndex];

                                var valueCell = worksheet.Cells[rowIndex, columnIndex + 1];
                                valueCell.Value = cell.DataString;

                                if (cell.Hilight)
                                {
                                    valueCell.Style.Font.Color.SetColor(Color.Red);
                                }
                            }

                            rowIndex++;

                            rowIndexReport++;
                        }

                        progress.Report(100 * rowIndexReport / totalRows);
                        cancellationToken.ThrowIfCancellationRequested();

                        rowIndex++;
                    }
                }

                package.SaveAs(new FileInfo(path));
            }
        }
Exemplo n.º 2
0
 public Task ExportToDocumentAsync <TModel>(string path, IReadOnlyList <ResGroupModel <TModel> > groups, IStatusProgress progress, CancellationToken cancellationToken) where TModel : IRowModel
 {
     return(Task.Run(() => ExportToDocument(path, groups, progress, cancellationToken), cancellationToken));
 }
Exemplo n.º 3
0
 public Task <IReadOnlyList <ResGroupModel <TModel> > > ImportFromDocumentAsync <TModel>(string path, IStatusProgress progress, CancellationToken cancellationToken) where TModel : IRowModel, new()
 {
     return(Task.Run(() => ImportFromDocument <TModel>(path), cancellationToken));
 }
Exemplo n.º 4
0
 private Task <SolutionResources> GetSolutionResourcesAsync(IEnumerable <string> selectedCultures, IReadOnlyCollection <Project> projects, IStatusProgress progress, CancellationToken cancellationToken)
 {
     return(Task.Run(() => GetSolutionResources(selectedCultures, projects, progress, cancellationToken), cancellationToken));
 }
Exemplo n.º 5
0
        private SolutionResources GetSolutionResources(IEnumerable <string> selectedCultures, IReadOnlyCollection <Project> projects, IStatusProgress progress, CancellationToken cancellationToken)
        {
            Func <ResourceData, bool> resourceFilesFilter;

            if (selectedCultures == null)
            {
                resourceFilesFilter = r => true;
            }
            else
            {
                var selectedCulturesHashSet = new HashSet <string>(selectedCultures);

                resourceFilesFilter = r => selectedCulturesHashSet.Contains(r.Culture.Name);
            }

            var progresses              = progress.CreateParallelProgresses(0.7, 0.3);
            var dteProjectsProgress     = progresses[0];
            var resourceContentProgress = progresses[1];

            double projectsCount = projects.Count;

            var projectResourceItems = new SolutionResources
            {
                ProjectResources = projects.Select((project, index) =>
                {
                    string projectDirectory  = Path.GetDirectoryName(project.FullName);
                    var resourceProjectItems = project.GetAllItems().Where(projItem => Path.GetExtension(projItem.FileNames[0]) == ".resx").ToList();

                    dteProjectsProgress.Report(100 * (index + 1) / projectsCount);
                    cancellationToken.ThrowIfCancellationRequested();

                    return(new ProjectResources
                    {
                        ProjectName = project.Name,
                        ProjectDirectory = projectDirectory,
                        ProjectId = project.UniqueName,
                        ResourceProjectItems = resourceProjectItems
                    });
                })
                                   .ToList()
            };

            double resourceFilesCount = projectResourceItems.ProjectResources.Sum(pr => pr.ResourceProjectItems.Count);
            int    resourceIndex      = 0;

            foreach (var projectResourceItem in projectResourceItems.ProjectResources)
            {
                int projectDirectoryPathLength = projectResourceItem.ProjectDirectory.Length;

                projectResourceItem.Resources = projectResourceItem.ResourceProjectItems
                                                .Select(projItem =>
                {
                    string fileName = projItem.FileNames[0];

                    //Removing .resx extension.
                    string resName = Path.GetFileNameWithoutExtension(fileName);

                    string cultureName = Path.GetExtension(resName);
                    if (NonCultureExtensions.Contains(cultureName))
                    {
                        cultureName = string.Empty;
                    }
                    else
                    {
                        //Removing culture extension.
                        resName = Path.GetFileNameWithoutExtension(resName);
                    }

                    string directoryName = (Path.GetDirectoryName(fileName) ?? string.Empty).Substring(projectDirectoryPathLength);
                    //Relative path to the resource.
                    resName = Path.Combine(directoryName, resName);

                    resourceContentProgress.Report(100 * (++resourceIndex) / resourceFilesCount);
                    cancellationToken.ThrowIfCancellationRequested();

                    return(new ResourceData
                           (
                               resourceName: resName,
                               resourcePath: fileName,
                               culture: String.IsNullOrEmpty(cultureName) ? CultureInfo.InvariantCulture : CultureInfo.GetCultureInfo(cultureName.Substring(1)),
                               projectItem: projItem,
                               resources: GetResourceContent(fileName)
                           ));
                })
                                                .Where(resourceFilesFilter)
                                                .GroupBy(res => res.ResourceName)
                                                .ToDictionary(resGroup => resGroup.Key, resGroup => resGroup.ToDictionary(res => res.Culture.Name, res => res));
            }



            return(projectResourceItems);
        }
Exemplo n.º 6
0
 public Task UpdateResourcesAsync(IReadOnlyCollection <string> selectedCultures, IReadOnlyCollection <Project> selectedProjects, IStatusProgress progress, CancellationToken cancellationToken, UpdateResourcesOptions options)
 {
     return(Task.Run(() => UpdateResources(selectedCultures, selectedProjects, progress, cancellationToken, options), cancellationToken));
 }
Exemplo n.º 7
0
        public async Task ExportToDocumentAsync(IDocumentGenerator documentGenerator, string path, IReadOnlyCollection <string> selectedCultures, IReadOnlyCollection <Project> selectedProjects, IStatusProgress progress, CancellationToken cancellationToken)
        {
            progress.Report(StatusRes.GettingProjectsResources);
            SolutionResources solutionResources = await GetSolutionResourcesAsync(selectedCultures, selectedProjects, progress, cancellationToken);

            progress.Report(StatusRes.PreparingResourcesToExport);

            var cultures = selectedCultures.Select(CultureInfo.GetCultureInfo)
                           .ToDictionary(
                cult => cult.Name,
                cult => cult.Name == InvariantCultureId ? InvariantCultureDisplayName : cult.Name.ToUpper()
                );

            var culturesOrder = new List <string>(cultures.Count)
            {
                InvariantCultureId
            };

            culturesOrder.AddRange(cultures.Where(cult => cult.Key != InvariantCultureId).OrderBy(cult => cult.Value).Select(cult => cult.Key));

            var header = new HeaderModel
            {
                Columns = new List <ColumnModel>(1)
                {
                    new ColumnModel {
                        Title = ExcelRes.ResourceKey
                    }
                }
                .Concat(culturesOrder.Select(cultureId => cultures[cultureId]).Select(headerName => new ColumnModel {
                    Title = headerName
                }))
                .Concat(new List <ColumnModel>(1)
                {
                    new ColumnModel {
                        Title = ExcelRes.Comment
                    }
                })
                .ToList()
            };

            IReadOnlyList <ResGroupModel <ResExcelModel> > groups = solutionResources
                                                                    .ProjectResources.Select(proj => new ResGroupModel <ResExcelModel>
            {
                GroupTitle = proj.ProjectName,
                Tables     = proj.Resources.Select(res =>
                {
                    var neutralResources    = res.Value[InvariantCultureId].StringResources;
                    List <string> keysOrder = neutralResources.Keys.OrderBy(key => key).ToList();

                    List <RowModel <ResExcelModel> > rows = keysOrder.Select(
                        resKey => new RowModel <ResExcelModel>
                    {
                        Model = new ResExcelModel(resKey,
                                                  culturesOrder.Select(cultureId => res.Value[cultureId]).Select(resData => resData.StringResources[resKey].Value).ToList(),
                                                  res.Value[InvariantCultureId].StringResources[resKey].Comment)
                    })
                                                            .Where(r => r.Model.ResourceValues.Count != 0)
                                                            .ToList();

                    var tableModel = new ResTableModel <ResExcelModel>
                    {
                        TableTitle = res.Key,
                        Header     = header,
                        Rows       = rows
                    };

                    cancellationToken.ThrowIfCancellationRequested();

                    return(tableModel);
                })
                             .Where(table => table.Rows.Count != 0)
                             .ToList()
            })
                                                                    .Where(res => res.Tables.Count != 0)
                                                                    .ToList();

            await documentGenerator.ExportToDocumentAsync(path, groups, progress, cancellationToken);
        }
Exemplo n.º 8
0
        public void UpdateResources(IReadOnlyCollection <string> selectedCultures, IReadOnlyCollection <Project> selectedProjects, IStatusProgress progress, CancellationToken cancellationToken, UpdateResourcesOptions options)
        {
            IReadOnlyDictionary <string, CultureInfo> selectedCultureInfos = selectedCultures.Select(CultureInfo.GetCultureInfo)
                                                                             .ToDictionary(cult => cult.Name, cult => cult);

            IReadOnlyDictionary <string, Project> projectsDictionary = selectedProjects.ToDictionary(proj => proj.UniqueName, proj => proj);

            progress.Report(StatusRes.GettingProjectsResources);
            SolutionResources solutionResources = GetSolutionResources(null, selectedProjects, progress, cancellationToken);

            progress.Report(StatusRes.GeneratingResx);
            cancellationToken.ThrowIfCancellationRequested();

            int resourceFilesProcessed = 0;
            int resourceFilesCount     = solutionResources.ProjectResources.Sum(pr => pr.Resources.Count);

            foreach (var projectResources in solutionResources.ProjectResources)
            {
                var project = projectsDictionary[projectResources.ProjectId];

                foreach (Dictionary <string, ResourceData> resourceFileGroup in projectResources.Resources.Values)
                {
                    //Removing culture files without neutral culture file. TODO: find if it is required.
                    ResourceData neutralCulture;
                    if (!resourceFileGroup.TryGetValue(InvariantCultureId, out neutralCulture))
                    {
                        _logger.Log(String.Format(LoggerRes.MissingNeutralCulture, resourceFileGroup.Values.First().ResourcePath, String.Join("\r\n", resourceFileGroup.Values.Select(r => r.ResourcePath))));

                        foreach (var projectItem in resourceFileGroup.Values)
                        {
                            _logger.Log(String.Format(LoggerRes.RemovedFormat, projectItem.ProjectItem.FileNames[0]));

                            projectItem.ProjectItem.Delete();
                        }

                        resourceFileGroup.Clear();
                        project.Save();
                        continue;
                    }

                    var items2Remove = resourceFileGroup.Where(f => !selectedCultureInfos.ContainsKey(f.Key)).ToList();

                    List <KeyValuePair <string, ProjectItem> > projectItems2Remove;
                    if (items2Remove.Count == 0)
                    {
                        projectItems2Remove = new List <KeyValuePair <string, ProjectItem> >(0);
                    }
                    else
                    {
                        projectItems2Remove = items2Remove.Select(d => new KeyValuePair <string, ProjectItem>(d.Key, d.Value.ProjectItem)).ToList();
                    }

                    var cultures2Add = selectedCultureInfos.Where(cult => !resourceFileGroup.ContainsKey(cult.Key)).Select(cult => cult.Value).ToList();

                    if (options.RemoveNotSelectedCultures)
                    {
                        foreach (var projectItem in projectItems2Remove)
                        {
                            _logger.Log(String.Format(LoggerRes.RemovedFormat, projectItem.Value.FileNames[0]));

                            projectItem.Value.Delete();
                            resourceFileGroup.Remove(projectItem.Key);
                        }
                    }

                    foreach (var cultureInfo in cultures2Add)
                    {
                        string resourcePath = Path.Combine(Path.GetDirectoryName(neutralCulture.ResourcePath), Path.GetFileName(neutralCulture.ResourceName) + "." + cultureInfo.Name.ToUpper() + ".resx");

                        using (File.Create(resourcePath)) { }

                        ProjectItem projectItem = project.ProjectItems.AddFromFile(resourcePath);

                        var newFile = new ResourceData
                                      (
                            resourceName: neutralCulture.ResourceName,
                            resourcePath: resourcePath,
                            culture: cultureInfo,
                            projectItem: projectItem,
                            resources: new Dictionary <string, ResXDataNode>(0)
                                      );

                        resourceFileGroup.Add(cultureInfo.Name, newFile);

                        _logger.Log(String.Format(LoggerRes.AddedNewResource, newFile.ResourcePath));
                    }

                    List <ResourceData> otherCultureResources = resourceFileGroup.Where(resData => resData.Key != InvariantCultureId).Select(resData => resData.Value).ToList();

                    if (options.EmbeedSubCultures.HasValue)
                    {
                        if (options.EmbeedSubCultures.Value)
                        {
                            EmbeedResources(neutralCulture.ProjectItem, otherCultureResources);
                        }
                    }

                    if (options.UseDefaultCustomTool.HasValue)
                    {
                        Property customToolProperty = neutralCulture.ProjectItem.Properties.Cast <Property>().First(p => p.Name == "CustomTool");

                        customToolProperty.Value = options.UseDefaultCustomTool.Value ? "PublicResXFileCodeGenerator" : "";
                    }

                    if (options.UseDefaultContentType.HasValue)
                    {
                        foreach (var resProjectItem in resourceFileGroup.Values.Select(g => g.ProjectItem))
                        {
                            Property itemTypeProperty = resProjectItem.Properties.Cast <Property>().First(p => p.Name == "ItemType");

                            itemTypeProperty.Value = options.UseDefaultContentType.Value ? "EmbeddedResource" : "None";
                        }
                    }

                    UpdateResourceFiles(neutralCulture, otherCultureResources);

                    project.Save();

                    progress.Report((int)Math.Round((double)100 * (++resourceFilesProcessed) / resourceFilesCount));
                    cancellationToken.ThrowIfCancellationRequested();
                }
            }
        }
Exemplo n.º 9
0
        private async Task ImportFromDocument(IDocumentGenerator documentGenerator, string path, IReadOnlyCollection <string> selectedCultures, IReadOnlyCollection <Project> selectedProjects, IStatusProgress progress, CancellationToken cancellationToken)
        {
            IReadOnlyList <ResGroupModel <ResExcelModel> > data = await documentGenerator.ImportFromDocumentAsync <ResExcelModel>(path, progress, cancellationToken);

            progress.Report(StatusRes.GettingProjectsResources);
            SolutionResources resources = await GetSolutionResourcesAsync(selectedCultures, selectedProjects, progress, cancellationToken);

            progress.Report(StatusRes.MergingResources);

            var projectsJoin = resources.ProjectResources
                               .Join(data, projRes => projRes.ProjectName, excelProjRes => excelProjRes.GroupTitle, (projRes, excelProjRes) => new { ProjRes = projRes, ExcelProjRes = excelProjRes });

            foreach (var project in projectsJoin)
            {
                var resourceTablesJoin = project.ProjRes.Resources
                                         .Join(project.ExcelProjRes.Tables, resTable => resTable.Key, excelResTable => excelResTable.TableTitle, (resTable, excelResTable) => new { ResTable = resTable, ExcelResTable = excelResTable });

                foreach (var resource in resourceTablesJoin)
                {
                    int columnsCount  = resource.ExcelResTable.Header.Columns.Count;
                    int culturesCount = columnsCount - 2;

                    List <string> cultureIds = resource.ExcelResTable.Header.Columns
                                               .Skip(1)
                                               .Select(col => col.Title == InvariantCultureDisplayName ? InvariantCultureId : CultureInfo.GetCultureInfo(col.Title).Name)
                                               .Take(culturesCount)
                                               .ToList();
                    List <string> resourceKeys = resource.ExcelResTable.Rows.Select(row => row.DataList[0].DataString).ToList();
                    List <string> comments     = resource.ExcelResTable.Rows.Select(row => row.DataList[columnsCount - 1].DataString).ToList();

                    Dictionary <string, IReadOnlyCollection <ResourceEntryData> > excelResources = cultureIds
                                                                                                   .Select((cultureId, index) => new KeyValuePair <string, IReadOnlyCollection <ResourceEntryData> >
                                                                                                           (
                                                                                                               cultureId,
                                                                                                               resourceKeys.Zip(
                                                                                                                   resource.ExcelResTable.Rows.Select(row => row.DataList[index + 1].DataString),
                                                                                                                   (key, value) => new { Key = key, Value = value })
                                                                                                               .Zip(comments, (kvp, comment) => new ResourceEntryData(kvp.Key, kvp.Value, comment))
                                                                                                               .ToList()
                                                                                                           ))
                                                                                                   .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

                    var resourceFileTablesJoin = resource.ResTable.Value
                                                 .Join(excelResources, resData => resData.Key, excelResData => excelResData.Key, (resData, excelResData) => new { ResData = resData.Value, ExcelResData = excelResData.Value });

                    foreach (var resFileTablesJoin in resourceFileTablesJoin)
                    {
                        try
                        {
                            UpdateResourceFile(resFileTablesJoin.ResData, resFileTablesJoin.ExcelResData);
                        }
                        catch (MissingManifestResourceException ex)
                        {
                            throw new MissingManifestResourceException(String.Format(ErrorsRes.MissingResourcesFormat,
                                                                                     project.ProjRes.ProjectId, resFileTablesJoin.ResData.ResourceName, resFileTablesJoin.ResData.Culture.DisplayName), ex);
                        }
                    }
                }
            }
        }
Exemplo n.º 10
0
 public Task ImportFromDocumentAsync(IDocumentGenerator documentGenerator, string path, IReadOnlyCollection <string> selectedCultures, IReadOnlyCollection <Project> selectedProjects, IStatusProgress progress, CancellationToken cancellationToken)
 {
     return(Task.Run(() => ImportFromDocument(documentGenerator, path, selectedCultures, selectedProjects, progress, cancellationToken), cancellationToken));
 }
Exemplo n.º 11
0
        public async Task <IReadOnlyList <ResGroupModel <TModel> > > ImportFromDocumentAsync <TModel>(string path, IStatusProgress progress, CancellationToken cancellationToken) where TModel : IRowModel, new()
        {
            progress.Report(StatusRes.GettingSpreadsheet);
            SpreadsheetFeed spreadSheets = await Service.GetFeedAsync(new SpreadsheetQuery(path), progress, cancellationToken);

            SpreadsheetEntry spreadsheet = (SpreadsheetEntry)spreadSheets.Entries.First();

            progress.Report(StatusRes.GettingWorksheets);
            WorksheetFeed worksheetsFeed = await Service.GetFeedAsync(spreadsheet.GetWorkSheetQuery(), progress, cancellationToken);

            List <WorksheetEntry> worksheets = worksheetsFeed.Entries.Cast <WorksheetEntry>().ToList();

            var progresses = progress.CreateParallelProgresses(worksheets.Select(ws => (double)ws.Cols * ws.Rows).ToList());

            progress.Report(StatusRes.GettingWorksheetsData);

            SemaphoreSlim semaphore  = new SemaphoreSlim(MaxPushRequestsCount);
            var           groupTasks = worksheets.Zip(progresses, (entry, p) => GetGroupAsync <TModel>(entry, semaphore, p, cancellationToken));

            return((await Task.WhenAll(groupTasks)).ToList());
        }
Exemplo n.º 12
0
        public async Task ExportToDocumentAsync <TModel>(string path, IReadOnlyList <ResGroupModel <TModel> > groups, IStatusProgress progress, CancellationToken cancellationToken) where TModel : IRowModel
        {
            progress.Report(StatusRes.GettingSpreadsheet);
            SpreadsheetFeed spreadSheets = await Service.GetFeedAsync(new SpreadsheetQuery(path), progress, cancellationToken);

            SpreadsheetEntry spreadsheet = (SpreadsheetEntry)spreadSheets.Entries.First();

            progress.Report(StatusRes.GettingWorksheets);
            WorksheetFeed worksheetsFeed = await Service.GetFeedAsync(spreadsheet.GetWorkSheetQuery(), progress, cancellationToken);

            int columsCount = groups.First().Tables.First().Rows.First().DataList.Count;
            List <KeyValuePair <string, WorksheetEntry> > newWorksheets = groups
                                                                          .Select(g => new KeyValuePair <string, WorksheetEntry>(g.GroupTitle, new WorksheetEntry((uint)(g.Tables.Sum(t => t.Rows.Count + 3) + /*Table name rows*/ g.Tables.Count - 1), (uint)columsCount, g.GroupTitle)))
                                                                          .ToList();

            List <WorksheetEntry> worksheets2Rename = worksheetsFeed.Entries.Cast <WorksheetEntry>()
                                                      .Where(ws => newWorksheets.Any(nws => String.Equals(nws.Key, ws.Title.Text, StringComparison.OrdinalIgnoreCase)))
                                                      .ToList();

            if (worksheets2Rename.Count != 0)
            {
                foreach (var worksheetEntry in worksheets2Rename)
                {
                    worksheetEntry.Title.Text = Guid.NewGuid().ToString("N");
                    worksheetEntry.BatchData  = new GDataBatchEntryData(GDataBatchOperationType.update);
                }

                progress.Report(StatusRes.RenamingOldWorksheets);
                var progresses = progress.CreateParallelProgresses(worksheets2Rename.Count);
                //Renaming worksheets with matching names.
                await Task.WhenAll(worksheets2Rename.Zip(progresses, (ws, p) => Service.UpdateItemAsync(ws, p, cancellationToken)));
            }

            progress.Report(StatusRes.InsertingNewWorksheets);
            //Creating new worksheets.
            var insertingProgresses = progress.CreateParallelProgresses(newWorksheets.Count);
            var createdWorksheets   = await Task.WhenAll(newWorksheets.Zip(insertingProgresses, (kvp, p) => Service.InsertItemAsync(spreadsheet.GetWorkSheetLink(), kvp.Value, p, cancellationToken)));

            newWorksheets = createdWorksheets.Select(ws => new KeyValuePair <string, WorksheetEntry>(ws.Title.Text, ws)).ToList();

            progress.Report(StatusRes.DeletingOldWorksheets);
            //Clearing of previous worksheets.
            var deletingProgresses = progress.CreateParallelProgresses(worksheetsFeed.Entries.Count);
            await Task.WhenAll(worksheetsFeed.Entries.Cast <WorksheetEntry>().Zip(deletingProgresses, (ws, p) => Service.DeleteItemAsync(ws, p, cancellationToken)).ToArray());

            progress.Report(StatusRes.PushingCells);
            var groupWorksheetsJoin = newWorksheets.Join(groups, ws => ws.Key, g => g.GroupTitle, (kvp, group) => new { Group = group, Worksheet = kvp.Value }).ToList();
            var groupProgresses     = progress.CreateParallelProgresses(groupWorksheetsJoin.Select(j => (double)j.Worksheet.Cols * j.Worksheet.Rows).ToList());

            SemaphoreSlim semaphore = new SemaphoreSlim(MaxPushRequestsCount);
            await Task.WhenAll(groupWorksheetsJoin.Zip(groupProgresses, (j, p) => PushCellsAsync(j.Worksheet, j.Group, semaphore, p, cancellationToken)));
        }