diff --git a/languagetool-core/src/main/java/org/languagetool/rules/AbstractFillerWordsRule.java b/languagetool-core/src/main/java/org/languagetool/rules/AbstractFillerWordsRule.java index 39d76f7fcdcc..6d397ba41b9e 100644 --- a/languagetool-core/src/main/java/org/languagetool/rules/AbstractFillerWordsRule.java +++ b/languagetool-core/src/main/java/org/languagetool/rules/AbstractFillerWordsRule.java @@ -189,4 +189,9 @@ else if ((!isDirectSpeech || minPercent == 0) && !token.isWhitespace() && !token return toRuleMatchArray(ruleMatches); } + @Override + public int minToCheckParagraph() { + return 0; + } + } diff --git a/languagetool-core/src/main/java/org/languagetool/rules/AbstractStyleRepeatedWordRule.java b/languagetool-core/src/main/java/org/languagetool/rules/AbstractStyleRepeatedWordRule.java index 35613c74eda8..100be881acb0 100644 --- a/languagetool-core/src/main/java/org/languagetool/rules/AbstractStyleRepeatedWordRule.java +++ b/languagetool-core/src/main/java/org/languagetool/rules/AbstractStyleRepeatedWordRule.java @@ -319,4 +319,9 @@ public RuleMatch[] match(List sentences) throws IOException { return toRuleMatchArray(ruleMatches); } + @Override + public int minToCheckParagraph() { + return maxDistanceOfSentences; + } + } diff --git a/languagetool-core/src/main/java/org/languagetool/rules/AbstractWordCoherencyRule.java b/languagetool-core/src/main/java/org/languagetool/rules/AbstractWordCoherencyRule.java index 5b85b7ff8c68..5c766792bd1d 100644 --- a/languagetool-core/src/main/java/org/languagetool/rules/AbstractWordCoherencyRule.java +++ b/languagetool-core/src/main/java/org/languagetool/rules/AbstractWordCoherencyRule.java @@ -93,4 +93,9 @@ public RuleMatch[] match(List sentences) { return toRuleMatchArray(ruleMatches); } + @Override + public int minToCheckParagraph() { + return -1; + } + } diff --git a/languagetool-core/src/main/java/org/languagetool/rules/EmptyLineRule.java b/languagetool-core/src/main/java/org/languagetool/rules/EmptyLineRule.java index bfa37fe725af..e46385291714 100644 --- a/languagetool-core/src/main/java/org/languagetool/rules/EmptyLineRule.java +++ b/languagetool-core/src/main/java/org/languagetool/rules/EmptyLineRule.java @@ -86,4 +86,9 @@ public org.languagetool.rules.RuleMatch[] match(List sentences return toRuleMatchArray(ruleMatches); } + @Override + public int minToCheckParagraph() { + return 1; + } + } diff --git a/languagetool-core/src/main/java/org/languagetool/rules/GenericUnpairedBracketsRule.java b/languagetool-core/src/main/java/org/languagetool/rules/GenericUnpairedBracketsRule.java index c05405b67cd9..3b35213f43a0 100644 --- a/languagetool-core/src/main/java/org/languagetool/rules/GenericUnpairedBracketsRule.java +++ b/languagetool-core/src/main/java/org/languagetool/rules/GenericUnpairedBracketsRule.java @@ -293,4 +293,9 @@ private String findCorrespondingSymbol(String symbol) { } } + @Override + public int minToCheckParagraph() { + return -1; + } + } diff --git a/languagetool-core/src/main/java/org/languagetool/rules/LongParagraphRule.java b/languagetool-core/src/main/java/org/languagetool/rules/LongParagraphRule.java index 42aab3736507..db9ec2d351cc 100644 --- a/languagetool-core/src/main/java/org/languagetool/rules/LongParagraphRule.java +++ b/languagetool-core/src/main/java/org/languagetool/rules/LongParagraphRule.java @@ -146,4 +146,9 @@ public RuleMatch[] match(List sentences) throws IOException { return toRuleMatchArray(ruleMatches); } + @Override + public int minToCheckParagraph() { + return 0; + } + } diff --git a/languagetool-core/src/main/java/org/languagetool/rules/MultipleWhitespaceRule.java b/languagetool-core/src/main/java/org/languagetool/rules/MultipleWhitespaceRule.java index daec64d50ac5..219871027716 100644 --- a/languagetool-core/src/main/java/org/languagetool/rules/MultipleWhitespaceRule.java +++ b/languagetool-core/src/main/java/org/languagetool/rules/MultipleWhitespaceRule.java @@ -93,4 +93,9 @@ public RuleMatch[] match(List sentences) { return toRuleMatchArray(ruleMatches); } + @Override + public int minToCheckParagraph() { + return 0; + } + } diff --git a/languagetool-core/src/main/java/org/languagetool/rules/ParagraphRepeatBeginningRule.java b/languagetool-core/src/main/java/org/languagetool/rules/ParagraphRepeatBeginningRule.java index 6d1d2a3a34a5..ad957e1280bb 100644 --- a/languagetool-core/src/main/java/org/languagetool/rules/ParagraphRepeatBeginningRule.java +++ b/languagetool-core/src/main/java/org/languagetool/rules/ParagraphRepeatBeginningRule.java @@ -140,5 +140,10 @@ public RuleMatch[] match(List sentences) throws IOException { return toRuleMatchArray(ruleMatches); } + @Override + public int minToCheckParagraph() { + return 1; + } + } \ No newline at end of file diff --git a/languagetool-core/src/main/java/org/languagetool/rules/PunctuationMarkAtParagraphEnd.java b/languagetool-core/src/main/java/org/languagetool/rules/PunctuationMarkAtParagraphEnd.java index c0b59ca301c2..624aa2df6d4b 100644 --- a/languagetool-core/src/main/java/org/languagetool/rules/PunctuationMarkAtParagraphEnd.java +++ b/languagetool-core/src/main/java/org/languagetool/rules/PunctuationMarkAtParagraphEnd.java @@ -138,4 +138,9 @@ public RuleMatch[] match(List sentences) throws IOException { return toRuleMatchArray(ruleMatches); } + @Override + public int minToCheckParagraph() { + return 0; + } + } diff --git a/languagetool-core/src/main/java/org/languagetool/rules/ReadabilityRule.java b/languagetool-core/src/main/java/org/languagetool/rules/ReadabilityRule.java index f0e284fa0751..fba85e9a1539 100644 --- a/languagetool-core/src/main/java/org/languagetool/rules/ReadabilityRule.java +++ b/languagetool-core/src/main/java/org/languagetool/rules/ReadabilityRule.java @@ -331,5 +331,10 @@ public RuleMatch[] match(List sentences) throws IOException { return toRuleMatchArray(new ArrayList<>()); } } + + @Override + public int minToCheckParagraph() { + return 0; + } } \ No newline at end of file diff --git a/languagetool-core/src/main/java/org/languagetool/rules/SentenceWhitespaceRule.java b/languagetool-core/src/main/java/org/languagetool/rules/SentenceWhitespaceRule.java index b8c266d8d715..84631e3563a3 100644 --- a/languagetool-core/src/main/java/org/languagetool/rules/SentenceWhitespaceRule.java +++ b/languagetool-core/src/main/java/org/languagetool/rules/SentenceWhitespaceRule.java @@ -88,5 +88,10 @@ public RuleMatch[] match(List sentences) throws IOException { } return toRuleMatchArray(ruleMatches); } + + @Override + public int minToCheckParagraph() { + return 0; + } } diff --git a/languagetool-core/src/main/java/org/languagetool/rules/TextLevelRule.java b/languagetool-core/src/main/java/org/languagetool/rules/TextLevelRule.java index 42ae11baf21c..7dea9125c1eb 100644 --- a/languagetool-core/src/main/java/org/languagetool/rules/TextLevelRule.java +++ b/languagetool-core/src/main/java/org/languagetool/rules/TextLevelRule.java @@ -67,5 +67,18 @@ public int estimateContextForSureMatch() { public final RuleMatch[] match(AnalyzedSentence sentence) throws IOException { throw new RuntimeException("Not implemented for a text-level rule"); } + + /** + * Gives back the minimum number of paragraphs to check to give back a correct result + * only used by LO office extension + * return n; + * n == -1 --> need to check full text (use only if really needed / bad performance) + * examples: AbstractWordCoherencyRule, GenericUnpairedBracketsRule, ... + * n == 0 --> need only to check the current paragraph + * examples: MultipleWhitespaceRule, LongParagraphRule, ... + * n >= 1 --> need only to check n paragraphs around the current paragraph + * examples: ParagraphRepeatBeginningRule (n == 1), WordRepeatBeginningRule (n == 2), ... + */ + public abstract int minToCheckParagraph(); } diff --git a/languagetool-core/src/main/java/org/languagetool/rules/UppercaseSentenceStartRule.java b/languagetool-core/src/main/java/org/languagetool/rules/UppercaseSentenceStartRule.java index 34ddbb00fde7..a8944a6f74b4 100644 --- a/languagetool-core/src/main/java/org/languagetool/rules/UppercaseSentenceStartRule.java +++ b/languagetool-core/src/main/java/org/languagetool/rules/UppercaseSentenceStartRule.java @@ -188,4 +188,9 @@ private boolean isSentenceEnd(String word) { private boolean isQuoteStart(String word) { return StringUtils.equalsAny(word, "\"", "'", "„", "»", "«", "“", "‘"); } + + @Override + public int minToCheckParagraph() { + return 0; + } } diff --git a/languagetool-core/src/main/java/org/languagetool/rules/WhiteSpaceBeforeParagraphEnd.java b/languagetool-core/src/main/java/org/languagetool/rules/WhiteSpaceBeforeParagraphEnd.java index c5cf5fa90b2e..7bb8e4297811 100644 --- a/languagetool-core/src/main/java/org/languagetool/rules/WhiteSpaceBeforeParagraphEnd.java +++ b/languagetool-core/src/main/java/org/languagetool/rules/WhiteSpaceBeforeParagraphEnd.java @@ -89,4 +89,9 @@ public RuleMatch[] match(List sentences) throws IOException { return toRuleMatchArray(ruleMatches); } + @Override + public int minToCheckParagraph() { + return 0; + } + } diff --git a/languagetool-core/src/main/java/org/languagetool/rules/WordRepeatBeginningRule.java b/languagetool-core/src/main/java/org/languagetool/rules/WordRepeatBeginningRule.java index 5a37833a7072..5588453673dc 100644 --- a/languagetool-core/src/main/java/org/languagetool/rules/WordRepeatBeginningRule.java +++ b/languagetool-core/src/main/java/org/languagetool/rules/WordRepeatBeginningRule.java @@ -107,4 +107,9 @@ public RuleMatch[] match(List sentences) throws IOException { return toRuleMatchArray(ruleMatches); } + @Override + public int minToCheckParagraph() { + return 2; + } + } diff --git a/languagetool-language-modules/de/src/main/java/org/languagetool/rules/de/CompoundCoherencyRule.java b/languagetool-language-modules/de/src/main/java/org/languagetool/rules/de/CompoundCoherencyRule.java index 600bdd31274e..a9c277e3d22b 100644 --- a/languagetool-language-modules/de/src/main/java/org/languagetool/rules/de/CompoundCoherencyRule.java +++ b/languagetool-language-modules/de/src/main/java/org/languagetool/rules/de/CompoundCoherencyRule.java @@ -135,4 +135,9 @@ private String getLemma(AnalyzedTokenReadings atr) { } } + @Override + public int minToCheckParagraph() { + return -1; + } + } diff --git a/languagetool-language-modules/de/src/main/java/org/languagetool/rules/de/DuUpperLowerCaseRule.java b/languagetool-language-modules/de/src/main/java/org/languagetool/rules/de/DuUpperLowerCaseRule.java index 6ebd84b3a83b..ad440f187841 100644 --- a/languagetool-language-modules/de/src/main/java/org/languagetool/rules/de/DuUpperLowerCaseRule.java +++ b/languagetool-language-modules/de/src/main/java/org/languagetool/rules/de/DuUpperLowerCaseRule.java @@ -117,4 +117,9 @@ public RuleMatch[] match(List sentences) throws IOException { return toRuleMatchArray(ruleMatches); } + @Override + public int minToCheckParagraph() { + return -1; + } + } diff --git a/languagetool-language-modules/de/src/main/java/org/languagetool/rules/de/SimilarNameRule.java b/languagetool-language-modules/de/src/main/java/org/languagetool/rules/de/SimilarNameRule.java index 4cd84a21cbc0..5668dcdc31f1 100644 --- a/languagetool-language-modules/de/src/main/java/org/languagetool/rules/de/SimilarNameRule.java +++ b/languagetool-language-modules/de/src/main/java/org/languagetool/rules/de/SimilarNameRule.java @@ -111,5 +111,10 @@ private String similarName(String nameHere, Set namesSoFar) { } return null; } + + @Override + public int minToCheckParagraph() { + return -1; + } } diff --git a/languagetool-language-modules/de/src/main/java/org/languagetool/rules/de/VerbAgreementRule.java b/languagetool-language-modules/de/src/main/java/org/languagetool/rules/de/VerbAgreementRule.java index 3501f232a4ae..62cfb55ab923 100644 --- a/languagetool-language-modules/de/src/main/java/org/languagetool/rules/de/VerbAgreementRule.java +++ b/languagetool-language-modules/de/src/main/java/org/languagetool/rules/de/VerbAgreementRule.java @@ -594,4 +594,9 @@ private BooleanAndFiniteVerb(boolean verbDoesMatchPersonAndNumber, AnalyzedToken this.finiteVerb = finiteVerb; } } + + @Override + public int minToCheckParagraph() { + return 0; + } } \ No newline at end of file diff --git a/languagetool-language-modules/en/src/test/java/org/languagetool/JLanguageToolTest.java b/languagetool-language-modules/en/src/test/java/org/languagetool/JLanguageToolTest.java index e02b41819c09..e511f09cdd7a 100644 --- a/languagetool-language-modules/en/src/test/java/org/languagetool/JLanguageToolTest.java +++ b/languagetool-language-modules/en/src/test/java/org/languagetool/JLanguageToolTest.java @@ -270,5 +270,9 @@ public String getId() { public String getDescription() { return "Test rule"; } + @Override + public int minToCheckParagraph() { + return -1; + } } } diff --git a/languagetool-office-extension/src/main/java/org/languagetool/openoffice/MultiDocumentsHandler.java b/languagetool-office-extension/src/main/java/org/languagetool/openoffice/MultiDocumentsHandler.java index 890e440fb6fd..564d18715bb3 100644 --- a/languagetool-office-extension/src/main/java/org/languagetool/openoffice/MultiDocumentsHandler.java +++ b/languagetool-office-extension/src/main/java/org/languagetool/openoffice/MultiDocumentsHandler.java @@ -34,6 +34,7 @@ import org.languagetool.gui.Configuration; import org.languagetool.rules.CategoryId; import org.languagetool.rules.Rule; +import org.languagetool.rules.TextLevelRule; import org.languagetool.tools.Tools; import com.sun.star.awt.XMenuBar; @@ -78,6 +79,7 @@ public class MultiDocumentsHandler { private final String configFile; private Configuration config = null; private LinguisticServices linguServices = null; + private SortedTextRules sortedTextRules; private XComponentContext xContext; // The context of the document private List documents; // The List of LO documents to be checked @@ -367,7 +369,7 @@ private int getNumDoc(String docID) { } } } - documents.add(new SingleDocument(xContext, config, docID, xComponent)); + documents.add(new SingleDocument(xContext, config, docID, xComponent, this)); setMenuTextForSwitchOff(xContext); if (debugMode) { MessageHandler.printToLogFile("Document " + docNum + " created; docID = " + docID); @@ -469,10 +471,12 @@ void initCheck() { langTool.enableRule(ruleName); } } + recheck = false; + sortedTextRules = new SortedTextRules(); + setConfigValues(config, langTool); for (SingleDocument document : documents) { document.resetCache(); } - recheck = false; } /** @@ -573,5 +577,128 @@ public boolean toggleSwitchedOff() throws IOException { return ret; } + /** + * Returns a list of different numbers of paragraphs to check for text level rules + * (currently only -1 for full text check and n for max number for other text level rules) + */ + public List getNumMinToCheckParas() { + return sortedTextRules.minToCheckParagraph; + } + + /** + * activate all rules stored under a given index related to the list of getNumMinToCheckParas + * deactivate all other text level rules + */ + public void activateTextRulesByIndex(int index) { + sortedTextRules.activateTextRulesByIndex(index); + } + + /** + * reactivate all text level rules + */ + public void reactivateTextRules() { + sortedTextRules.reactivateTextRules();; + } + /** + * class to store all text level rules sorted by the minimum to check paragraphs + * (currently only full text check and all other text level rules) + * + */ + class SortedTextRules { + List minToCheckParagraph; + List> textLevelRules; + SortedTextRules () { + minToCheckParagraph = new ArrayList(); + textLevelRules = new ArrayList>(); + List rules = langTool.getAllActiveOfficeRules(); + for(Rule rule : rules) { + if(rule instanceof TextLevelRule) { + insertRule(((TextLevelRule) rule).minToCheckParagraph(), rule.getId()); + } + } + if(debugMode) { + MessageHandler.printToLogFile("Number different minToCheckParagraph: " + minToCheckParagraph.size()); + for( int i = 0; i < minToCheckParagraph.size(); i++) { + MessageHandler.printToLogFile("minToCheckParagraph: " + minToCheckParagraph.get(i)); + for (int j = 0; j < textLevelRules.get(i).size(); j++) { + MessageHandler.printToLogFile("RuleId: " + textLevelRules.get(i).get(j)); + } + } + } + } + + private void insertRule (int minPara, String RuleId) { + if(minPara < 0) { + int n = minToCheckParagraph.indexOf(minPara); + if( n >= 0) { + } else { + minToCheckParagraph.add(minPara); + textLevelRules.add(new ArrayList()); + } + textLevelRules.get(textLevelRules.size() - 1).add(new String(RuleId)); + } else { + int n = minToCheckParagraph.indexOf(-1); + if( n == 0 || minToCheckParagraph.size() == 0) { + minToCheckParagraph.add(0, minPara); + textLevelRules.add(0, new ArrayList()); + } else if(minPara > minToCheckParagraph.get(0)) { + minToCheckParagraph.set(0, minPara); + } + textLevelRules.get(0).add(new String(RuleId)); + } + } +/* + * This rule was commented out for performance reasons and replaced by the same named rule before + * + private void insertRule (int minPara, String RuleId) { + int n = minToCheckParagraph.indexOf(minPara); + if( n >= 0) { + textLevelRules.get(n).add(new String(RuleId)); + return; + } else { + if(minPara < 0) { + n = minToCheckParagraph.size(); + } else { + for (n = 0; n < minToCheckParagraph.size(); n++) { + if(minPara < minToCheckParagraph.get(n) || minToCheckParagraph.get(n) < 0) { + break; + } + } + } + minToCheckParagraph.add(n, minPara); + textLevelRules.add(n, new ArrayList()); + textLevelRules.get(n).add(new String(RuleId)); + } + } +*/ + public List getMinToCheckParas() { + return minToCheckParagraph; + } + + public void activateTextRulesByIndex(int index) { + for(int i = 0; i < textLevelRules.size(); i++) { + if(i == index) { + for (String ruleId : textLevelRules.get(i)) { + langTool.enableRule(ruleId); + } + } else { + for (String ruleId : textLevelRules.get(i)) { + langTool.disableRule(ruleId); + } + } + } + } + + public void reactivateTextRules() { + for(List textRules : textLevelRules) { + for (String ruleId : textRules) { + langTool.enableRule(ruleId); + } + } + } + + } + + } diff --git a/languagetool-office-extension/src/main/java/org/languagetool/openoffice/SingleDocument.java b/languagetool-office-extension/src/main/java/org/languagetool/openoffice/SingleDocument.java index 236b4ce6a413..981e7f6c3ef7 100644 --- a/languagetool-office-extension/src/main/java/org/languagetool/openoffice/SingleDocument.java +++ b/languagetool-office-extension/src/main/java/org/languagetool/openoffice/SingleDocument.java @@ -67,7 +67,7 @@ class SingleDocument { private static final String MANUAL_LINEBREAK = "\r"; // to distinguish from paragraph separator private static final String ZERO_WIDTH_SPACE = "\u200B"; // Used to mark footnotes private static final String logLineBreak = System.getProperty("line.separator"); // LineBreak in Log-File (MS-Windows compatible) - private static final int PARA_CHECK_FACTOR = 40; // Factor for parameter checked at once at iteration (no text change) + private static final int PARA_CHECK_DEFAULT = 50; // Factor for parameter checked at once at iteration (no text change) private static final int MAX_SUGGESTIONS = 15; @@ -75,14 +75,19 @@ class SingleDocument { private Configuration config; - private int numParasToCheck = 5; // will be overwritten by config + private int maxParasToCheck = 5; // will be overwritten by config private int defaultParaCheck = 10; // will be overwritten by config private boolean doResetCheck = true; // will be overwritten by config + private boolean doFullCheckAtFirst = true; // TODO: will be overwritten by config + + private int numParasToCheck = 0; // current number of Paragraphs to be checked + private boolean firstCheckIsDone = false; // Is first check done? private XComponentContext xContext; // The context of the document private String docID; // docID of the document private XComponent xComponent; // XComponent of the open document - + private MultiDocumentsHandler mDocHandler; + private List allParas = null; // List of paragraphs (only readable by parallel thread) private DocumentCursorTools docCursor = null; // Save Cursor for the single documents private Integer numLastVCPara = 0; // Save position of ViewCursor for the single documents @@ -92,22 +97,34 @@ class SingleDocument { private int resetParaNum = -1; // true: do a reset after last sentence is checked private int divNum; // difference between number of paragraphs from cursor and from flatParagraph (unchanged by parallel thread) private ResultCache sentencesCache; // Cache for matches of sentences rules - private ResultCache paragraphsCache; // Cache for matches of text rules + private List paragraphsCache; // Cache for matches of text rules private ResultCache singleParaCache; // Cache for matches of text rules for single paragraphs private int resetFrom = 0; // Reset from paragraph private int resetTo = 0; // Reset to paragraph private List isChecked; // List of status of all flat paragraphs of document - private List changedParas; // List of changed paragraphs after editing the document + private List changedParas; // List of changed paragraphs after editing the document private int paraNum; // Number of current checked paragraph + List minToCheckPara; + List> textLevelRules; - SingleDocument(XComponentContext xContext, Configuration config, String docID, XComponent xComponent) { + SingleDocument(XComponentContext xContext, Configuration config, String docID, + XComponent xComponent, MultiDocumentsHandler mDH) { this.xContext = xContext; this.config = config; this.docID = docID; this.xComponent = xComponent; + this.mDocHandler = mDH; this.sentencesCache = new ResultCache(); - this.paragraphsCache = new ResultCache(); this.singleParaCache = new ResultCache(); + this.paragraphsCache = new ArrayList(); + if((doFullCheckAtFirst || maxParasToCheck < 0) && mDocHandler != null) { + minToCheckPara = mDocHandler.getNumMinToCheckParas(); + for(int i = 0; i < minToCheckPara.size(); i++) { + paragraphsCache.add(new ResultCache()); + } + } else { + paragraphsCache.add(new ResultCache()); + } if (config != null) { setConfigValues(config); } @@ -149,13 +166,14 @@ ProofreadingResult getCheckResults(String paraText, Locale locale, ProofreadingR sErrors = checkSentence(sentence, paRes.nStartOfSentencePosition, paRes.nStartOfNextSentencePosition, paraNum, footnotePositions, isParallelThread, langTool); } - SingleProofreadingError[] pErrors = checkParaRules(paraText, paraNum, paRes.nStartOfSentencePosition, + List pErrors = checkTextRules(paraText, paraNum, paRes.nStartOfSentencePosition, paRes.nStartOfNextSentencePosition, isParallelThread, langTool); + paRes.aErrors = mergeErrors(sErrors, pErrors); + textIsChanged = false; if (debugMode > 1) { MessageHandler.printToLogFile("paRes.aErrors.length: " + paRes.aErrors.length + "; docID: " + docID + logLineBreak); } - textIsChanged = false; } catch (Throwable t) { MessageHandler.showError(t); } @@ -168,9 +186,10 @@ ProofreadingResult getCheckResults(String paraText, Locale locale, ProofreadingR void setConfigValues(Configuration config) { this.config = config; numParasToCheck = config.getNumParasToCheck(); - defaultParaCheck = numParasToCheck * PARA_CHECK_FACTOR; + defaultParaCheck = PARA_CHECK_DEFAULT; doResetCheck = config.isResetCheck(); changedParas = null; + firstCheckIsDone = false; } /** Set XComponentContext and XComponent of the document @@ -196,8 +215,16 @@ String getDocID() { */ void resetCache() { sentencesCache.removeAll(); - paragraphsCache.removeAll(); singleParaCache.removeAll(); + paragraphsCache = new ArrayList(); + if(doFullCheckAtFirst || maxParasToCheck < 0) { + minToCheckPara = mDocHandler.getNumMinToCheckParas(); + for(int i = 0; i < minToCheckPara.size(); i++) { + paragraphsCache.add(new ResultCache()); + } + } else { + paragraphsCache.add(new ResultCache()); + } } /** @@ -229,7 +256,11 @@ boolean doresetCheck() { void optimizeReset() { if(numParasToCheck != 0) { FlatParagraphTools flatPara = new FlatParagraphTools(xContext); - flatPara.markFlatParasAsChecked(resetFrom + divNum, resetTo + divNum, isChecked); + if(numParasToCheck < 0) { + flatPara.markFlatParasAsChecked(0, 0, isChecked); + } else { + flatPara.markFlatParasAsChecked(resetFrom + divNum, resetTo + divNum, isChecked); + } } resetCheck = false; } @@ -278,7 +309,7 @@ private int getParaPos(String chPara, boolean isParallelThread) { boolean isReset = false; textIsChanged = false; - if (allParas == null || allParas.isEmpty()) { + if (allParas == null || allParas.size() < 1) { if (isParallelThread) { // if numThread > 0: Thread may only read allParas return -1; } @@ -317,11 +348,10 @@ private int getParaPos(String chPara, boolean isParallelThread) { && allParas.get(from).equals(oldParas.get(from))) { from++; } - from -= 1 + numParasToCheck; if(numParasToCheck > 0) { - resetFrom = from; + resetFrom = from - numParasToCheck - 1; } else { - resetFrom = 0; + resetFrom = from - 1; } int to = 1; while (to <= allParas.size() && to <= oldParas.size() @@ -329,13 +359,14 @@ private int getParaPos(String chPara, boolean isParallelThread) { oldParas.get(oldParas.size() - to))) { to++; } - to = allParas.size() + numParasToCheck - to; if(numParasToCheck > 0) { - resetTo = to; + resetTo = allParas.size() + numParasToCheck - to; } else { - resetTo = 0; + resetTo = allParas.size() - to; + } + for(ResultCache cache : paragraphsCache) { + cache.removeAndShift(from, to, allParas.size() - oldParas.size()); } - paragraphsCache.removeAndShift(from, to, allParas.size() - oldParas.size()); isReset = true; if(doResetCheck) { from += numParasToCheck; @@ -343,6 +374,7 @@ private int getParaPos(String chPara, boolean isParallelThread) { sentencesCache.removeAndShift(from, to, allParas.size() - oldParas.size()); resetCheck = true; } + textIsChanged = true; } // try to get next position from last ViewCursorPosition (proof per dialog box) @@ -405,14 +437,21 @@ private int getParaPos(String chPara, boolean isParallelThread) { + "new: " + chPara + logLineBreak); } allParas.set(nParas, chPara); - paragraphsCache.remove(nParas); + for(ResultCache cache : paragraphsCache) { + cache.remove(nParas); + } if(doResetCheck) { sentencesCache.remove(nParas); resetCheck = true; resetParaNum = nParas; } - resetFrom = nParas - numParasToCheck; - resetTo = nParas + numParasToCheck + 1; + if(numParasToCheck > 0) { + resetFrom = nParas - numParasToCheck; + resetTo = nParas + numParasToCheck + 1; + } else { + resetFrom = nParas; + resetTo = nParas + 1; + } textIsChanged = true; return nParas; } @@ -428,7 +467,7 @@ private int getParaPos(String chPara, boolean isParallelThread) { */ private boolean resetAllParas(DocumentCursorTools docCursor, FlatParagraphTools flatPara) { allParas = docCursor.getAllTextParagraphs(); - if (allParas == null || allParas.isEmpty()) { + if (allParas == null || allParas.size() < 1) { return false; } // change all footnotes to \u200B (like in paraText) @@ -568,13 +607,17 @@ private AnnotatedText getAnnotatedText(String text, int[] footnotePos, int start return annotations.build(); } - private SingleProofreadingError[] mergeErrors(SingleProofreadingError[] sErrors, SingleProofreadingError[] pErrors) { + private SingleProofreadingError[] mergeErrors(SingleProofreadingError[] sErrors, List pErrors) { int errorCount = 0; if (sErrors != null) { errorCount += sErrors.length; } if (pErrors != null) { - errorCount += pErrors.length; + for(SingleProofreadingError[] pError : pErrors) { + if(pError != null) { + errorCount += pError.length; + } + } } if (errorCount == 0) { return new SingleProofreadingError[0]; @@ -586,23 +629,95 @@ private SingleProofreadingError[] mergeErrors(SingleProofreadingError[] sErrors, arraycopy(sErrors, 0, errorArray, 0, sErrorCount); } if (pErrors != null) { - arraycopy(pErrors, 0, errorArray, sErrorCount, pErrors.length); + for(SingleProofreadingError[] pError : pErrors) { + if(pError != null) { + arraycopy(pError, 0, errorArray, sErrorCount, pError.length); + sErrorCount += pError.length; + } + } } Arrays.sort(errorArray, new ErrorPositionComparator()); return errorArray; } @Nullable - private SingleProofreadingError[] checkParaRules( String paraText, int paraNum, + private List checkTextRules( String paraText, int paraNum, int startSentencePos, int endSentencePos, boolean isParallelThread, SwJLanguageTool langTool) { + List pErrors = new ArrayList(); + + if(paraNum < 0 || (!doFullCheckAtFirst && maxParasToCheck >= 0)) { + pErrors.add(checkParaRules(paraText, paraNum, startSentencePos, endSentencePos, isParallelThread, langTool, 0)); + } else { + // Real full text check / numParas < 0 + ResultCache oldCache = null; + List tmpChangedParas; + if(doResetCheck && resetCheck) { + changedParas = new ArrayList(); + } + for(int i = 0; i < minToCheckPara.size(); i++) { + numParasToCheck = minToCheckPara.get(i); + if(firstCheckIsDone && (numParasToCheck == -1 || numParasToCheck > maxParasToCheck)) { + numParasToCheck = maxParasToCheck; + } + defaultParaCheck = PARA_CHECK_DEFAULT; + mDocHandler.activateTextRulesByIndex(i); + if (debugMode > 1) { + MessageHandler.printToLogFile("ParaCeck: Index: " + i + "/" + minToCheckPara.size() + + "; numParasToCheck: " + numParasToCheck + logLineBreak); + } + if(doResetCheck && resetCheck && numParasToCheck < 0) { + oldCache = paragraphsCache.get(i); + paragraphsCache.set(i, new ResultCache()); + } + pErrors.add(checkParaRules(paraText, paraNum, startSentencePos, endSentencePos, isParallelThread, langTool, i)); + if(doResetCheck && resetCheck) { + if(numParasToCheck < 0) { + tmpChangedParas = paragraphsCache.get(i).differenceInCaches(oldCache); + for(int chPara : tmpChangedParas) { + if(!changedParas.contains(chPara)) { + changedParas.add(chPara); + } + } + } else { + int firstPara = resetFrom - numParasToCheck; + if (firstPara < 0) { + firstPara = 0; + } + int lastPara = resetTo + numParasToCheck; + if (lastPara > allParas.size()) { + lastPara = allParas.size(); + } + for (int n = firstPara; n < lastPara; n++) { + if(!changedParas.contains(n)) { + changedParas.add(n); + } + } + } + } + } + oldCache = null; + if(!firstCheckIsDone && numParasToCheck == -1) { + firstCheckIsDone = true; + } + mDocHandler.reactivateTextRules(); + } + return pErrors; + } + + + @Nullable + private SingleProofreadingError[] checkParaRules( String paraText, int paraNum, + int startSentencePos, int endSentencePos, boolean isParallelThread, SwJLanguageTool langTool, int cacheNum) { List paragraphMatches; SingleProofreadingError[] pErrors = null; try { - // use Cache for check in single paragraph mode only after the first call of paragraph - if(numParasToCheck != 0 && paraNum >= 0) { - pErrors = paragraphsCache.getFromPara(paraNum, startSentencePos, endSentencePos); + if(paraNum >= 0) { + pErrors = paragraphsCache.get(cacheNum).getFromPara(paraNum, startSentencePos, endSentencePos); + if (debugMode > 1 && pErrors != null) { + MessageHandler.printToLogFile("Check Para Rules: pErrors from cache: " + pErrors.length); + } } else if (startSentencePos > 0) { pErrors = singleParaCache.getFromPara(0, startSentencePos, endSentencePos); return pErrors; @@ -620,9 +735,17 @@ private SingleProofreadingError[] checkParaRules( String paraText, int paraNum, paragraphMatches = langTool.check(textToCheck, true, JLanguageTool.ParagraphHandling.ONLYPARA); // One paragraph check (set by options or proof of footnote, etc.) - if (numParasToCheck == 0 || paraNum < 0) { + if (paraNum < 0 || numParasToCheck == 0) { if(paragraphMatches == null || paragraphMatches.isEmpty()) { - singleParaCache.put(0, new SingleProofreadingError[0]); + if (paraNum < 0) { + singleParaCache.put(0, new SingleProofreadingError[0]); + } else { + paragraphsCache.get(cacheNum).put(paraNum, new SingleProofreadingError[0]); + if (debugMode > 1) { + MessageHandler.printToLogFile("--> Enter to para cache(" + cacheNum + "): Paragraph: " + paraText + + "; Error number: " + 0 + logLineBreak); + } + } } else { List errorList = new ArrayList<>(); for (RuleMatch myRuleMatch : paragraphMatches) { @@ -633,12 +756,32 @@ private SingleProofreadingError[] checkParaRules( String paraText, int paraNum, errorList.add(createOOoError(myRuleMatch, 0, toPos, paraText.charAt(toPos-1))); } if (!errorList.isEmpty()) { - singleParaCache.put(0, errorList.toArray(new SingleProofreadingError[0])); + if (paraNum < 0) { + singleParaCache.put(0, errorList.toArray(new SingleProofreadingError[0])); + } else { + if (debugMode > 1) { + MessageHandler.printToLogFile("--> Enter to para cache(" + cacheNum + "): Paragraph: " + paraText + + "; Error number: " + errorList.size() + logLineBreak); + } + paragraphsCache.get(cacheNum).put(paraNum, errorList.toArray(new SingleProofreadingError[0])); + } } else { - singleParaCache.put(0, new SingleProofreadingError[0]); + if (paraNum < 0) { + singleParaCache.put(0, new SingleProofreadingError[0]); + } else { + if (debugMode > 1) { + MessageHandler.printToLogFile("--> Enter to para cache(" + cacheNum + "): Paragraph: " + paraText + + "; Error number: " + 0 + logLineBreak); + } + paragraphsCache.get(cacheNum).put(paraNum, new SingleProofreadingError[0]); + } } } - return singleParaCache.getFromPara(0, startSentencePos, endSentencePos); + if (paraNum < 0) { + return singleParaCache.getFromPara(0, startSentencePos, endSentencePos); + } else { + return paragraphsCache.get(cacheNum).getFromPara(paraNum, startSentencePos, endSentencePos); + } } // check of numParasToCheck or full text @@ -667,12 +810,6 @@ private SingleProofreadingError[] checkParaRules( String paraText, int paraNum, } int startPos = getStartOfParagraph(startPara, paraNum); int endPos; - ResultCache oldCache = null; - if(numParasToCheck < 0 && doResetCheck && resetCheck) { - oldCache = paragraphsCache; - paragraphsCache = new ResultCache(); - } - for (int i = startPara; i < endPara; i++) { if(i < endPara - 1) { endPos = getStartOfParagraph(i + 1, paraNum); @@ -680,7 +817,11 @@ private SingleProofreadingError[] checkParaRules( String paraText, int paraNum, endPos = textToCheck.length(); } if(paragraphMatches == null || paragraphMatches.isEmpty()) { - paragraphsCache.put(i, new SingleProofreadingError[0]); + paragraphsCache.get(cacheNum).put(i, new SingleProofreadingError[0]); + if (debugMode > 1) { + MessageHandler.printToLogFile("--> Enter to para cache(" + cacheNum + "): Paragraph: " + allParas.get(i) + + "; Error number: 0" + logLineBreak); + } } else { List errorList = new ArrayList<>(); int textPos = startPos; @@ -695,25 +836,22 @@ private SingleProofreadingError[] checkParaRules( String paraText, int paraNum, } } if (!errorList.isEmpty()) { - paragraphsCache.put(i, errorList.toArray(new SingleProofreadingError[0])); + paragraphsCache.get(cacheNum).put(i, errorList.toArray(new SingleProofreadingError[0])); if (debugMode > 1) { - MessageHandler.printToLogFile("--> Enter to para cache: Paragraph: " + allParas.get(i) + "; Error number: " + errorList.size() + logLineBreak); + MessageHandler.printToLogFile("--> Enter to para cache(" + cacheNum + "): Paragraph: " + allParas.get(i) + + "; Error number: " + errorList.size() + logLineBreak); } } else { - paragraphsCache.put(i, new SingleProofreadingError[0]); + paragraphsCache.get(cacheNum).put(i, new SingleProofreadingError[0]); if (debugMode > 1) { - MessageHandler.printToLogFile("--> Enter to para cache: Paragraph: " + allParas.get(i) + "; Error number: 0" + logLineBreak); + MessageHandler.printToLogFile("--> Enter to para cache(" + cacheNum + "): Paragraph: " + allParas.get(i) + + "; Error number: 0" + logLineBreak); } } } startPos = endPos; } - - if(numParasToCheck < 0 && doResetCheck && resetCheck) { - changedParas = paragraphsCache.differenceInCaches(oldCache); - oldCache = null; - } - return paragraphsCache.getFromPara(paraNum, startSentencePos, endSentencePos); + return paragraphsCache.get(cacheNum).getFromPara(paraNum, startSentencePos, endSentencePos); } catch (Throwable t) { MessageHandler.showError(t); } diff --git a/languagetool-office-extension/src/test/java/org/languagetool/openoffice/MainTest.java b/languagetool-office-extension/src/test/java/org/languagetool/openoffice/MainTest.java index f13b7321cd60..dcd8b3d54da8 100644 --- a/languagetool-office-extension/src/test/java/org/languagetool/openoffice/MainTest.java +++ b/languagetool-office-extension/src/test/java/org/languagetool/openoffice/MainTest.java @@ -87,7 +87,7 @@ public void testVariants() { public void testCleanFootnotes() { Main main = new Main(null); main.setTestMode(true); - SingleDocument prog = new SingleDocument(null, null, null, null); + SingleDocument prog = new SingleDocument(null, null, null, null, null); assertEquals("A house.¹ Here comes more text.", prog.cleanFootnotes("A house.1 Here comes more text.")); assertEquals("A road that's 3.4 miles long.", prog.cleanFootnotes("A road that's 3.4 miles long.")); assertEquals("A house.1234 Here comes more text.", prog.cleanFootnotes("A house.1234 Here comes more text.")); // too many digits for a footnote