/* The MIT License (MIT) Copyright (c) 2013, V. Giacometti, M. Giuriato, B. Petrantuono Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package it.angrydroids.epub3reader; import java.io.IOException; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.util.Log; import android.webkit.WebViewClient; public class EpubNavigator extends WebViewClient { // TODO: generalize private EpubManipulator book1; private EpubManipulator book2; // TODO: better logic private boolean atLeastOneBookOpen; private boolean exactlyOneBookOpen; private boolean synchronizedReadingActive; private boolean parallelText = false; private String pageOnView1; private String pageOnView2; private static Context context; public EpubNavigator(Context theContext) { atLeastOneBookOpen = false; exactlyOneBookOpen = true; synchronizedReadingActive = false; pageOnView1 = ""; pageOnView2 = ""; if (context == null) { context = theContext; } } public boolean openBook1(String path) { try { // if a book is already open, deletes it if (book1 != null) book1.destroy(); parallelText = false; book1 = new EpubManipulator(path, "1", context); setView1(book1.getSpineElementPath(0)); atLeastOneBookOpen = true; book1.createTocFile(); return true; } catch (Exception e) { return false; } } public boolean openBook2(String path) { try { if (book2 != null) book2.destroy(); parallelText = false; book2 = new EpubManipulator(path, "2", context); setView2(book2.getSpineElementPath(0)); book2.createTocFile(); exactlyOneBookOpen = false; return true; } catch (Exception e) { return false; } } public boolean parallelText(BookEnum which, int firstLanguage, int secondLanguage) { boolean ok = true; if (firstLanguage != -1) { try { if (which != BookEnum.first) { openBook1(book2.getFileName()); book1.goToPage(book2.getCurrentSpineElementIndex()); } book1.setLanguage(firstLanguage); setView1(book1.getCurrentPageURL()); } catch (Exception e) { ok = false; } } if (secondLanguage != -1) { try { if (which != BookEnum.second) { openBook2(book1.getFileName()); book2.goToPage(book1.getCurrentSpineElementIndex()); } book2.setLanguage(secondLanguage); setView2(book2.getCurrentPageURL()); } catch (Exception e) { ok = false; } } if (ok && firstLanguage != -1 && secondLanguage != -1) setSynchronizedReadingActive(true); parallelText = true; return ok; } public String[] getLanguagesBook1() { return book1.getLanguages(); } public String[] getLanguagesBook2() { return book2.getLanguages(); } // if synchronized reading is active, change chapter in both books public void goToNextChapter(BookEnum which) throws Exception { if ((synchronizedReadingActive) || (which == BookEnum.first)) setView1(book1.goToNextChapter()); if ((synchronizedReadingActive) || (which == BookEnum.second)) setView2(book2.goToNextChapter()); } // if synchronized reading is active, change chapter in both books public void goToPrevChapter(BookEnum which) throws Exception { if ((synchronizedReadingActive) || (which == BookEnum.first)) setView1(book1.goToPreviousChapter()); if ((synchronizedReadingActive) || (which == BookEnum.second)) setView2(book2.goToPreviousChapter()); } public ViewStateEnum loadPageIntoView1(String pathOfPage) { EpubReaderMain.getView1().loadUrl(pathOfPage); if ((book1 != null) && ((pathOfPage.equals(book1.getCurrentPageURL())) || (book1 .getPageIndex(pathOfPage) >= 0))) return ViewStateEnum.books; else return ViewStateEnum.notes; } public ViewStateEnum loadPageIntoView2(String pathOfPage) { EpubReaderMain.getView2().loadUrl(pathOfPage); if ((book2 != null) && ((pathOfPage.equals(book1.getCurrentPageURL())) || (book2 .getPageIndex(pathOfPage) >= 0))) return ViewStateEnum.books; else return ViewStateEnum.notes; } public ViewStateEnum closeView1() { // book mode? if ((book1.getPageIndex(pageOnView1) >= 0) || (pageOnView1.equals(book1.getCurrentPageURL()))) { // book mode: delete it try { book1.destroy(); } catch (Exception e) { } if ((exactlyOneBookOpen) || (book2 == null)) { // no second book open atLeastOneBookOpen = false; // There is no longer any open book return ViewStateEnum.invisible; // and the first view must be // closed } else { // second book open // the former book2 now becomes book1 book1 = book2; book2 = null; pageOnView1 = pageOnView2; pageOnView2 = ""; exactlyOneBookOpen = true; setSynchronizedReadingActive(false); return loadPageIntoView1(pageOnView1); } } else { // note mode: go back to book mode pageOnView1 = book1.getCurrentPageURL(); loadPageIntoView1(book1.getCurrentPageURL()); return ViewStateEnum.books; } } public ViewStateEnum closeView2() { // book mode? if ((book2 == null) || (book2.getPageIndex(pageOnView2) >= 0) || (pageOnView2.equals(book2.getCurrentPageURL()))) { // book mode: delete it try { book2.destroy(); } catch (Exception e) { } exactlyOneBookOpen = true; return ViewStateEnum.invisible; } else { // note mode: go back to book mode pageOnView2 = book2.getCurrentPageURL(); loadPageIntoView2(book2.getCurrentPageURL()); return ViewStateEnum.books; } } public void setSynchronizedReadingActive(boolean value) { synchronizedReadingActive = value; } public boolean flipSynchronizedReadingActive() { if (exactlyOneBookOpen) return false; synchronizedReadingActive = !synchronizedReadingActive; return true; } public boolean synchronizeView2WithView1() throws Exception { if (!exactlyOneBookOpen) { setView2(book2.goToPage(book1.getCurrentSpineElementIndex())); return true; } else return false; } public boolean synchronizeView1WithView2() throws Exception { if (!exactlyOneBookOpen) { setView1(book1.goToPage(book2.getCurrentSpineElementIndex())); return true; } else return false; } public ViewStateEnum setView1(String page) { ViewStateEnum res; pageOnView1 = page; if ((book1 != null) && (book1.goToPage(page))) { // book mode res = ViewStateEnum.books; } else { // note or external link mode res = ViewStateEnum.notes; } loadPageIntoView1(page); return res; } public ViewStateEnum setView2(String page) { ViewStateEnum res; pageOnView2 = page; if ((book2 != null) && (book2.goToPage(page))) { // book mode res = ViewStateEnum.books; } else { // note or external link mode res = ViewStateEnum.notes; } loadPageIntoView2(page); return res; } // display book metadata // returns true if metadata are available, false otherwise public boolean displayMetadata(BookEnum which) { boolean res = true; if (which == BookEnum.first) if (book1 != null) { pageOnView1 = getS(R.string.metadata); EpubReaderMain.getView1().loadData(book1.metadata(), getS(R.string.textOrHTML), null); } else res = false; else if (book2 != null) { pageOnView2 = getS(R.string.metadata); EpubReaderMain.getView2().loadData(book2.metadata(), getS(R.string.textOrHTML), null); } else res = false; return res; } // return true if TOC is available, false otherwise public boolean displayTOC(BookEnum which) { boolean res = true; if (which == BookEnum.first) if (book1 != null) { pageOnView1 = getS(R.string.Table_of_Contents); EpubReaderMain.getView1().loadUrl(book1.tableOfContents()); } else res = false; else if (book2 != null) { pageOnView2 = getS(R.string.Table_of_Contents); EpubReaderMain.getView2().loadUrl(book2.tableOfContents()); } else res = false; return res; } public void saveState(Editor editor) { editor.putBoolean(getS(R.string.bookOpen), atLeastOneBookOpen); editor.putBoolean(getS(R.string.onlyOne), exactlyOneBookOpen); editor.putBoolean(getS(R.string.sync), synchronizedReadingActive); editor.putBoolean(getS(R.string.parallelTextBool), parallelText); if (atLeastOneBookOpen) { if (book1 != null) { // book1 exists: save its state and close it editor.putString(getS(R.string.page1), pageOnView1); editor.putInt(getS(R.string.CurrentPageBook1), book1.getCurrentSpineElementIndex()); editor.putInt(getS(R.string.LanguageBook1), book1.getCurrentLanguage()); editor.putString(getS(R.string.nameEpub1), book1.getDecompressedFolder()); editor.putString(getS(R.string.pathBook1), book1.getFileName()); try { book1.closeStream(); } catch (IOException e) { Log.e(getS(R.string.error_CannotCloseStream), getS(R.string.Book1_Stream)); e.printStackTrace(); } editor.putString(getS(R.string.page2), pageOnView2); if ((!exactlyOneBookOpen) && (book2 != null)) { // book2 exists: save its state and close it editor.putInt(getS(R.string.CurrentPageBook2), book2.getCurrentSpineElementIndex()); editor.putInt(getS(R.string.LanguageBook2), book2.getCurrentLanguage()); editor.putString(getS(R.string.nameEpub2), book2.getDecompressedFolder()); editor.putString(getS(R.string.pathBook2), book2.getFileName()); try { book2.closeStream(); } catch (IOException e) { Log.e(getS(R.string.error_CannotCloseStream), getS(R.string.Book2_Stream)); e.printStackTrace(); } } } } } public boolean loadState(SharedPreferences preferences) { boolean ok = true; atLeastOneBookOpen = preferences.getBoolean(getS(R.string.bookOpen), false); exactlyOneBookOpen = preferences.getBoolean(getS(R.string.onlyOne), true); synchronizedReadingActive = preferences.getBoolean(getS(R.string.sync), false); parallelText = preferences.getBoolean(getS(R.string.parallelTextBool), false); if (atLeastOneBookOpen) { // load the first book pageOnView1 = preferences.getString(getS(R.string.page1), ""); int pageIndex = preferences.getInt(getS(R.string.CurrentPageBook1), 0); int langIndex = preferences.getInt(getS(R.string.LanguageBook1), 0); String folder = preferences.getString(getS(R.string.nameEpub1), ""); String file = preferences.getString(getS(R.string.pathBook1), ""); // try loading a book already extracted try { book1 = new EpubManipulator(file, folder, pageIndex, langIndex, context); book1.goToPage(pageIndex); } catch (Exception e1) { // error: retry this way try { book1 = new EpubManipulator(file, "1", context); book1.goToPage(pageIndex); } catch (Exception e2) { ok = false; } } // Show the first view's actual page loadPageIntoView1(pageOnView1); if (pageOnView1 == getS(R.string.metadata)) // if they were // metadata, reload them displayMetadata(BookEnum.first); if (pageOnView1 == getS(R.string.Table_of_Contents)) // if it was // table of // content, reload it displayTOC(BookEnum.first); // If there is a second book, try to reload it pageOnView2 = preferences.getString(getS(R.string.page2), ""); if (!exactlyOneBookOpen) { pageIndex = preferences.getInt(getS(R.string.CurrentPageBook2), 0); langIndex = preferences.getInt(getS(R.string.LanguageBook2), 0); folder = preferences.getString(getS(R.string.nameEpub2), ""); file = preferences.getString(getS(R.string.pathBook2), ""); try { book2 = new EpubManipulator(file, folder, pageIndex, langIndex, context); book2.goToPage(pageIndex); } catch (Exception e3) { try { book2 = new EpubManipulator(file, "2", context); book2.goToPage(pageIndex); } catch (Exception e4) { ok = false; } } } loadPageIntoView2(pageOnView2); if (pageOnView2 == getS(R.string.metadata)) displayMetadata(BookEnum.second); if (pageOnView2 == getS(R.string.Table_of_Contents)) displayTOC(BookEnum.second); } return ok; } public boolean isExactlyOneBookOpen() { return exactlyOneBookOpen; } public String getS(int id) { return context.getResources().getString(id); } public boolean isParallelTextOn() { return parallelText; } public boolean isSynchronized() { return synchronizedReadingActive; } public boolean isAtLeastOneBookOpen() { return atLeastOneBookOpen; } }