gt: 		final ColorProfile profile = myViewOptions.getColorProfile();
context: /*
   * Copyright (C) 2007-2014 Geometer Plus <contact@geometerplus.com>
   *
   * 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.fbreader.bookmodel.BookModel;
  import org.geometerplus.fbreader.bookmodel.FBHyperlinkType;
  import org.geometerplus.fbreader.bookmodel.TOCTree;
  import org.geometerplus.fbreader.fbreader.options.ColorProfile;
  import org.geometerplus.fbreader.fbreader.options.FooterOptions;
  import org.geometerplus.fbreader.fbreader.options.ImageOptions;
  import org.geometerplus.fbreader.fbreader.options.MiscOptions;
  import org.geometerplus.fbreader.fbreader.options.PageTurningOptions;
  import org.geometerplus.fbreader.fbreader.options.ViewOptions;
  import org.geometerplus.zlibrary.core.filesystem.ZLFile;
  import org.geometerplus.zlibrary.core.filesystem.ZLResourceFile;
  import org.geometerplus.zlibrary.core.fonts.FontEntry;
  import org.geometerplus.zlibrary.core.library.ZLibrary;
  import org.geometerplus.zlibrary.core.util.ZLColor;
  import org.geometerplus.zlibrary.core.view.ZLPaintContext;
  import org.geometerplus.zlibrary.text.model.ZLTextModel;
  import org.geometerplus.zlibrary.text.view.ZLTextHighlighting;
  import org.geometerplus.zlibrary.text.view.ZLTextHyperlink;
  import org.geometerplus.zlibrary.text.view.ZLTextHyperlinkRegionSoul;
  import org.geometerplus.zlibrary.text.view.ZLTextImageRegionSoul;
  import org.geometerplus.zlibrary.text.view.ZLTextRegion;
  import org.geometerplus.zlibrary.text.view.ZLTextSelectionCursor;
  import org.geometerplus.zlibrary.text.view.ZLTextVideoRegionSoul;
  import org.geometerplus.zlibrary.text.view.ZLTextView;
  import org.geometerplus.zlibrary.text.view.ZLTextWordRegionSoul;
  import org.geometerplus.zlibrary.text.view.style.ZLTextStyleCollection;
  
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.List;
  
  public final class FBView extends ZLTextView {
  	private final FBReaderApp myReader;
  	private final ViewOptions myViewOptions;
  
  	FBView(FBReaderApp reader) {
  		super(reader);
  		myReader = reader;
  		myViewOptions = reader.ViewOptions;
  	}
  
  	public void setModel(ZLTextModel model) {
  		super.setModel(model);
  		if (myFooter != null) {
  			myFooter.resetTOCMarks();
  		}
  	}
  
  	private int myStartY;
  	private boolean myIsBrightnessAdjustmentInProgress;
  	private int myStartBrightness;
  
  	private TapZoneMap myZoneMap;
  
  	private TapZoneMap getZoneMap() {
  		final PageTurningOptions prefs = myReader.PageTurningOptions;
  		String id = prefs.TapZoneMap.getValue();
  		if ("".equals(id)) {
  			id = prefs.Horizontal.getValue() ? "right_to_left" : "up";
  		}
  		if (myZoneMap == null || !id.equals(myZoneMap.Name)) {
  			myZoneMap = TapZoneMap.zoneMap(id);
  		}
  		return myZoneMap;
  	}
  
  	public boolean onFingerSingleTap(int x, int y) {
  		if (super.onFingerSingleTap(x, y)) {
  			return true;
  		}
  
  		final ZLTextRegion hyperlinkRegion = findRegion(x, y, MAX_SELECTION_DISTANCE, ZLTextRegion.HyperlinkFilter);
  		if (hyperlinkRegion != null) {
  			selectRegion(hyperlinkRegion);
  			myReader.getViewWidget().reset();
  			myReader.getViewWidget().repaint();
  			myReader.runAction(ActionCode.PROCESS_HYPERLINK);
  			return true;
  		}
  
  		final ZLTextRegion videoRegion = findRegion(x, y, 0, ZLTextRegion.VideoFilter);
  		if (videoRegion != null) {
  			selectRegion(videoRegion);
  			myReader.getViewWidget().reset();
  			myReader.getViewWidget().repaint();
  			myReader.runAction(ActionCode.OPEN_VIDEO, (ZLTextVideoRegionSoul)videoRegion.getSoul());
  			return true;
  		}
  
  		final ZLTextHighlighting highlighting = findHighlighting(x, y, MAX_SELECTION_DISTANCE);
  		if (highlighting instanceof BookmarkHighlighting) {
  			myReader.runAction(
  				ActionCode.SELECTION_BOOKMARK,
  				((BookmarkHighlighting)highlighting).Bookmark
  			);
  			return true;
  		}
  
  		myReader.runAction(getZoneMap().getActionByCoordinates(
  			x, y, getContextWidth(), getContextHeight(),
  			isDoubleTapSupported() ? TapZoneMap.Tap.singleNotDoubleTap : TapZoneMap.Tap.singleTap
  		), x, y);
  
  		return true;
  	}
  
  	@Override
  	public boolean isDoubleTapSupported() {
  		return myReader.MiscOptions.EnableDoubleTap.getValue();
  	}
  
  	@Override
  	public boolean onFingerDoubleTap(int x, int y) {
  		if (super.onFingerDoubleTap(x, y)) {
  			return true;
  		}
  		myReader.runAction(getZoneMap().getActionByCoordinates(
  			x, y, getContextWidth(), getContextHeight(), TapZoneMap.Tap.doubleTap
  		), x, y);
  		return true;
  	}
  
  	public boolean onFingerPress(int x, int y) {
  		if (super.onFingerPress(x, y)) {
  			return true;
  		}
  
  		final ZLTextSelectionCursor cursor = findSelectionCursor(x, y, MAX_SELECTION_DISTANCE);
  		if (cursor != ZLTextSelectionCursor.None) {
  			myReader.runAction(ActionCode.SELECTION_HIDE_PANEL);
  			moveSelectionCursorTo(cursor, x, y);
  			return true;
  		}
  
  		if (myReader.MiscOptions.AllowScreenBrightnessAdjustment.getValue() && x < getContextWidth() / 10) {
  			myIsBrightnessAdjustmentInProgress = true;
  			myStartY = y;
  			myStartBrightness = ZLibrary.Instance().getScreenBrightness();
  			return true;
  		}
  
  		startManualScrolling(x, y);
  		return true;
  	}
  
  	private boolean isFlickScrollingEnabled() {
  		final PageTurningOptions.FingerScrollingType fingerScrolling =
  			myReader.PageTurningOptions.FingerScrolling.getValue();
  		return
  			fingerScrolling == PageTurningOptions.FingerScrollingType.byFlick ||
  			fingerScrolling == PageTurningOptions.FingerScrollingType.byTapAndFlick;
  	}
  
  	private void startManualScrolling(int x, int y) {
  		if (!isFlickScrollingEnabled()) {
  			return;
  		}
  
  		final boolean horizontal = myReader.PageTurningOptions.Horizontal.getValue();
  		final Direction direction = horizontal ? Direction.rightToLeft : Direction.up;
  		myReader.getViewWidget().startManualScrolling(x, y, direction);
  	}
  
  	public boolean onFingerMove(int x, int y) {
  		if (super.onFingerMove(x, y)) {
  			return true;
  		}
  
  		final ZLTextSelectionCursor cursor = getSelectionCursorInMovement();
  		if (cursor != ZLTextSelectionCursor.None) {
  			moveSelectionCursorTo(cursor, x, y);
  			return true;
  		}
  
  		synchronized (this) {
  			if (myIsBrightnessAdjustmentInProgress) {
  				if (x >= getContextWidth() / 5) {
  					myIsBrightnessAdjustmentInProgress = false;
  					startManualScrolling(x, y);
  				} else {
  					final int delta = (myStartBrightness + 30) * (myStartY - y) / getContextHeight();
  					ZLibrary.Instance().setScreenBrightness(myStartBrightness + delta);
  					return true;
  				}
  			}
  
  			if (isFlickScrollingEnabled()) {
  				myReader.getViewWidget().scrollManuallyTo(x, y);
  			}
  		}
  		return true;
  	}
  
  	public boolean onFingerRelease(int x, int y) {
  		if (super.onFingerRelease(x, y)) {
  			return true;
  		}
  
  		final ZLTextSelectionCursor cursor = getSelectionCursorInMovement();
  		if (cursor != ZLTextSelectionCursor.None) {
  			releaseSelectionCursor();
  			return true;
  		}
  
  		if (myIsBrightnessAdjustmentInProgress) {
  			myIsBrightnessAdjustmentInProgress = false;
  			return true;
  		}
  
  		if (isFlickScrollingEnabled()) {
  			myReader.getViewWidget().startAnimatedScrolling(
  				x, y, myReader.PageTurningOptions.AnimationSpeed.getValue()
  			);
  			return true;
  		}
  
  		return true;
  	}
  
  	public boolean onFingerLongPress(int x, int y) {
  		if (super.onFingerLongPress(x, y)) {
  			return true;
  		}
  
  		final ZLTextRegion region = findRegion(x, y, MAX_SELECTION_DISTANCE, ZLTextRegion.AnyRegionFilter);
  		if (region != null) {
  			final ZLTextRegion.Soul soul = region.getSoul();
  			boolean doSelectRegion = false;
  			if (soul instanceof ZLTextWordRegionSoul) {
  				switch (myReader.MiscOptions.WordTappingAction.getValue()) {
  					case startSelecting:
  						myReader.runAction(ActionCode.SELECTION_HIDE_PANEL);
  						initSelection(x, y);
  						final ZLTextSelectionCursor cursor = findSelectionCursor(x, y);
  						if (cursor != ZLTextSelectionCursor.None) {
  							moveSelectionCursorTo(cursor, x, y);
  						}
  						return true;
  					case selectSingleWord:
  					case openDictionary:
  						doSelectRegion = true;
  						break;
  				}
  			} else if (soul instanceof ZLTextImageRegionSoul) {
  				doSelectRegion =
  					myReader.ImageOptions.TapAction.getValue() !=
  					ImageOptions.TapActionEnum.doNothing;
  			} else if (soul instanceof ZLTextHyperlinkRegionSoul) {
  				doSelectRegion = true;
  			}
  
  			if (doSelectRegion) {
  				selectRegion(region);
  				myReader.getViewWidget().reset();
  				myReader.getViewWidget().repaint();
  				return true;
  			}
  		}
  
  		return false;
  	}
  
  	public boolean onFingerMoveAfterLongPress(int x, int y) {
  		if (super.onFingerMoveAfterLongPress(x, y)) {
  			return true;
  		}
  
  		final ZLTextSelectionCursor cursor = getSelectionCursorInMovement();
  		if (cursor != ZLTextSelectionCursor.None) {
  			moveSelectionCursorTo(cursor, x, y);
  			return true;
  		}
  
  		ZLTextRegion region = getSelectedRegion();
  		if (region != null) {
  			ZLTextRegion.Soul soul = region.getSoul();
  			if (soul instanceof ZLTextHyperlinkRegionSoul ||
  				soul instanceof ZLTextWordRegionSoul) {
  				if (myReader.MiscOptions.WordTappingAction.getValue() !=
  					MiscOptions.WordTappingActionEnum.doNothing) {
  					region = findRegion(x, y, MAX_SELECTION_DISTANCE, ZLTextRegion.AnyRegionFilter);
  					if (region != null) {
  						soul = region.getSoul();
  						if (soul instanceof ZLTextHyperlinkRegionSoul
  							 || soul instanceof ZLTextWordRegionSoul) {
  							selectRegion(region);
  							myReader.getViewWidget().reset();
  							myReader.getViewWidget().repaint();
  						}
  					}
  				}
  			}
  		}
  		return true;
  	}
  
  	public boolean onFingerReleaseAfterLongPress(int x, int y) {
  		if (super.onFingerReleaseAfterLongPress(x, y)) {
  			return true;
  		}
  
  		final ZLTextSelectionCursor cursor = getSelectionCursorInMovement();
  		if (cursor != ZLTextSelectionCursor.None) {
  			releaseSelectionCursor();
  			return true;
  		}
  
  		final ZLTextRegion region = getSelectedRegion();
  		if (region != null) {
  			final ZLTextRegion.Soul soul = region.getSoul();
  
  			boolean doRunAction = false;
  			if (soul instanceof ZLTextWordRegionSoul) {
  				doRunAction =
  					myReader.MiscOptions.WordTappingAction.getValue() ==
  					MiscOptions.WordTappingActionEnum.openDictionary;
  			} else if (soul instanceof ZLTextImageRegionSoul) {
  				doRunAction =
  					myReader.ImageOptions.TapAction.getValue() ==
  					ImageOptions.TapActionEnum.openImageView;
  			}
  
  			if (doRunAction) {
  				myReader.runAction(ActionCode.PROCESS_HYPERLINK);
  				return true;
  			}
  		}
  
  		return false;
  	}
  
  	public boolean onTrackballRotated(int diffX, int diffY) {
  		if (diffX == 0 && diffY == 0) {
  			return true;
  		}
  
  		final Direction direction = (diffY != 0) ?
  			(diffY > 0 ? Direction.down : Direction.up) :
  			(diffX > 0 ? Direction.leftToRight : Direction.rightToLeft);
  
  		new MoveCursorAction(myReader, direction).run();
  		return true;
  	}
  
  	@Override
  	public ZLTextStyleCollection getTextStyleCollection() {
  		return myViewOptions.getTextStyleCollection();
  	}
  
  	@Override
  	public ImageFitting getImageFitting() {
  		return myReader.ImageOptions.FitToScreen.getValue();
  	}
  
  	@Override
  	public int getLeftMargin() {
  		return myViewOptions.LeftMargin.getValue();
  	}
  
  	@Override
  	public int getRightMargin() {
  		return myViewOptions.RightMargin.getValue();
  	}
  
  	@Override
  	public int getTopMargin() {
  		return myViewOptions.TopMargin.getValue();
  	}
  
  	@Override
  	public int getBottomMargin() {
  		return myViewOptions.BottomMargin.getValue();
  	}
  
  	@Override
  	public int getSpaceBetweenColumns() {
  		return myViewOptions.SpaceBetweenColumns.getValue();
  	}
  
  	@Override
  	public boolean twoColumnView() {
  		return getContextHeight() <= getContextWidth() && myViewOptions.TwoColumnView.getValue();
  	}
  
  	@Override
  	public ZLFile getWallpaperFile() {
  		final String filePath = myViewOptions.getColorProfile().WallpaperOption.getValue();
  		if ("".equals(filePath)) {
  			return null;
  		}
  
  		final ZLFile file = ZLFile.createFileByPath(filePath);
  		if (file == null || !file.exists()) {
  			return null;
  		}
  		return file;
  	}
  
  	@Override
  	public ZLPaintContext.FillMode getFillMode() {
  		return getWallpaperFile() instanceof ZLResourceFile
  			? ZLPaintContext.FillMode.tileMirror
  			: myViewOptions.getColorProfile().FillModeOption.getValue();
  	}
  
  	@Override
  	public ZLColor getBackgroundColor() {
  		return myViewOptions.getColorProfile().BackgroundOption.getValue();
  	}
  
  	@Override
  	public ZLColor getSelectionBackgroundColor() {
  		return myViewOptions.getColorProfile().SelectionBackgroundOption.getValue();
  	}
  
  	@Override
  	public ZLColor getSelectionForegroundColor() {
  		return myViewOptions.getColorProfile().SelectionForegroundOption.getValue();
  	}
  
  	@Override
  	public ZLColor getTextColor(ZLTextHyperlink hyperlink) {
  