diff --git a/assets/resources/application/cs.xml b/assets/resources/application/cs.xml index 76b45f007..7be472f51 100644 --- a/assets/resources/application/cs.xml +++ b/assets/resources/application/cs.xml @@ -542,6 +542,7 @@ + diff --git a/assets/resources/application/de.xml b/assets/resources/application/de.xml index b45d92610..62620ecf0 100644 --- a/assets/resources/application/de.xml +++ b/assets/resources/application/de.xml @@ -528,6 +528,7 @@ + diff --git a/assets/resources/application/en.xml b/assets/resources/application/en.xml index a3b89736d..9261fabcb 100644 --- a/assets/resources/application/en.xml +++ b/assets/resources/application/en.xml @@ -542,6 +542,7 @@ + diff --git a/assets/resources/application/fr.xml b/assets/resources/application/fr.xml index 5e685609a..01af26f51 100644 --- a/assets/resources/application/fr.xml +++ b/assets/resources/application/fr.xml @@ -528,6 +528,7 @@ + diff --git a/assets/resources/application/gl.xml b/assets/resources/application/gl.xml index 013d3cbea..ef6b06aec 100644 --- a/assets/resources/application/gl.xml +++ b/assets/resources/application/gl.xml @@ -528,6 +528,7 @@ + diff --git a/assets/resources/application/hu.xml b/assets/resources/application/hu.xml index 733d9a64a..3f5117b9d 100644 --- a/assets/resources/application/hu.xml +++ b/assets/resources/application/hu.xml @@ -528,6 +528,7 @@ + diff --git a/assets/resources/application/it.xml b/assets/resources/application/it.xml index 5a932ef3d..cc53fc339 100644 --- a/assets/resources/application/it.xml +++ b/assets/resources/application/it.xml @@ -528,6 +528,7 @@ + diff --git a/assets/resources/application/nl.xml b/assets/resources/application/nl.xml index fac1edd85..037bace98 100644 --- a/assets/resources/application/nl.xml +++ b/assets/resources/application/nl.xml @@ -528,6 +528,7 @@ + diff --git a/assets/resources/application/ru.xml b/assets/resources/application/ru.xml index 8d6438b1c..359943d93 100644 --- a/assets/resources/application/ru.xml +++ b/assets/resources/application/ru.xml @@ -528,6 +528,7 @@ + diff --git a/assets/resources/application/th.xml b/assets/resources/application/th.xml index 6bdff9530..a93df6f0c 100644 --- a/assets/resources/application/th.xml +++ b/assets/resources/application/th.xml @@ -528,6 +528,7 @@ + diff --git a/assets/resources/application/uk.xml b/assets/resources/application/uk.xml index 560f1b68c..e9c9605af 100644 --- a/assets/resources/application/uk.xml +++ b/assets/resources/application/uk.xml @@ -528,6 +528,7 @@ + diff --git a/assets/resources/application/vi.xml b/assets/resources/application/vi.xml index 9c4adcf10..7c8c86ffd 100644 --- a/assets/resources/application/vi.xml +++ b/assets/resources/application/vi.xml @@ -528,6 +528,7 @@ + diff --git a/assets/resources/application/zh.xml b/assets/resources/application/zh.xml index 98fcbd276..10ef5a13c 100644 --- a/assets/resources/application/zh.xml +++ b/assets/resources/application/zh.xml @@ -528,6 +528,7 @@ + diff --git a/assets/resources/application/zh_TW.xml b/assets/resources/application/zh_TW.xml index b7fe69fd1..5926d095e 100644 --- a/assets/resources/application/zh_TW.xml +++ b/assets/resources/application/zh_TW.xml @@ -547,6 +547,7 @@ + diff --git a/src/org/geometerplus/android/fbreader/DictionaryUtil.java b/src/org/geometerplus/android/fbreader/DictionaryUtil.java index 73680d3eb..1826f9448 100644 --- a/src/org/geometerplus/android/fbreader/DictionaryUtil.java +++ b/src/org/geometerplus/android/fbreader/DictionaryUtil.java @@ -165,6 +165,17 @@ public abstract class DictionaryUtil { } public static void openTextInDictionary(Activity activity, String text, boolean singleWord, int selectionTop, int selectionBottom) { + if (singleWord) { + int start = 0; + int end = text.length(); + for (; start < end && !Character.isLetterOrDigit(text.charAt(start)); ++start); + for (; start < end && !Character.isLetterOrDigit(text.charAt(end - 1)); --end); + if (start == end) { + return; + } + text = text.substring(start, end); + } + final PackageInfo info = getCurrentDictionaryInfo(singleWord); final Intent intent = getDictionaryIntent(info, text); try { @@ -190,17 +201,8 @@ public abstract class DictionaryUtil { } public static void openWordInDictionary(Activity activity, ZLTextWord word, ZLTextRegion region) { - final String text = word.toString(); - int start = 0; - int end = text.length(); - for (; start < end && !Character.isLetterOrDigit(text.charAt(start)); ++start); - for (; start < end && !Character.isLetterOrDigit(text.charAt(end - 1)); --end); - if (start == end) { - return; - } - openTextInDictionary( - activity, text.substring(start, end), true, region.getTop(), region.getBottom() + activity, word.toString(), true, region.getTop(), region.getBottom() ); } diff --git a/src/org/geometerplus/android/fbreader/SelectionPopup.java b/src/org/geometerplus/android/fbreader/SelectionPopup.java index bf76b8605..213629581 100644 --- a/src/org/geometerplus/android/fbreader/SelectionPopup.java +++ b/src/org/geometerplus/android/fbreader/SelectionPopup.java @@ -69,10 +69,10 @@ class SelectionPopup extends ButtonsPopupPanel { final int diffTop = screenHeight - selectionEndY; final int diffBottom = selectionStartY; if (diffTop > diffBottom) { - verticalPosition = diffTop > myWindow.getHeight() + 10 + verticalPosition = diffTop > myWindow.getHeight() + 20 ? RelativeLayout.ALIGN_PARENT_BOTTOM : RelativeLayout.CENTER_VERTICAL; } else { - verticalPosition = diffBottom > myWindow.getHeight() + 10 + verticalPosition = diffBottom > myWindow.getHeight() + 20 ? RelativeLayout.ALIGN_PARENT_TOP : RelativeLayout.CENTER_VERTICAL; } diff --git a/src/org/geometerplus/android/fbreader/SelectionTranslateAction.java b/src/org/geometerplus/android/fbreader/SelectionTranslateAction.java index 81c317233..3410751a6 100644 --- a/src/org/geometerplus/android/fbreader/SelectionTranslateAction.java +++ b/src/org/geometerplus/android/fbreader/SelectionTranslateAction.java @@ -29,10 +29,13 @@ public class SelectionTranslateAction extends FBAndroidAction { public void run() { final FBView fbview = Reader.getTextView(); - final int selectionStartY = fbview.getSelectionStartY(), selectionEndY = fbview.getSelectionEndY(); - final String text = fbview.getSelectedText(); - Reader.getTextView().clearSelection(); - DictionaryUtil.openTextInDictionary(BaseActivity, text, false, selectionStartY, selectionEndY); + DictionaryUtil.openTextInDictionary( + BaseActivity, + fbview.getSelectedText(), + fbview.getCountOfSelectedWords() == 1, + fbview.getSelectionStartY(), + fbview.getSelectionEndY() + ); + fbview.clearSelection(); } - } diff --git a/src/org/geometerplus/fbreader/fbreader/FBView.java b/src/org/geometerplus/fbreader/fbreader/FBView.java index f1ec94278..3066e6fa6 100644 --- a/src/org/geometerplus/fbreader/fbreader/FBView.java +++ b/src/org/geometerplus/fbreader/fbreader/FBView.java @@ -601,17 +601,27 @@ public final class FBView extends ZLTextView { @Override protected void releaseSelectionCursor() { super.releaseSelectionCursor(); - myReader.doAction(ActionCode.SELECTION_SHOW_PANEL); + if (getCountOfSelectedWords() > 0) { + myReader.doAction(ActionCode.SELECTION_SHOW_PANEL); + } } public String getSelectedText() { - final TextBuilderTraverser traverser = new TextBuilderTraverser(this); + final TextBuildTraverser traverser = new TextBuildTraverser(this); if (!isSelectionEmpty()) { traverser.traverse(getSelectionStartPosition(), getSelectionEndPosition()); } return traverser.getText(); } + public int getCountOfSelectedWords() { + final WordCountTraverser traverser = new WordCountTraverser(this); + if (!isSelectionEmpty()) { + traverser.traverse(getSelectionStartPosition(), getSelectionEndPosition()); + } + return traverser.getCount(); + } + public static final int SCROLLBAR_SHOW_AS_FOOTER = 3; @Override diff --git a/src/org/geometerplus/fbreader/fbreader/TextBuilderTraverser.java b/src/org/geometerplus/fbreader/fbreader/TextBuildTraverser.java similarity index 93% rename from src/org/geometerplus/fbreader/fbreader/TextBuilderTraverser.java rename to src/org/geometerplus/fbreader/fbreader/TextBuildTraverser.java index 9e9b8e405..bb37fbb50 100644 --- a/src/org/geometerplus/fbreader/fbreader/TextBuilderTraverser.java +++ b/src/org/geometerplus/fbreader/fbreader/TextBuildTraverser.java @@ -21,10 +21,10 @@ package org.geometerplus.fbreader.fbreader; import org.geometerplus.zlibrary.text.view.*; -class TextBuilderTraverser extends ZLTextTraverser { +class TextBuildTraverser extends ZLTextTraverser { protected final StringBuilder myBuffer = new StringBuilder(); - TextBuilderTraverser(ZLTextView view) { + TextBuildTraverser(ZLTextView view) { super(view); } diff --git a/src/org/geometerplus/fbreader/fbreader/WordCountTraverser.java b/src/org/geometerplus/fbreader/fbreader/WordCountTraverser.java new file mode 100644 index 000000000..50b395a94 --- /dev/null +++ b/src/org/geometerplus/fbreader/fbreader/WordCountTraverser.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2007-2011 Geometer Plus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +package org.geometerplus.fbreader.fbreader; + +import org.geometerplus.zlibrary.text.view.*; + +class WordCountTraverser extends ZLTextTraverser { + protected int myCount; + + WordCountTraverser(ZLTextView view) { + super(view); + } + + @Override + protected void processWord(ZLTextWord word) { + ++myCount; + } + + @Override + protected void processControlElement(ZLTextControlElement control) { + // does nothing + } + + @Override + protected void processSpace() { + // does nothing + } + + @Override + protected void processEndOfParagraph() { + // does nothing + } + + public int getCount() { + return myCount; + } +} diff --git a/src/org/geometerplus/zlibrary/text/view/ZLTextElementAreaVector.java b/src/org/geometerplus/zlibrary/text/view/ZLTextElementAreaVector.java index b4aff6df6..7400d9c38 100644 --- a/src/org/geometerplus/zlibrary/text/view/ZLTextElementAreaVector.java +++ b/src/org/geometerplus/zlibrary/text/view/ZLTextElementAreaVector.java @@ -29,9 +29,9 @@ final class ZLTextElementAreaVector { private ZLTextRegion myCurrentElementRegion; public void clear() { - myAreas.clear(); myElementRegions.clear(); myCurrentElementRegion = null; + myAreas.clear(); } public boolean isEmpty() { @@ -95,9 +95,11 @@ final class ZLTextElementAreaVector { if (soul == null) { return null; } - for (ZLTextRegion region : myElementRegions) { - if (soul.equals(region.getSoul())) { - return region; + synchronized (myElementRegions) { + for (ZLTextRegion region : myElementRegions) { + if (soul.equals(region.getSoul())) { + return region; + } } } return null; @@ -106,12 +108,14 @@ final class ZLTextElementAreaVector { ZLTextRegion findRegion(int x, int y, int maxDistance, ZLTextRegion.Filter filter) { ZLTextRegion bestRegion = null; int distance = maxDistance + 1; - for (ZLTextRegion region : myElementRegions) { - if (filter.accepts(region)) { - final int d = region.distanceTo(x, y); - if (d < distance) { - bestRegion = region; - distance = d; + synchronized (myElementRegions) { + for (ZLTextRegion region : myElementRegions) { + if (filter.accepts(region)) { + final int d = region.distanceTo(x, y); + if (d < distance) { + bestRegion = region; + distance = d; + } } } } @@ -119,88 +123,90 @@ final class ZLTextElementAreaVector { } protected ZLTextRegion nextRegion(ZLTextRegion currentRegion, ZLTextView.Direction direction, ZLTextRegion.Filter filter) { - if (myElementRegions.isEmpty()) { - return null; - } - - int index = currentRegion != null ? myElementRegions.indexOf(currentRegion) : -1; - - switch (direction) { - case rightToLeft: - case up: - if (index == -1) { - index = myElementRegions.size() - 1; - } else if (index == 0) { - return null; - } else { - --index; - } - break; - case leftToRight: - case down: - if (index == myElementRegions.size() - 1) { - return null; - } else { - ++index; - } - break; - } - - switch (direction) { - case rightToLeft: - for (; index >= 0; --index) { - final ZLTextRegion candidate = myElementRegions.get(index); - if (filter.accepts(candidate) && candidate.isAtLeftOf(currentRegion)) { - return candidate; - } - } - break; - case leftToRight: - for (; index < myElementRegions.size(); ++index) { - final ZLTextRegion candidate = myElementRegions.get(index); - if (filter.accepts(candidate) && candidate.isAtRightOf(currentRegion)) { - return candidate; - } - } - break; - case down: - { - ZLTextRegion firstCandidate = null; - for (; index < myElementRegions.size(); ++index) { - final ZLTextRegion candidate = myElementRegions.get(index); - if (!filter.accepts(candidate)) { - continue; - } - if (candidate.isExactlyUnder(currentRegion)) { - return candidate; - } - if (firstCandidate == null && candidate.isUnder(currentRegion)) { - firstCandidate = candidate; - } - } - if (firstCandidate != null) { - return firstCandidate; - } - break; + synchronized (myElementRegions) { + if (myElementRegions.isEmpty()) { + return null; } - case up: - ZLTextRegion firstCandidate = null; - for (; index >= 0; --index) { - final ZLTextRegion candidate = myElementRegions.get(index); - if (!filter.accepts(candidate)) { - continue; + + int index = currentRegion != null ? myElementRegions.indexOf(currentRegion) : -1; + + switch (direction) { + case rightToLeft: + case up: + if (index == -1) { + index = myElementRegions.size() - 1; + } else if (index == 0) { + return null; + } else { + --index; } - if (candidate.isExactlyOver(currentRegion)) { - return candidate; + break; + case leftToRight: + case down: + if (index == myElementRegions.size() - 1) { + return null; + } else { + ++index; } - if (firstCandidate == null && candidate.isOver(currentRegion)) { - firstCandidate = candidate; + break; + } + + switch (direction) { + case rightToLeft: + for (; index >= 0; --index) { + final ZLTextRegion candidate = myElementRegions.get(index); + if (filter.accepts(candidate) && candidate.isAtLeftOf(currentRegion)) { + return candidate; + } } + break; + case leftToRight: + for (; index < myElementRegions.size(); ++index) { + final ZLTextRegion candidate = myElementRegions.get(index); + if (filter.accepts(candidate) && candidate.isAtRightOf(currentRegion)) { + return candidate; + } + } + break; + case down: + { + ZLTextRegion firstCandidate = null; + for (; index < myElementRegions.size(); ++index) { + final ZLTextRegion candidate = myElementRegions.get(index); + if (!filter.accepts(candidate)) { + continue; + } + if (candidate.isExactlyUnder(currentRegion)) { + return candidate; + } + if (firstCandidate == null && candidate.isUnder(currentRegion)) { + firstCandidate = candidate; + } + } + if (firstCandidate != null) { + return firstCandidate; + } + break; } - if (firstCandidate != null) { - return firstCandidate; - } - break; + case up: + ZLTextRegion firstCandidate = null; + for (; index >= 0; --index) { + final ZLTextRegion candidate = myElementRegions.get(index); + if (!filter.accepts(candidate)) { + continue; + } + if (candidate.isExactlyOver(currentRegion)) { + return candidate; + } + if (firstCandidate == null && candidate.isOver(currentRegion)) { + firstCandidate = candidate; + } + } + if (firstCandidate != null) { + return firstCandidate; + } + break; + } } return null; } diff --git a/src/org/geometerplus/zlibrary/text/view/ZLTextHorizontalConvexHull.java b/src/org/geometerplus/zlibrary/text/view/ZLTextHorizontalConvexHull.java index ee1ab56a7..0cb5710cc 100644 --- a/src/org/geometerplus/zlibrary/text/view/ZLTextHorizontalConvexHull.java +++ b/src/org/geometerplus/zlibrary/text/view/ZLTextHorizontalConvexHull.java @@ -26,7 +26,7 @@ import org.geometerplus.zlibrary.core.view.ZLPaintContext; class ZLTextHorizontalConvexHull { private final LinkedList myRectangles = new LinkedList(); - ZLTextHorizontalConvexHull(List textAreas) { + ZLTextHorizontalConvexHull(ZLTextElementArea[] textAreas) { for (ZLTextElementArea area : textAreas) { addArea(area); } diff --git a/src/org/geometerplus/zlibrary/text/view/ZLTextRegion.java b/src/org/geometerplus/zlibrary/text/view/ZLTextRegion.java index 12fd35383..b159a018b 100644 --- a/src/org/geometerplus/zlibrary/text/view/ZLTextRegion.java +++ b/src/org/geometerplus/zlibrary/text/view/ZLTextRegion.java @@ -107,14 +107,16 @@ public final class ZLTextRegion { }; private final Soul mySoul; - private final List myList; + // this field must be accessed in synchronized context only + private final List myAreaList; + private ZLTextElementArea[] myAreas; private final int myFromIndex; private int myToIndex; private ZLTextHorizontalConvexHull myHull; ZLTextRegion(Soul soul, List list, int fromIndex) { mySoul = soul; - myList = list; + myAreaList = list; myFromIndex = fromIndex; myToIndex = fromIndex + 1; } @@ -128,8 +130,16 @@ public final class ZLTextRegion { return mySoul; } - private List textAreas() { - return myList.subList(myFromIndex, myToIndex); + private ZLTextElementArea[] textAreas() { + if (myAreas == null || myAreas.length != myToIndex - myFromIndex) { + synchronized (myAreaList) { + myAreas = new ZLTextElementArea[myToIndex - myFromIndex]; + for (int i = 0; i < myAreas.length; ++i) { + myAreas[i] = myAreaList.get(i + myFromIndex); + } + } + } + return myAreas; } private ZLTextHorizontalConvexHull convexHull() { if (myHull == null) { @@ -139,11 +149,12 @@ public final class ZLTextRegion { } ZLTextElementArea getFirstArea() { - return myList.get(myFromIndex); + return textAreas()[0]; } ZLTextElementArea getLastArea() { - return myList.get(myToIndex - 1); + final ZLTextElementArea[] areas = textAreas(); + return areas[areas.length - 1]; } public int getTop() { @@ -189,8 +200,8 @@ public final class ZLTextRegion { if (!isUnder(other)) { return false; } - final List areas0 = textAreas(); - final List areas1 = other.textAreas(); + final ZLTextElementArea[] areas0 = textAreas(); + final ZLTextElementArea[] areas1 = other.textAreas(); for (ZLTextElementArea i : areas0) { for (ZLTextElementArea j : areas1) { if (i.XStart <= j.XEnd && j.XStart <= i.XEnd) {