/* * Copyright 2014 Roque Pinel * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package cc.pinel.mangue; import java.awt.KeyEventDispatcher; import java.awt.KeyboardFocusManager; import java.awt.event.KeyEvent; import org.apache.log4j.PropertyConfigurator; import org.kwt.ui.KWTSelectableLabel; import cc.pinel.mangue.handler.StorageHandler; import cc.pinel.mangue.model.Chapter; import cc.pinel.mangue.model.Manga; import cc.pinel.mangue.storage.GeneralStorage; import cc.pinel.mangue.storage.MangaStorage; import cc.pinel.mangue.storage.StateStorage; import cc.pinel.mangue.ui.AddMangaPanel; import cc.pinel.mangue.ui.ChaptersPanel; import cc.pinel.mangue.ui.MainPanel; import cc.pinel.mangue.ui.Menu; import cc.pinel.mangue.ui.ViewPanel; import com.amazon.kindle.kindlet.Kindlet; import com.amazon.kindle.kindlet.KindletContext; import com.amazon.kindle.kindlet.event.KindleKeyCodes; import com.amazon.kindle.kindlet.ui.KOptionPane; import com.amazon.kindle.kindlet.ui.KPanel; /** * The main controller. * * @author Roque Pinel * */ public class Main implements Kindlet { /** * The possible values for the variable <code>state</code>. */ private static final int INACTIVE_STATE = -1; private static final int MAIN_STATE = 0; private static final int CHAPTERS_STATE = 1; private static final int VIEW_STATE = 2; /** * The minimal number of characters that can be searched. */ private static final int MIN_CHARS_SEARCH = 3; private KindletContext context; private MainPanel mainPanel; private ChaptersPanel chaptersPanel; private ViewPanel viewPanel; private AddMangaPanel addMangaPanel; private int state = INACTIVE_STATE; // --- KDK Methods --- /** * {@inheritDoc} */ public void create(KindletContext context) { this.context = context; PropertyConfigurator.configure(getClass().getResource("/res/log4j.properties")); getContext().setMenu(new Menu(this)); KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new MainKeyEventDispatcher()); } /** * {@inheritDoc} */ public void start() { if (!isViewActive()) { GeneralStorage generalStorage = new GeneralStorage(context); String pageNumber = generalStorage.getCurrentPageNumber(); if (pageNumber != null) { String mangaId = generalStorage.getCurrentMangaId(); String chapterNumber = generalStorage.getCurrentChapterNumber(); if (mangaId != null && chapterNumber != null) loadLastViewed(mangaId, chapterNumber, pageNumber); } } if (isInactive()) { this.mainPanel = new MainPanel(this); this.mainPanel.loadMangas(); this.state = MAIN_STATE; } paintActive(); } /** * {@inheritDoc} */ public void stop() { // ignored } /** * {@inheritDoc} */ public void destroy() { // ignored } /** * @return the Kindlet Context */ public KindletContext getContext() { return this.context; } // --- States --- /** * The kindlet is always inactive the first time it is started. * * @return if it is inactive */ public boolean isInactive() { return this.state == INACTIVE_STATE; } /** * @return if the main panel is being displayed */ public boolean isMainActive() { return this.state == MAIN_STATE; } /** * @return if the chapters panel is being displayed */ public boolean isChaptersActive() { return this.state == CHAPTERS_STATE; } /** * @return if the view panel is being displayed */ public boolean isViewActive() { return this.state == VIEW_STATE; } /** * @return if the add manga panel is being displayed */ public boolean isAddActive() { return this.state > VIEW_STATE; } // --- Panels --- /** * @return the chapters panel */ public ChaptersPanel getChaptersPanel() { return this.chaptersPanel; } /** * @param chaptersPanel the chapters panel */ public void setChaptersPanel(ChaptersPanel chaptersPanel) { this.chaptersPanel = chaptersPanel; } /** * @return the view panel */ public ViewPanel getViewPanel() { return this.viewPanel; } /** * @param viewPanel the view panel */ public void setViewPanel(ViewPanel viewPanel) { this.viewPanel = viewPanel; } /** * @return the add manga panel */ public AddMangaPanel getAddMangaPanel() { return this.addMangaPanel; } /** * @param addMangaPanel the add manga panel */ public void setAddMangaPanel(AddMangaPanel addMangaPanel) { this.addMangaPanel = addMangaPanel; } // --- Paint Methods --- /** * Set the state as main panel and paints it. */ public void paintMainPanel() { this.state = MAIN_STATE; paintActive(); } /** * Set the state as chapters panel and paints it. */ public void paintChaptersPanel() { this.state = CHAPTERS_STATE; paintActive(); } /** * Set the state as view panel and paints it. */ public void paintViewPanel() { this.state = VIEW_STATE; paintActive(); } /** * Set the state as add manga panel and paints it. */ public void paintAddMangaPanel() { if (!isAddActive()) this.state += VIEW_STATE + 1; paintActive(); } /** * Paints the active panel based on the current state. */ public void paintActive() { KPanel panel; if (isViewActive()) panel = this.viewPanel; else if (isChaptersActive()) panel = this.chaptersPanel; else if (isAddActive()) panel = this.addMangaPanel; else panel = this.mainPanel; context.getRootContainer().removeAll(); context.getRootContainer().add(panel); panel.requestFocus(); context.getRootContainer().invalidate(); context.getRootContainer().repaint(); } /** * Reloads the mangas and paints the main panel. * * It creates a main panel if it does not exist. */ public void reloadMainPanel() { if (this.mainPanel == null) this.mainPanel = new MainPanel(this); paintMainPanel(); this.mainPanel.loadMangas(); } // --- Menu Actions --- /** * Displays the search manga dialog. */ public void searchManga() { final KindletContext context = getContext(); String term = new GeneralStorage(context).getSearchTerm(); KOptionPane.showInputDialog(context.getRootContainer(), "Title (min " + MIN_CHARS_SEARCH + " char): ", term == null ? "" : term, new KOptionPane.InputDialogListener() { public void onClose(String input) { if (input != null && input.length() >= MIN_CHARS_SEARCH) { new GeneralStorage(context).setSearchTerm(input); AddMangaPanel addMangaPanel = getAddMangaPanel(); if (addMangaPanel == null) setAddMangaPanel(new AddMangaPanel(Main.this, input)); else addMangaPanel.loadResults(input); paintAddMangaPanel(); } } }); } /** * Displays the clear all mangas confirmation message. */ public void clearMangas() { final KindletContext context = getContext(); KOptionPane.showConfirmDialog(context.getRootContainer(), "Would you really like to clear your favorites?", new KOptionPane.ConfirmDialogListener() { public void onClose(int option) { if (option == KOptionPane.OK_OPTION) { new StorageHandler(context, "Clearing Favorites...") { public void handleRun() throws Exception { new MangaStorage(context).clear(); new StateStorage(context).clear(); reloadMainPanel(); } }.start(); } } }); } /** * Displays the clear previous searched term confirmation message. */ public void clearSearch() { final KindletContext context = getContext(); KOptionPane.showConfirmDialog(context.getRootContainer(), "Would you really like to clear your previous searched term?", new KOptionPane.ConfirmDialogListener() { public void onClose(int option) { if (option == KOptionPane.OK_OPTION) new GeneralStorage(context).removeSearchTerm(); } }); } // --- Events --- /** * Handles the main key events. * * Basically, the back button. * * @author Roque Pinel * */ private class MainKeyEventDispatcher implements KeyEventDispatcher { /** * {@inheritDoc} */ public boolean dispatchKeyEvent(KeyEvent e) { if (e.isConsumed()) return false; if (e.getKeyCode() == KindleKeyCodes.VK_BACK) { if (e.getID() == KeyEvent.KEY_PRESSED) { if (isChaptersActive()) { new GeneralStorage(getContext()).removeCurrentChapterNumber(); if (Main.this.mainPanel == null) Main.this.mainPanel = new MainPanel(Main.this); paintMainPanel(); Main.this.mainPanel.loadMangas(); requestGC(); } else if (isViewActive()) { GeneralStorage generalStorage = new GeneralStorage(getContext()); generalStorage.removeCurrentPageNumber(); if (getChaptersPanel() == null) { final String mangaId = generalStorage.getCurrentMangaId(); final Manga manga = new MangaStorage(getContext()).getManga(mangaId); if (manga != null) setChaptersPanel(new ChaptersPanel(Main.this, manga)); } paintChaptersPanel(); requestGC(); } else if (isAddActive()) { Main.this.state -= Main.VIEW_STATE + 1; paintActive(); requestGC(); } } e.consume(); return true; } else if (e.getSource() instanceof KWTSelectableLabel) { KWTSelectableLabel label = (KWTSelectableLabel) e.getSource(); label.processEvent(e); } return false; } } // --- Special Methods /** * Loads the last view panel for the parameters provided * * @param mangaId the manga id * @param chapterNumber the chapter number * @param pageNumber the page number */ private void loadLastViewed(String mangaId, String chapterNumber, String pageNumber) { final Manga manga = new MangaStorage(getContext()).getManga(mangaId); if (manga != null) { Chapter chapter = new Chapter(chapterNumber, manga.getChapterLink(chapterNumber)); ViewPanel viewPanel = getViewPanel(); if (viewPanel == null) setViewPanel(new ViewPanel(this, chapter, new Integer(pageNumber))); else viewPanel.loadImage(chapter); this.state = VIEW_STATE; } } /** * Resquests the system Garbage Collection to run. */ public void requestGC() { System.gc(); } }