示例#1
0
        /// <summary>
        /// Gets all books that need to be deleted.
        /// </summary>
        private IEnumerable <int> GetBooksToDelete(TextType textType, IEnumerable <int> existingBooks)
        {
            string projectPath   = GetProjectPath(textType);
            var    booksToDelete = new HashSet <int>(_fileSystemService.DirectoryExists(projectPath)
                ? _fileSystemService.EnumerateFiles(projectPath)
                                                     .Select(p => Canon.BookIdToNumber(Path.GetFileNameWithoutExtension(p)))
                : Enumerable.Empty <int>());

            booksToDelete.ExceptWith(existingBooks);
            return(booksToDelete);
        }
示例#2
0
        public void ParseChapterVerseLine()
        {
            versification.ParseChapterVerseLine("HAB 1:17 2:20 3:19");

            int          bookId   = Canon.BookIdToNumber("HAB");
            List <int[]> bookList = versification.bookList();

            Assert.AreEqual(bookList.Count, bookId);
            Assert.AreEqual(bookList[bookId - 1], new [] { 17, 20, 19 });

            Assert.AreEqual(bookId, versification.GetLastBook(),
                            "HAB should be the last book in the versification");
            Assert.AreEqual(3, versification.GetLastChapter(bookId), "HAB has three chapters");
            Assert.AreEqual(17, versification.GetLastVerse(bookId, 1), "HAB 1 has 17 verses");
            Assert.AreEqual(20, versification.GetLastVerse(bookId, 2), "HAB 2 has 20 verses");
            Assert.AreEqual(19, versification.GetLastVerse(bookId, 3), "HAB 3 has 19 verses");
        }
示例#3
0
        public void ProcessVersLine_Custom_ChapterRemoved()
        {
            versification.ProcessVersLine("HAB 1:17 2:20 3:19");

            // Add a custom line that updates the original chapter-verse versification for Habakkuk
            versification.ProcessVersLine("HAB 2:0");

            // Confirm that the custom versification overrides the original
            int          bookId   = Canon.BookIdToNumber("HAB");
            List <int[]> bookList = versification.bookList();

            Assert.AreEqual(bookList.Count, bookId);
            Assert.AreEqual(bookList[bookId - 1], new int[] { 17, 0, 19 });

            Assert.AreEqual(3, versification.GetLastChapter(bookId),
                            "The customized version of HAB should still have three chapters");
            Assert.AreEqual(17, versification.GetLastVerse(bookId, 1));
            Assert.AreEqual(0, versification.GetLastVerse(bookId, 2));
            Assert.AreEqual(19, versification.GetLastVerse(bookId, 3));
        }
示例#4
0
        public void ProcessVersLine_Custom_SingleChapter()
        {
            versification.ProcessVersLine("HAB 1:17 2:20 3:19");

            // Add a custom line that updates a single chapter in Habakkuk
            versification.ProcessVersLine("HAB 2:55");

            // Confirm that the custom versification overrides the original
            int          bookId   = Canon.BookIdToNumber("HAB");
            List <int[]> bookList = versification.bookList();

            Assert.AreEqual(bookList.Count, bookId);
            Assert.AreEqual(bookList[bookId - 1], new int[] { 17, 55, 19 });

            Assert.AreEqual(3, versification.GetLastChapter(bookId),
                            "The customized version of HAB should have three chapters");
            Assert.AreEqual(17, versification.GetLastVerse(bookId, 1), "Custom HAB 1 has 17 verses");
            Assert.AreEqual(55, versification.GetLastVerse(bookId, 2), "Custom HAB 2 has 55 verses");
            Assert.AreEqual(19, versification.GetLastVerse(bookId, 3), "Custom HAB 3 has 19 verses");
        }
示例#5
0
        public void ProcessVersLine_Custom_ChapterVerseUpdated()
        {
            versification.ProcessVersLine("HAB 1:17 2:20 3:19");

            // Add a custom line that updates the original chapter-verse versification for Habakkuk
            versification.ProcessVersLine("HAB 1:15 2:13 3:22 4:21");

            // Confirm that the custom versification overrides the original
            int          bookId   = Canon.BookIdToNumber("HAB");
            List <int[]> bookList = versification.bookList();

            Assert.AreEqual(bookList.Count, bookId);
            Assert.AreEqual(bookList[bookId - 1], new int[] { 15, 13, 22, 21 });

            Assert.AreEqual(4, versification.GetLastChapter(bookId),
                            "The customized version of HAB should have four chapters");
            Assert.AreEqual(15, versification.GetLastVerse(bookId, 1), "Custom HAB 1 has 15 verses");
            Assert.AreEqual(13, versification.GetLastVerse(bookId, 2), "Custom HAB 2 has 13 verses");
            Assert.AreEqual(22, versification.GetLastVerse(bookId, 3), "Custom HAB 3 has 22 verses");
            Assert.AreEqual(21, versification.GetLastVerse(bookId, 4), "Custom HAB 4 has 21 verses");
        }
示例#6
0
        public void RemoveAllUnknownVersifications()
        {
            Assert.IsFalse(Versification.Table.Implementation.Exists("ModifiedRuth"));

            using (TextReader reader = new StringReader("RUT 5:91"))
                Versification.Table.Implementation.Load(reader, "", ScrVers.English, "ModifiedRuth");

            Assert.IsTrue(Versification.Table.Implementation.Exists("ModifiedRuth"));

            ScrVers modRuth = new ScrVers("ModifiedRuth");

            Assert.AreEqual(5, modRuth.GetLastChapter(Canon.BookIdToNumber("RUT")));
            Assert.AreEqual(91, modRuth.GetLastVerse(Canon.BookIdToNumber("RUT"), 5));

            Versification.Table.Implementation.RemoveAllUnknownVersifications();

            Assert.IsFalse(Versification.Table.Implementation.Exists("ModifiedRuth"));

            modRuth = new ScrVers("ModifiedRuth");
            Assert.AreEqual(4, modRuth.GetLastChapter(Canon.BookIdToNumber("RUT")));
            Assert.AreEqual(22, modRuth.GetLastVerse(Canon.BookIdToNumber("RUT"), 4));
        }
示例#7
0
        public void ProcessVersLine_Custom_ChapterNotInOriginal()
        {
            versification.ProcessVersLine("HAB 1:17 2:20 3:19");

            // Add a custom line that updates the original chapter-verse versification for Habakkuk
            versification.ProcessVersLine("HAB 7:55");

            // Confirm that the custom versification overrides the original
            int          bookId   = Canon.BookIdToNumber("HAB");
            List <int[]> bookList = versification.bookList();

            Assert.AreEqual(bookList.Count, bookId);
            Assert.AreEqual(bookList[bookId - 1], new int[] { 17, 20, 19, 1, 1, 1, 55 });

            Assert.AreEqual(7, versification.GetLastChapter(bookId));
            Assert.AreEqual(17, versification.GetLastVerse(bookId, 1));
            Assert.AreEqual(20, versification.GetLastVerse(bookId, 2));
            Assert.AreEqual(19, versification.GetLastVerse(bookId, 3));
            Assert.AreEqual(1, versification.GetLastVerse(bookId, 4));
            Assert.AreEqual(1, versification.GetLastVerse(bookId, 5));
            Assert.AreEqual(1, versification.GetLastVerse(bookId, 6));
            Assert.AreEqual(55, versification.GetLastVerse(bookId, 7));
        }
示例#8
0
        static void Main(string[] args)
        {
            if (args.Length < 2 || args.Length > 3)
            {
                BadArguments();
            }

            if (args.Length == 3 && args[0] != "-usfm2")
            {
                BadArguments();
            }

            int bookArg = args.Length == 2 ? 0 : 1;
            int bookNum = Canon.BookIdToNumber(args[bookArg]);

            if (bookNum <= 0)
            {
                BadArguments();
            }

            string textFile = args[bookArg + 1];

            if (!File.Exists(textFile))
            {
                BadArguments();
            }

            // allow USFM 3 markers to be used if not turned off
            MarkerCheck check = new MarkerCheck(args.Length == 2);

            if (check.Run(bookNum, File.ReadAllText(textFile)))
            {
                Console.WriteLine("MarkerCheck: file had errors");
                Environment.Exit(1);
            }
        }
示例#9
0
        /// <summary>
        /// Processes a single token
        /// </summary>
        /// <returns>false if there were no more tokens process</returns>
        public bool ProcessToken()
        {
            // If past end
            if (index >= tokens.Count - 1)
            {
                return(false);
            }

            // Move to next token
            index++;

            // Update verse offset with previous token (since verse offset is from start of current token)
            if (index > 0)
            {
                State.VerseOffset += tokens[index - 1].GetLength(false, !tokensPreserveWhitespace);
            }

            // Skip over tokens that are to be skipped, ensuring that
            // SpecialToken state is true.
            if (skip > 0)
            {
                skip--;
                State.SpecialToken = true;
                return(true);
            }

            // Reset special token and figure status
            State.SpecialToken = false;

            UsfmToken token = tokens[index];

            // Switch unknown types to either character or paragraph
            UsfmTokenType tokenType = token.Type;

            if (tokenType == UsfmTokenType.Unknown)
            {
                tokenType = DetermineUnknownTokenType();
            }

            if (sink != null && !string.IsNullOrEmpty(token.Marker))
            {
                sink.GotMarker(State, token.Marker);
            }

            // Close open elements
            switch (tokenType)
            {
            case UsfmTokenType.Book:
            case UsfmTokenType.Chapter:
                CloseAll();
                break;

            case UsfmTokenType.Paragraph:
                // Handle special case of table rows
                if (token.Marker == "tr")
                {
                    // Close all but table and sidebar
                    while (State.Stack.Count > 0 &&
                           Peek().Type != UsfmElementTypes.Table &&
                           Peek().Type != UsfmElementTypes.Sidebar)
                    {
                        CloseElement();
                    }
                    break;
                }

                // Handle special case of sidebars
                if (token.Marker == "esb")
                {
                    // Close all
                    CloseAll();
                    break;
                }

                // Close all but sidebar
                while (State.Stack.Count > 0 && Peek().Type != UsfmElementTypes.Sidebar)
                {
                    CloseElement();
                }
                break;

            case UsfmTokenType.Character:
                // Handle special case of table cell
                if (IsCell(token))
                {
                    // Close until row
                    while (Peek().Type != UsfmElementTypes.Row)
                    {
                        CloseElement();
                    }
                    break;
                }

                // Handle refs
                if (IsRef(token))
                {
                    // Refs don't close anything
                    break;
                }

                // If non-nested character style, close all character styles
                if (!token.Marker.StartsWith("+"))
                {
                    CloseCharStyles();
                }
                break;

            case UsfmTokenType.Verse:
                CloseNote();
                break;

            case UsfmTokenType.Note:
                CloseNote();
                break;

            case UsfmTokenType.End:
                // If end marker for an active note
                if (State.Stack.Exists(e => e.Type == UsfmElementTypes.Note && (e.Marker + "*" == token.Marker)))
                {
                    CloseNote();
                    break;
                }

                // If end marker for a character style on stack, close it
                // If no matching end marker, close all character styles on top of stack
                UsfmParserElement elem;
                bool unmatched = true;
                while (State.Stack.Count > 0)
                {
                    elem = Peek();
                    if (elem.Type != UsfmElementTypes.Char)
                    {
                        break;
                    }
                    CloseElement();

                    // Determine if a + prefix is needed to close it (was nested char style)
                    bool plusPrefix = (State.Stack.Count > 0 && Peek().Type == UsfmElementTypes.Char);

                    // If is a match
                    if ((plusPrefix ? "+" : "") + elem.Marker + "*" == token.Marker)
                    {
                        unmatched = false;
                        break;
                    }
                }

                // Unmatched end marker
                if (unmatched)
                {
                    if (sink != null)
                    {
                        sink.Unmatched(State, token.Marker);
                    }
                }
                break;
            }

            // Handle tokens
            switch (tokenType)
            {
            case UsfmTokenType.Book:
                State.Stack.Add(new UsfmParserElement(UsfmElementTypes.Book, token.Marker));

                // Code is always upper case
                string code = token.Data[0].ToUpperInvariant();

                // Update verse ref. Leave book alone if not empty to prevent parsing errors
                // on books with bad id lines.
                if (State.VerseRef.Book == "" && Canon.BookIdToNumber(code) != 0)
                {
                    State.VerseRef.Book = code;
                }
                State.VerseRef.ChapterNum = 1;
                State.VerseRef.VerseNum   = 0;
                State.VerseOffset         = 0;

                // Book start.
                if (sink != null)
                {
                    sink.StartBook(State, token.Marker, code);
                }
                break;

            case UsfmTokenType.Chapter:
                // Get alternate chapter number
                string altChapter = null;
                string pubChapter = null;
                if (!InventoryMode)
                {
                    if (index < tokens.Count - 3 &&
                        tokens[index + 1].Marker == "ca" &&
                        tokens[index + 2].Text != null &&
                        tokens[index + 3].Marker == "ca*")
                    {
                        altChapter = tokens[index + 2].Text.Trim();
                        skip      += 3;

                        // Skip blank space after if present
                        if (index + skip < tokens.Count - 1 &&
                            tokens[index + skip + 1].Text != null &&
                            tokens[index + skip + 1].Text.Trim().Length == 0)
                        {
                            skip++;
                        }
                    }

                    // Get publishable chapter number
                    if (index + skip < tokens.Count - 2 &&
                        tokens[index + skip + 1].Marker == "cp" &&
                        tokens[index + skip + 2].Text != null)
                    {
                        pubChapter = tokens[index + skip + 2].Text.Trim();
                        skip      += 2;
                    }
                }

                // Chapter
                State.VerseRef.Chapter  = token.Data[0];
                State.VerseRef.VerseNum = 0;
                // Verse offset is not zeroed for chapter 1, as it is part of intro
                if (State.VerseRef.ChapterNum != 1)
                {
                    State.VerseOffset = 0;
                }

                if (sink != null)
                {
                    sink.Chapter(State, token.Data[0], token.Marker, altChapter, pubChapter);
                }
                break;

            case UsfmTokenType.Verse:
                string pubVerse = null;
                string altVerse = null;

                if (!InventoryMode)
                {
                    if (index < tokens.Count - 3 &&
                        tokens[index + 1].Marker == "va" &&
                        tokens[index + 2].Text != null &&
                        tokens[index + 3].Marker == "va*")
                    {
                        // Get alternate verse number
                        altVerse = tokens[index + 2].Text.Trim();
                        skip    += 3;
                    }
                    if (index + skip < tokens.Count - 3 &&
                        tokens[index + skip + 1].Marker == "vp" &&
                        tokens[index + skip + 2].Text != null &&
                        tokens[index + skip + 3].Marker == "vp*")
                    {
                        // Get publishable verse number
                        pubVerse = tokens[index + skip + 2].Text.Trim();
                        skip    += 3;
                    }
                }

                // Verse
                State.VerseRef.Verse = token.Data[0];
                State.VerseOffset    = 0;

                if (sink != null)
                {
                    sink.Verse(State, token.Data[0], token.Marker, altVerse, pubVerse);
                }
                break;

            case UsfmTokenType.Paragraph:
                // Handle special case of table rows
                if (token.Marker == "tr")
                {
                    // Start table if not open
                    if (State.Stack.TrueForAll(e => e.Type != UsfmElementTypes.Table))
                    {
                        State.Stack.Add(new UsfmParserElement(UsfmElementTypes.Table, null));
                        if (sink != null)
                        {
                            sink.StartTable(State);
                        }
                    }

                    State.Stack.Add(new UsfmParserElement(UsfmElementTypes.Row, token.Marker));

                    // Row start
                    if (sink != null)
                    {
                        sink.StartRow(State, token.Marker);
                    }
                    break;
                }

                // Handle special case of sidebars
                if (token.Marker == "esb")
                {
                    bool isClosed = IsStudyBibleItemClosed("esb", "esbe");

                    // TODO - see FB 23934
                    // Would like to only add start sidebar if it is closed - adding unclosed marker will cause
                    // an end marker to be created in an unexpected place in the editor.
                    // if (isClosed)
                    State.Stack.Add(new UsfmParserElement(UsfmElementTypes.Sidebar, token.Marker));

                    // Look for category
                    string sidebarCategory = null;
                    if (index < tokens.Count - 3 &&
                        tokens[index + 1].Marker == "cat" &&
                        tokens[index + 2].Text != null &&
                        tokens[index + 3].Marker == "cat*")
                    {
                        // Get category
                        sidebarCategory = tokens[index + 2].Text.Trim();
                        skip           += 3;
                    }

                    if (sink != null)
                    {
                        sink.StartSidebar(State, token.Marker, sidebarCategory, isClosed);
                    }
                    break;
                }

                // Close sidebar if in sidebar
                if (token.Marker == "esbe")
                {
                    if (State.Stack.Exists(e => e.Type == UsfmElementTypes.Sidebar))
                    {
                        CloseAll();
                    }
                    else if (sink != null)
                    {
                        sink.Unmatched(State, token.Marker);
                    }
                    break;
                }

                State.Stack.Add(new UsfmParserElement(UsfmElementTypes.Para, token.Marker));

                // Paragraph opening
                if (sink != null)
                {
                    sink.StartPara(State, token.Marker, token.Type == UsfmTokenType.Unknown);
                }
                break;

            case UsfmTokenType.Character:
                // Handle special case of table cells (treated as special character style)
                if (IsCell(token))
                {
                    string align = "start";
                    if (token.Marker.Length > 2 && token.Marker[2] == 'c')
                    {
                        align = "center";
                    }
                    else if (token.Marker.Length > 2 && token.Marker[2] == 'r')
                    {
                        align = "end";
                    }

                    State.Stack.Add(new UsfmParserElement(UsfmElementTypes.Cell, token.Marker));

                    if (sink != null)
                    {
                        sink.StartCell(State, token.Marker, align);
                    }
                    break;
                }

                if (IsRef(token))
                {
                    // xrefs are special tokens (they do not stand alone)
                    State.SpecialToken = true;

                    string display;
                    string target;
                    ParseDisplayAndTarget(out display, out target);

                    skip += 2;

                    if (sink != null)
                    {
                        sink.Ref(State, token.Marker, display, target);
                    }
                    break;
                }

                string actualMarker;
                bool   invalidMarker = false;
                if (token.Marker.StartsWith("+"))
                {
                    // Only strip + if properly nested
                    actualMarker = state.CharTag != null?token.Marker.TrimStart('+') : token.Marker;

                    invalidMarker = state.CharTag == null;
                }
                else
                {
                    actualMarker = token.Marker;
                }

                State.Stack.Add(new UsfmParserElement(UsfmElementTypes.Char, actualMarker, tokens[index].Attributes));
                if (sink != null)
                {
                    bool charIsClosed           = IsTokenClosed();
                    State.Stack.Last().IsClosed = charIsClosed;     // save for attribute check in Text method
                    sink.StartChar(State, actualMarker, charIsClosed,
                                   token.Type == UsfmTokenType.Unknown || invalidMarker, tokens[index].Attributes);
                }
                break;

            case UsfmTokenType.Note:
                // Look for category
                string noteCategory = null;
                if (index < tokens.Count - 3 &&
                    tokens[index + 1].Marker == "cat" &&
                    tokens[index + 2].Text != null &&
                    tokens[index + 3].Marker == "cat*")
                {
                    // Get category
                    noteCategory = tokens[index + 2].Text.Trim();
                    skip        += 3;
                }

                State.Stack.Add(new UsfmParserElement(UsfmElementTypes.Note, token.Marker));

                if (sink != null)
                {
                    sink.StartNote(State, token.Marker, token.Data[0], noteCategory, IsTokenClosed());
                }
                break;

            case UsfmTokenType.Text:
                string text = token.Text;

                // If last token before a paragraph, book or chapter, esb, esbe (both are paragraph types),
                // or at very end, strip final space
                // This is because USFM requires these to be on a new line, therefore adding whitespace
                if ((index == tokens.Count - 1 ||
                     tokens[index + 1].Type == UsfmTokenType.Paragraph ||
                     tokens[index + 1].Type == UsfmTokenType.Book ||
                     tokens[index + 1].Type == UsfmTokenType.Chapter) &&
                    text.Length > 0 && text[text.Length - 1] == ' ')
                {
                    text = text.Substring(0, text.Length - 1);
                }

                if (sink != null)
                {
                    // Replace ~ with nbsp
                    text = text.Replace('~', '\u00A0');

                    // Replace // with <optbreak/>
                    foreach (string str in optBreakSplitter.Split(text))
                    {
                        if (str == "//")
                        {
                            sink.OptBreak(state);
                        }
                        else
                        {
                            sink.Text(state, str);
                        }
                    }
                }
                break;

            case UsfmTokenType.Milestone:
            case UsfmTokenType.MilestoneEnd:
                // currently, parse state doesn't need to be update, so just inform the sink about the milestone.
                sink?.Milestone(state, token.Marker, token.Type == UsfmTokenType.Milestone, token.Attributes);
                break;
            }

            return(true);
        }
示例#10
0
        public async Task RunAsync(string projectId, string userId, bool trainEngine)
        {
            try
            {
                if (!await InitAsync(projectId, userId))
                {
                    await CompleteSync(false);

                    return;
                }

                string targetParatextId = _projectDoc.Data.ParatextId;
                string sourceParatextId = _projectDoc.Data.TranslateConfig.Source?.ParatextId;

                var targetBooks = new HashSet <int>((await _paratextService.GetBooksAsync(_userSecret,
                                                                                          targetParatextId)).Select(bookId => Canon.BookIdToNumber(bookId)));

                var sourceBooks = new HashSet <int>(TranslationSuggestionsEnabled
                    ? (await _paratextService.GetBooksAsync(_userSecret, sourceParatextId))
                                                    .Select(bookId => Canon.BookIdToNumber(bookId))
                    : Enumerable.Empty <int>());
                sourceBooks.IntersectWith(targetBooks);

                var targetBooksToDelete = new HashSet <int>(GetBooksToDelete(TextType.Target, targetBooks));
                var sourceBooksToDelete = new HashSet <int>(TranslationSuggestionsEnabled
                    ? GetBooksToDelete(TextType.Source, sourceBooks)
                    : Enumerable.Empty <int>());

                _step      = 0;
                _stepCount = (targetBooks.Count * (CheckingEnabled ? 3 : 2)) + (sourceBooks.Count * 2);
                if (targetBooksToDelete.Count > 0 || sourceBooksToDelete.Count > 0)
                {
                    _stepCount += 1;

                    // delete source books
                    foreach (int bookNum in sourceBooksToDelete)
                    {
                        TextInfo text = _projectDoc.Data.Texts.First(t => t.BookNum == bookNum);
                        await DeleteAllTextDataForBookAsync(text, TextType.Source);
                    }
                    // delete target books
                    foreach (int bookNum in targetBooksToDelete)
                    {
                        int      textIndex = _projectDoc.Data.Texts.FindIndex(t => t.BookNum == bookNum);
                        TextInfo text      = _projectDoc.Data.Texts[textIndex];
                        await _projectDoc.SubmitJson0OpAsync(op => op.Remove(pd => pd.Texts, textIndex));

                        await DeleteAllTextDataForBookAsync(text, TextType.Target);
                        await DeleteAllQuestionsDocsForBookAsync(text);
                    }
                    await UpdateProgress();
                }

                // sync source and target books
                foreach (int bookNum in targetBooks)
                {
                    bool     hasSource = sourceBooks.Contains(bookNum);
                    int      textIndex = _projectDoc.Data.Texts.FindIndex(t => t.BookNum == bookNum);
                    TextInfo text;
                    if (textIndex == -1)
                    {
                        text = new TextInfo {
                            BookNum = bookNum, HasSource = hasSource
                        }
                    }
                    ;
                    else
                    {
                        text = _projectDoc.Data.Texts[textIndex];
                    }

                    List <Chapter> newChapters = await SyncOrCloneBookUsxAsync(text, TextType.Target, targetParatextId,
                                                                               false);

                    if (newChapters != null)
                    {
                        if (hasSource)
                        {
                            var chaptersToInclude = new HashSet <int>(newChapters.Select(c => c.Number));
                            await SyncOrCloneBookUsxAsync(text, TextType.Source, sourceParatextId, true,
                                                          chaptersToInclude);
                        }
                        await UpdateNotesData(text, newChapters);

                        await _projectDoc.SubmitJson0OpAsync(op =>
                        {
                            if (textIndex == -1)
                            {
                                // insert text info for new text
                                text.Chapters = newChapters;
                                op.Add(pd => pd.Texts, text);
                            }
                            else
                            {
                                // update text info
                                op.Set(pd => pd.Texts[textIndex].Chapters, newChapters, ChapterListEqualityComparer);
                                op.Set(pd => pd.Texts[textIndex].HasSource, hasSource);
                            }
                        });
                    }
                }

                if (TranslationSuggestionsEnabled && trainEngine)
                {
                    // start training Machine engine
                    await _engineService.StartBuildByProjectIdAsync(projectId);
                }

                await CompleteSync(true);
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Error occurred while executing Paratext sync for project '{Project}'", projectId);
                await CompleteSync(false);
            }
            finally
            {
                CloseConnection();
            }
        }
 public IEnumerable <string> GetCheckFailuresForBook(string bookId)
 {
     return(m_bookInfo.GetFailedChecks(Canon.BookIdToNumber(bookId)));
 }
        internal ParatextUsxBookList GetUsxDocumentsForIncludedParatextBooks(ISet <int> subset = null)
        {
            // Getting the checksum and the checking status at the same time and returning them together ensures that they are really
            // in sync, rather than relying on the caller to get them at the same time.
            var list = new ParatextUsxBookList();

            foreach (var bookNum in GlyssenDblTextMetadata.AvailableBooks.Where(ab => ab.IncludeInScript).Select(ib => Canon.BookIdToNumber(ib.Code)))
            {
                if (subset != null && !subset.Contains(bookNum))
                {
                    continue;
                }
                list.Add(bookNum, GetUsxDocumentForBook(bookNum), UnderlyingScrText.GetBookCheckSum(bookNum),
                         m_bookInfo.GetState(bookNum) == ParatextProjectBookInfo.BookState.NoProblem);
            }
            return(list);
        }
示例#13
0
        /// <summary>
        /// This method should be used any time the user takes an action that would result in marking a book
        /// for inclusion in the project. (It does not need to be called when a book is being removed.)
        /// Currently, this can be either when they click a check-box for an individual book or when they use one of
        /// the "select all" menu items. There are several quick-return paths, but in the "interesting" case,
        /// the purpose of this method is to check whether the book in question is currently in a state (as reported
        /// by Paratext) where the required basic checks all pass. If not, the user needs to confirm that they indeed
        /// wish to include the book and thus override this requirement.
        /// </summary>
        /// <param name="grid">Either the OT grid or the NT grid</param>
        /// <param name="rowIndex">The row index in the grid also corresponds to an entry in the available OT or
        /// NT books list.</param>
        /// <returns></returns>
        private bool IsValidToIncludeBook(DataGridView grid, int rowIndex)
        {
            if (!m_project.IsLiveParatextProject)
            {
                return(true);
            }
            var books = grid.Equals(m_otBooksGrid) ? m_availableOtBooks : m_availableNtBooks;
            var book  = books[rowIndex];

            if (book.IncludeInScript)
            {
                return(true);                // Always valid to exclude
            }
            var bookCode = book.Code;

            if (m_project.DoesBookScriptFileExist(bookCode))
            {
                return(true);                // Might try to get an updated version later but this one is valid.
            }
            GetParatextScrTextWrapperIfNeeded();
            var bookNum = Canon.BookIdToNumber(bookCode);

            if (!m_paratextScrTextWrapper.CanonicalBookNumbersInProject.Contains(bookNum))
            {
                ReportParatextBookNoLongerAvailable(bookCode);
                grid.CurrentRow.DefaultCellStyle.ForeColor = GlyssenColorPalette.ColorScheme.Warning;
                return(false);
            }
            else if (grid.CurrentRow.DefaultCellStyle.ForeColor == GlyssenColorPalette.ColorScheme.Warning)
            {
                grid.CurrentRow.DefaultCellStyle.ForeColor = grid.DefaultCellStyle.ForeColor;
            }

            if (m_paratextScrTextWrapper.DoesBookPassChecks(bookNum, true))
            {
                return(true);
            }

            var failureMessage = Format(LocalizationManager.GetString("DialogBoxes.ScriptureRangeSelectionDlg.FailedChecksForBook",
                                                                      "{0} is not reporting a current successful status for {1} in project {2} for the following basic checks " +
                                                                      "that {3} usually requires to pass:\r\n{4}",
                                                                      "Param 0: \")Paratext\" (product name); " +
                                                                      "Param 1: 3-letter Scripture book code; " +
                                                                      "Param 2: Paratext project short name (unique project identifier); " +
                                                                      "Param 3: \"Glyssen\" (product name); " +
                                                                      "Param 4: List of failing Paratext check names"),
                                        ParatextScrTextWrapper.kParatextProgramName,
                                        bookCode,
                                        m_project.ParatextProjectName,
                                        GlyssenInfo.kProduct,
                                        Join(", ", m_paratextScrTextWrapper.GetCheckFailuresForBook(bookCode)));

            var msg = failureMessage + Environment.NewLine + Environment.NewLine +
                      Format(LocalizationManager.GetString("DialogBoxes.ScriptureRangeSelectionDlg.ConfirmInclusionOfParatextBookThatDoesNotPassChecks",
                                                           "Depending on the specific errors, {0} might fail to process the data for this book properly, which could " +
                                                           "give the appearance of data loss or corruption and could even cause {0} to stop responding. " +
                                                           "Do you want to include this book in the {1} project anyway?",
                                                           "Param 0: \"Glyssen\" (product name); " +
                                                           "Param 1: Glyssen recording project name"),
                             GlyssenInfo.kProduct,
                             m_project.Name);

            if (DialogResult.No == MessageBox.Show(this, msg, GlyssenInfo.kProduct, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation))
            {
                return(false);
            }
            Logger.WriteEvent($"Including book {bookCode} even though " + failureMessage);
            return(true);
        }
示例#14
0
        private void btnOk_Click(object sender, EventArgs e)
        {
            var bookNumsToAddFromParatext = new HashSet <int>();

            foreach (var book in m_project.AvailableBooks)
            {
                bool includingThisBook = m_includeInScript[book.Code];

                if (!includingThisBook)
                {
                    book.IncludeInScript = false;
                    continue;
                }

                if (!m_project.IsLiveParatextProject)
                {
                    book.IncludeInScript = true;
                }

                var existingBookScript = m_project.IncludedBooks.SingleOrDefault(b => b.BookId == book.Code);

                if (existingBookScript != null)
                {
                    bool prevSingleVoiceValue = existingBookScript.SingleVoice;
                    existingBookScript.SingleVoice = !m_multiVoice[existingBookScript.BookId];
                    if (prevSingleVoiceValue != existingBookScript.SingleVoice)
                    {
                        Analytics.Track("SetSingleVoice", new Dictionary <string, string>
                        {
                            { "book", existingBookScript.BookId },
                            { "singleVoice", existingBookScript.SingleVoice.ToString() },
                            { "method", "ScriptureRangeSelectionDlg.m_btnOk_Click" }
                        });
                    }
                    continue;
                }

                Debug.Assert(m_project.IsLiveParatextProject);
                book.IncludeInScript = true;

                BookScript bookScriptFromExistingFile = m_project.FluffUpBookFromFileIfPossible(book.Code);
                if (bookScriptFromExistingFile == null || UserWantsUpdatedContent(bookScriptFromExistingFile))
                {
                    bookNumsToAddFromParatext.Add(Canon.BookIdToNumber(book.Code));
                }
                else
                {
                    bookScriptFromExistingFile.SingleVoice = !m_multiVoice[book.Code];
                    m_project.IncludeExistingBook(bookScriptFromExistingFile);
                    Analytics.Track("IncludeExistingBook", new Dictionary <string, string>
                    {
                        { "book", bookScriptFromExistingFile.BookId },
                        { "singleVoice", bookScriptFromExistingFile.SingleVoice.ToString() }
                    });
                }
            }

            if (bookNumsToAddFromParatext.Any())
            {
                GetParatextScrTextWrapperIfNeeded();
                m_project.IncludeBooksFromParatext(m_paratextScrTextWrapper, bookNumsToAddFromParatext,
                                                   bookScript =>
                {
                    bookScript.SingleVoice = !m_multiVoice[bookScript.BookId];
                    Analytics.Track("SetSingleVoice", new Dictionary <string, string>
                    {
                        { "book", bookScript.BookId },
                        { "singleVoice", bookScript.SingleVoice.ToString() },
                        { "method", "postParseAction anonymous delegate from ScriptureRangeSelectionDlg.m_btnOk_Click" }
                    });
                });
            }

            m_project.BookSelectionStatus = BookSelectionStatus.Reviewed;

            Analytics.Track("SelectBooks", new Dictionary <string, string> {
                { "bookSummary", m_project.BookSelectionSummary }
            });
        }