Package cz.cacek.ebook

Source Code of cz.cacek.ebook.View$Screen

/*
* View.java
*
* 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
* This was first modified no earlier than May 27, 2008.
*
*/

// Expand to define MIDP define
@DMIDPVERS@
// Expand to define test define
@DTESTDEF@
// Expand to define logging define
@DLOGDEF@

//#ifdef DMIDP20
package cz.cacek.ebook;

import java.io.EOFException;

import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

import cz.cacek.ebook.Page;

//#ifdef DLOGGING
import net.sf.jlogmicro.util.logging.Logger;
import net.sf.jlogmicro.util.logging.Level;
//#endif

/**
* Implementation of ebook content screen.
* @author Tom� Darmovzal [tomas.darmovzal (at) seznam.cz]
* @author Josef Cacek [josef.cacek (at) atlas.cz]
* @author $Author: ibuntonjr $
* @version $Revision: 1072 $
* @created $Date: 2008-08-02 12:45:29 +0800 (周六, 2008-08-02) $
*/
public class View extends AbstractView {
  protected Font font;
  protected StringBuffer buffer;
  protected Page page;
  protected int position;
  protected int[] charWidths;

  //#ifdef DLOGGING
    private Logger logger = Logger.getLogger("View");
    private boolean fineLoggable = logger.isLoggable(Level.FINE);
    private boolean finestLoggable = logger.isLoggable(Level.FINEST);
  //#endif

  private Screen screen;

    /**
     * Class Screen holds lines which are currently displayed on the screen.
     * Class is synchronized.<p/>
     * Instances of this class are created during LCD-screen font change.
     * @author Josef Cacek [josef.cacek (at) atlas.cz]
     * @author $Author: ibuntonjr $
     * @version $Revision: 1072 $
     * @created $Date: 2008-08-02 12:45:29 +0800 (周六, 2008-08-02) $
     */
  static class Screen {
    private int positions[];
    private String content[];

    /**
         * Creates new screen object
     * @param aLines
     */
    public Screen(int aLines) {
      positions = new int[aLines+1];
      content = new String[aLines];
    }
   
    /**
         * Returns count of rows displayed on screen.
     * @return count of rows displayed on screen
     */
    public int size() {
      synchronized(this) {
        return content.length;
      }
    }
   
    /**
         * Returns position (in page) of first character displayed on given line.
     * @param aLine line for which is position returned
     * @return position of line in page
     */
    public int getPosition(int aLine) {
      synchronized(this) {
        return positions[aLine];
      }
    }

    /**
         * Sets position of line
     * @param aLine
     * @param aPos
     */
    public void setPosition(int aLine, int aPos) {
      synchronized(this) {
        positions[aLine] = aPos;
      }
    }

    /**
         * Returns string displayed in given row.
     * @param aLine index of row
     * @return string displayed in given row
     */
    public String getContent(int aLine) {
      synchronized(this) {
        return content[aLine];
      }
    }

    /**
         * Sets string to display in given line
     * @param aLine index of row
     * @param aStr
     */
    public void setContent(int aLine, String aStr) {
      synchronized(this) {
        content[aLine] = aStr;
      }
    }
   
    /**
         * Rolls positions and content forward and adds new line. First displayed line
         * is deleted (rolled out).
         * to the end.
     * @param aLine new line
     * @param aNewPosition position of new line (position in page)
     */
    void rollFw(String aLine, int aNewPosition) {
      synchronized(this) {
        for (int i=0; i<content.length-1; i++) {
          content[i] = content[i + 1];
          positions[i] = positions[i + 1];
        }
        positions[content.length - 1] = positions[content.length];
        content[content.length - 1] = aLine;
        positions[positions.length - 1] = aNewPosition;
      }
    }

    /**
         * Rolls backward, new line (given as parameter) is added to the beginning.
     * @param aLine new line
     * @param aNewPosition
         * @see #rollFw(String, int)
     */
    void rollBw(String aLine, int aNewPosition) {
      synchronized(this) {
        positions[content.length] = positions[content.length - 1];
        for (int i = content.length - 1; i > 0; i--) {
          content[i] = content[i - 1];
          positions[i] = positions[i - 1];
        }
        content[0] = aLine;
        positions[0] = aNewPosition;
      }
    }

  }

  /**
   * Constructor for doing estimateHeight, and regular constructor
   * @throws Exception
   */
  private View() throws Exception {
    super.init();
    buffer = new StringBuffer(256);
    charWidths = new int[256];
  }

  /**
   * Constructor
   * @param aWidth
   * @param aHeight
   * @throws Exception
   */
  public View(int aWidth, int aHeight, int aFontSize)
  throws Exception {
    this();
    super.initView(aWidth, aHeight, aFontSize);
    buffer = new StringBuffer(256);
    charWidths = new int[256];
    //#ifdef DLOGGING
    if (finestLoggable) {logger.finest("new View aWidth,aHeight=" + aWidth + "," + aHeight);}
    //#endif
  }

  /**
   * Constructor
   * @param aWidth
   * @param aHeight
   * @throws Exception
   */
  public View(int aWidth, int aHeight, int aFontSize,
          boolean aUnderlinedStyle)
    throws Exception {
    this(aWidth, aHeight, aFontSize);
    setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN |
          (aUnderlinedStyle ? Font.STYLE_UNDERLINED : 0),
        aFontSize));
  }

  /**
   * Sets active page for view.
   * @param aPage
   */
  public void setPage(Page aPage) {
    page = aPage;
        setPosition(page.getPosition());
        fillPage();
  }

  /**
   * Set to be the first of the page
   *
   * @author Irv Bunton
   */
  public void setFirst() {
    setPosition(0);
  }

  /**
   * Sets font for view
   * @param aFont
   * @throws Exception
   */
  public void setFont(Font aFont) throws Exception {
    font = aFont;
    int tmpLines = (height - (2 * borderSpace))
        / (font.getHeight() + lineSpace);
    screen = new Screen(tmpLines);
    for (int i = 0; i < charWidths.length; i++) {
      charWidths[i] = font.charWidth((char) i);
    }
    if (page != null) {
      fillPage();
    }
  }

  /**
   * Returns font
   * @return font
   */
  public Font getFont() {
    return font;
  }

  /**
   * Sets position in active page in characters
   * @param aPos
   */
  private void setPosition(int aPos) {
    position = aPos;
    page.setPosition(position);
  }

  /**
   * Sets position in active page in percents
   * @param aPerc
   */
  public void setPercPosition(int aPerc) {
    setPosition((page.size - 1) * aPerc / 100);
  }

  /**
   * Returns current position as a percentige of page.
   *
   * @return current position as a percentige of page
   */
  public int getPercPosition() {
    return position * 100 / (page.size - 1);
  }
 
  /**
   * Moves view one page ahead
   * @throws Exception
   */
  public void fwdPage() throws Exception {
    position = screen.getPosition(screen.size());
    fillPage();
  }

  /**
   * Moves view one page back
   * @throws Exception
   */
  public void bckPage() throws Exception {
    for (int i = 0, n=screen.size(); i < n; i++) {
      bckLine();
    }
  }

  /**
   * Moves view one line ahead
   * @throws Exception
   * @return true if scrolling is succesfull
   */
  public boolean fwdLine() throws Exception {
    synchronized(this) {
      //#ifdef DTEST
      Common.debug("fwdLine() started");
      //#endif
      page.setPosition(screen.getPosition(screen.size()));
      final String tmpLine = nextLine();
      final boolean tmpResult = tmpLine != null;
      if (tmpResult) {
        screen.rollFw(tmpLine, page.getPosition());
        position = screen.getPosition(0);
      }
      //#ifdef DTEST
      Common.debug("fwdLine() finished ("+tmpResult+")");
      //#endif
      return tmpResult;
    }
  }

  /**
   * Moves view one line back
   * @throws Exception
   */
  public void bckLine() throws Exception {
    synchronized(this) {
      page.setPosition(screen.getPosition(0) - 1);
      String line = prevLine();
      if (line != null) {
        screen.rollBw(line, page.getPosition() + 1);
        position = screen.getPosition(0);
      }
    }
  }

  /**
   * fills page from current position
   */
  public void fillPage() {
    //#ifdef DTEST
    Common.debug("fillPage() started");
    //#endif
    page.setPosition(position);
    screen.setPosition(0, position);
    try {
      for (int i = 0, n=screen.size(); i < n; i++) {
        screen.setContent(i, nextLine());
        screen.setPosition(i + 1, page.getPosition());
        //#ifdef DLOGGING
        if (finestLoggable) {logger.finest("fillPage i,content=" + i + "," + screen.getContent(i));}
        //#endif
      }
    } catch (Exception e) {
      throw handleError("fillPage", e);
    }
    //#ifdef DTEST
    Common.debug("fillPage() finished");
    //#endif
  }

  /**
   * check if page empty
   */
  public boolean emptyPage() {
    //#ifdef DTEST
    Common.debug("emptyPage() started");
    //#endif
    if(page.getPosition() >= page.size) {
      try {
        for (int i = 0, n=screen.size(); i < n; i++) {
          if (screen.getContent(i) != null) {
            return false;
          }
        }
        //#ifdef DTEST
        Common.debug("emptyPage() finished");
        //#endif
        return true;
      } catch (Exception e) {
        throw handleError("emptyPage", e);
      }
    }
    //#ifdef DTEST
    Common.debug("emptyPage() finished");
    //#endif
    return false;
  }

  /**
   * Estimate height
   */
  final public static int estimateHeight(int aFontSize,
                       boolean aUnderlinedStyle,
                       int aWidth,
                       int aMaxHeight,
                               Page aPage)
  throws Exception {
    //#ifdef DTEST
    Common.debug("estimateHeight() started");
    //#endif
    //#ifdef DLOGGING
    Logger logger = Logger.getLogger("View");
    boolean finestLoggable = logger.isLoggable(Level.FINEST);
    //#endif
    View view = new View();
    view.width = aWidth;
    view.height = aMaxHeight;
    view.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN |
          (aUnderlinedStyle ? Font.STYLE_UNDERLINED : 0),
        aFontSize));
    view.page = aPage;
    int svpos = aPage.getPosition();
    aPage.setPosition(0);
        view.setPosition(0);
    try {
      int count = 0;
      /* Use some upper limit to prevent an infinate loop. */
      int maxLines = (aMaxHeight > 0) ? (2 * view.screen.size()) :
        (aPage.size / 80);
      //#ifdef DLOGGING
      String line;
      for (; ((maxLines == 0) || (count < maxLines)) &&
          ((line = view.nextLine()) != null); count++) {
        //#ifdef DLOGGING
        if (finestLoggable) {logger.finest("estimateHeight count,line=" + count + "," + line);}
        //#endif
      }
      //#else
      for (; ((maxLines == 0) || (count < maxLines)) &&
          (view.nextLine() != null); count++) {
      }
      //#endif
      //#ifdef DTEST
      Common.debug("estimateHeight() finished");
      //#endif
      aPage.setPosition(svpos);
      return ((count * (view.font.getHeight() + view.lineSpace)) +
          (2 * view.borderSpace));
    } catch (Exception e) {
      throw handleError("estimateHeight", e);
    } catch (Throwable e) {
      throw handleError("estimateHeight", e);
    }
  }

  /**
   * Reads and returns next line for view.
   * @return next line
   * @throws Exception
   */
  protected String nextLine() throws Exception {
    if(page.getPosition() >= page.size) {
      return null;
    }
    int len = 0;
    // First place of white space
    int ws = -1;
    int index = 0;
    int actWidth = width - (2 * borderSpace) - scrollWidth;
    boolean eof = false;
    buffer.setLength(0);
    for(;;){
      char c;
      try {
        c = page.readNext();
      } catch (EOFException e){
        eof = true;
        break;
      }
      // Change tabs to single space
      if(c == '\t') c = ' ';
      // If \r or line begins with spaces, go to next char without
      // saving.
      if(c == '\r' || (c == ' ' && index==0)) continue;
      // If line feed, end the line.
      if(c == '\n') break;
      // Save white space index
      if(c == ' ') ws = index;
      len += charWidth(c);
      if(len > actWidth){
        //#ifdef DLOGGING
        if (finestLoggable) {logger.finest("c,len,ws,actWidth,index=" + c + "," + len + "," + ws + "," + actWidth + "," + index);}
        //#endif
        // Read prev will give EOFException if at the end of the page
        // or the beginning.  In this case if we get it, we are at
        // the end.
        try {
          page.readPrev();
        } catch (EOFException e) {
          eof = true;
          page.setPosition(page.size - 1);
          break;
        }
        if((ws != -1) && wrapSpaces){
          int discard = index - ws - 1;
          for(int i = 0; i < discard; i++) {
            page.readPrev();
          }
          index = ws;
          buffer.setLength(index);
        }
        break;
      }
      buffer.append(c);
      index++;
    }
    if (eof && index == 0) {
      return null;
    }
    return (buffer.toString()).trim();
  }

  /**
   * Reads and returns previous line. (backward reading)
   * @return previous line
   * @throws Exception
   */
  protected String prevLine() throws Exception {
    if (page.getPosition() <= 0)
      return null;
    int len = 0;
    int ws = -1;
    int index = 0;
    boolean eof = false;
    buffer.setLength(0);
    for (;;) {
      char c;
      try {
        c = page.readPrev();
      } catch (EOFException e) {
        eof = true;
        break;
      }
      if (c == '\t') c = ' ';
      if (c == '\r' || (c==' ' && index==0)) continue;
      if (c == '\n') break;
      if (c == ' ') ws = index;
      len += charWidth(c);
      if (len > width - (2 * borderSpace) - scrollWidth) {
        page.readNext();
        if ((ws != -1) && wrapSpaces) {
          int discard = index - ws - 1;
          for (int i = 0; i < discard; i++) {
            page.readNext();
          }
          index = ws;
          buffer.setLength(index);
        }
        break;
      }
      buffer.append(c);
      index++;
    }
    if (eof && index==0) {
      return null;     
    }
    buffer.reverse();
    return (buffer.toString()).trim();
  }

  /**
   * returns width of given character for current font
   *
   * @param aChr character
   * @return width of given character
   */
  protected int charWidth(char aChr) {
    return (aChr < 256)?charWidths[aChr]:font.charWidth(aChr);
  }

  // Draw text
  protected void drawText(Graphics g) {
    g.setColor(foreground);
    g.setFont(font);
    //#ifdef DLOGGING
    if (finestLoggable) {logger.finest("screen.size()=" + screen.size());}
    //#endif
    int pos = 0;
    for (int i=0, n=screen.size(); i < n; i++) {
      String line = screen.getContent(i);
      //#ifdef DLOGGING
      if (finestLoggable) {logger.finest("draw i,line=" + i + "," + line);}
      //#endif
      if (line != null)
        g.drawString(line, borderSpace, borderSpace + pos,
            Graphics.LEFT | Graphics.TOP);
      pos += font.getHeight() + lineSpace;
    }
  }

    /**
     * Returns position of first character on screen of current view.
     * @return current position of view
     */
    public int getPosition() {
        return screen==null?0:screen.getPosition(0);
    }

    /**
     * @return Returns true if there is another page, false otherwise
     */
    public boolean isLastPage() {
        return page.getPosition() >= page.size;
    }

    /**
     * Log the error and throw an exception.
     */
  final private static RuntimeException handleError(String method,
      Throwable e) {
    Common.debugErr(e.getMessage());
    //#ifdef DLOGGING
    Logger logger = Logger.getLogger("View");
    logger.severe(method + " ", e);
    //#endif
    return new RuntimeException(e.getMessage());
  }

  protected int getScrollPosition(int height, int scrollHeight) {
    return (height-scrollHeight) * page.getPosition() / page.size;
  }
}
//#endif
TOP

Related Classes of cz.cacek.ebook.View$Screen

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.