-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* the SearchDescribers now return a TextFlow * moved the search.rules.describer package from logic to gui package because the SearchDescriber now creates TextFlow Elements * moved the tests accordingly * modified creation of Tooltip in GlobalSearchBar to display the TextFlow created by the SearchDescribers * SearchQuery now stores a TextFlow as description * Added a stub for compatibility in GroupDialog because it uses the SearchQuery to get the description and needs an HTML string for its Swing Tooltip * Styled the SearchBar Tooltip for readability It uses an own style class to not change any other styled elements. Styling was choosen to look like the other (swing) tooltips. * refactor for better readability * removed description member of SearchQuery class because the description of a SearchQuery is a gui element, it is not stored any more in this class. Everywhere the description is needed it is generated * add method to create HTML string from javafx Text * create HTML string from description for compat. * fixed formatting for style * created tests for TextUtil class * modified the SearchDescriber Implementations tests now they work properly again and check the created Texts inside the description TextFlow * split up testcases into single methods * using old localized strings again these old localized strings containing html tags are broken up and converted to Text objects to use in javafx TextFlow * added and modified tests * added changelog entry * changed syntax for getting SearchDescriber now a whole SearchQuery object is sufficient to get a corresponding SearchDescriber * refactored for better style * javafx tooltips styled per css also refactored the GlobalSearchBar tooltip to use this new styling * modified and restructured tests It was necessary to modify the tests of the SearchDescriber Implementations and the TooltipTextUtil class because of the new css styling for tooltips. Also refactored for better style
- Loading branch information
1 parent
9e2c010
commit e944c7a
Showing
20 changed files
with
737 additions
and
297 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
60 changes: 60 additions & 0 deletions
60
.../java/org/jabref/gui/search/rules/describer/ContainsAndRegexBasedSearchRuleDescriber.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package org.jabref.gui.search.rules.describer; | ||
|
||
import java.util.List; | ||
|
||
import javafx.scene.text.Text; | ||
import javafx.scene.text.TextFlow; | ||
|
||
import org.jabref.gui.util.TooltipTextUtil; | ||
import org.jabref.logic.l10n.Localization; | ||
import org.jabref.model.search.rules.SentenceAnalyzer; | ||
|
||
public class ContainsAndRegexBasedSearchRuleDescriber implements SearchDescriber { | ||
|
||
private final boolean regExp; | ||
private final boolean caseSensitive; | ||
private final String query; | ||
|
||
public ContainsAndRegexBasedSearchRuleDescriber(boolean caseSensitive, boolean regExp, String query) { | ||
this.caseSensitive = caseSensitive; | ||
this.regExp = regExp; | ||
this.query = query; | ||
} | ||
|
||
@Override | ||
public TextFlow getDescription() { | ||
List<String> words = new SentenceAnalyzer(query).getWords(); | ||
String firstWord = words.isEmpty() ? "" : words.get(0); | ||
|
||
String temp = regExp ? Localization.lang( | ||
"This search contains entries in which any field contains the regular expression <b>%0</b>") | ||
: Localization.lang("This search contains entries in which any field contains the term <b>%0</b>"); | ||
List<Text> textList = TooltipTextUtil.formatToTexts(temp, new TooltipTextUtil.TextReplacement("<b>%0</b>", firstWord, TooltipTextUtil.TextType.BOLD)); | ||
|
||
if (words.size() > 1) { | ||
List<String> unprocessedWords = words.subList(1, words.size()); | ||
for (String word : unprocessedWords) { | ||
textList.add(TooltipTextUtil.createText(String.format(" %s ", Localization.lang("and")), TooltipTextUtil.TextType.NORMAL)); | ||
textList.add(TooltipTextUtil.createText(word, TooltipTextUtil.TextType.BOLD)); | ||
} | ||
} | ||
|
||
String genericDescription = "\n\n" + Localization.lang("Hint: To search specific fields only, enter for example:<p><tt>author=smith and title=electrical</tt>"); | ||
genericDescription = genericDescription.replace("<p>", "\n"); | ||
List<Text> genericDescriptionTexts = TooltipTextUtil.formatToTexts(genericDescription, new TooltipTextUtil.TextReplacement("<tt>author=smith and title=electrical</tt>", "author=smith and title=electrical", TooltipTextUtil.TextType.MONOSPACED)); | ||
textList.add(getCaseSensitiveDescription()); | ||
textList.addAll(genericDescriptionTexts); | ||
|
||
TextFlow searchDescription = new TextFlow(); | ||
searchDescription.getChildren().setAll(textList); | ||
return searchDescription; | ||
} | ||
|
||
private Text getCaseSensitiveDescription() { | ||
if (caseSensitive) { | ||
return TooltipTextUtil.createText(String.format(" (%s). ", Localization.lang("case sensitive")), TooltipTextUtil.TextType.NORMAL); | ||
} else { | ||
return TooltipTextUtil.createText(String.format(" (%s). ", Localization.lang("case insensitive")), TooltipTextUtil.TextType.NORMAL); | ||
} | ||
} | ||
} |
129 changes: 129 additions & 0 deletions
129
src/main/java/org/jabref/gui/search/rules/describer/GrammarBasedSearchRuleDescriber.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
package org.jabref.gui.search.rules.describer; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.Optional; | ||
import java.util.regex.Pattern; | ||
|
||
import javafx.scene.text.Text; | ||
import javafx.scene.text.TextFlow; | ||
|
||
import org.jabref.gui.util.TooltipTextUtil; | ||
import org.jabref.logic.l10n.Localization; | ||
import org.jabref.model.search.rules.GrammarBasedSearchRule; | ||
import org.jabref.model.strings.StringUtil; | ||
import org.jabref.search.SearchBaseVisitor; | ||
import org.jabref.search.SearchParser; | ||
|
||
import org.antlr.v4.runtime.tree.ParseTree; | ||
|
||
public class GrammarBasedSearchRuleDescriber implements SearchDescriber { | ||
|
||
private final boolean caseSensitive; | ||
private final boolean regExp; | ||
private final ParseTree parseTree; | ||
|
||
public GrammarBasedSearchRuleDescriber(boolean caseSensitive, boolean regExp, ParseTree parseTree) { | ||
this.caseSensitive = caseSensitive; | ||
this.regExp = regExp; | ||
this.parseTree = Objects.requireNonNull(parseTree); | ||
} | ||
|
||
@Override | ||
public TextFlow getDescription() { | ||
TextFlow textFlow = new TextFlow(); | ||
DescriptionSearchBaseVisitor descriptionSearchBaseVisitor = new DescriptionSearchBaseVisitor(); | ||
|
||
// describe advanced search expression | ||
textFlow.getChildren().add(TooltipTextUtil.createText(String.format("%s ", Localization.lang("This search contains entries in which")), TooltipTextUtil.TextType.NORMAL)); | ||
textFlow.getChildren().addAll(descriptionSearchBaseVisitor.visit(parseTree)); | ||
textFlow.getChildren().add(TooltipTextUtil.createText(". ", TooltipTextUtil.TextType.NORMAL)); | ||
textFlow.getChildren().add(TooltipTextUtil.createText(caseSensitive ? Localization | ||
.lang("The search is case sensitive.") : | ||
Localization.lang("The search is case insensitive."), TooltipTextUtil.TextType.NORMAL)); | ||
return textFlow; | ||
} | ||
|
||
private class DescriptionSearchBaseVisitor extends SearchBaseVisitor<List<Text>> { | ||
|
||
@Override | ||
public List<Text> visitStart(SearchParser.StartContext context) { | ||
return visit(context.expression()); | ||
} | ||
|
||
@Override | ||
public List<Text> visitUnaryExpression(SearchParser.UnaryExpressionContext context) { | ||
List<Text> textList = visit(context.expression()); | ||
textList.add(0, TooltipTextUtil.createText(Localization.lang("not").concat(" "), TooltipTextUtil.TextType.NORMAL)); | ||
return textList; | ||
} | ||
|
||
@Override | ||
public List<Text> visitParenExpression(SearchParser.ParenExpressionContext context) { | ||
ArrayList<Text> textList = new ArrayList<>(); | ||
textList.add(TooltipTextUtil.createText(String.format("%s", context.expression()), TooltipTextUtil.TextType.NORMAL)); | ||
return textList; | ||
} | ||
|
||
@Override | ||
public List<Text> visitBinaryExpression(SearchParser.BinaryExpressionContext context) { | ||
List<Text> textList = visit(context.left); | ||
if ("AND".equalsIgnoreCase(context.operator.getText())) { | ||
textList.add(TooltipTextUtil.createText(String.format(" %s ", Localization.lang("and")), TooltipTextUtil.TextType.NORMAL)); | ||
} else { | ||
textList.add(TooltipTextUtil.createText(String.format(" %s ", Localization.lang("or")), TooltipTextUtil.TextType.NORMAL)); | ||
} | ||
textList.addAll(visit(context.right)); | ||
return textList; | ||
} | ||
|
||
@Override | ||
public List<Text> visitComparison(SearchParser.ComparisonContext context) { | ||
final List<Text> textList = new ArrayList<>(); | ||
final Optional<SearchParser.NameContext> fieldDescriptor = Optional.ofNullable(context.left); | ||
final String value = StringUtil.unquote(context.right.getText(), '"'); | ||
if (!fieldDescriptor.isPresent()) { | ||
TextFlow description = new ContainsAndRegexBasedSearchRuleDescriber(caseSensitive, regExp, value).getDescription(); | ||
description.getChildren().forEach(it -> textList.add((Text) it)); | ||
return textList; | ||
} | ||
|
||
final String field = StringUtil.unquote(fieldDescriptor.get().getText(), '"'); | ||
final GrammarBasedSearchRule.ComparisonOperator operator = GrammarBasedSearchRule.ComparisonOperator.build(context.operator.getText()); | ||
|
||
final boolean regExpFieldSpec = !Pattern.matches("\\w+", field); | ||
String temp = regExpFieldSpec ? Localization.lang( | ||
"any field that matches the regular expression <b>%0</b>") : Localization.lang("the field <b>%0</b>"); | ||
|
||
if (operator == GrammarBasedSearchRule.ComparisonOperator.CONTAINS) { | ||
if (regExp) { | ||
temp = Localization.lang("%0 contains the regular expression <b>%1</b>", temp); | ||
} else { | ||
temp = Localization.lang("%0 contains the term <b>%1</b>", temp); | ||
} | ||
} else if (operator == GrammarBasedSearchRule.ComparisonOperator.EXACT) { | ||
if (regExp) { | ||
temp = Localization.lang("%0 matches the regular expression <b>%1</b>", temp); | ||
} else { | ||
temp = Localization.lang("%0 matches the term <b>%1</b>", temp); | ||
} | ||
} else if (operator == GrammarBasedSearchRule.ComparisonOperator.DOES_NOT_CONTAIN) { | ||
if (regExp) { | ||
temp = Localization.lang("%0 doesn't contain the regular expression <b>%1</b>", temp); | ||
} else { | ||
temp = Localization.lang("%0 doesn't contain the term <b>%1</b>", temp); | ||
} | ||
} else { | ||
throw new IllegalStateException("CANNOT HAPPEN!"); | ||
} | ||
|
||
List<Text> formattedTexts = TooltipTextUtil.formatToTexts(temp, | ||
new TooltipTextUtil.TextReplacement("<b>%0</b>", field, TooltipTextUtil.TextType.BOLD), | ||
new TooltipTextUtil.TextReplacement("<b>%1</b>", value, TooltipTextUtil.TextType.BOLD)); | ||
textList.addAll(formattedTexts); | ||
return textList; | ||
} | ||
|
||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
src/main/java/org/jabref/gui/search/rules/describer/SearchDescriber.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package org.jabref.gui.search.rules.describer; | ||
|
||
import javafx.scene.text.TextFlow; | ||
|
||
@FunctionalInterface | ||
public interface SearchDescriber { | ||
|
||
TextFlow getDescription(); | ||
|
||
} |
Oops, something went wrong.