/* * @copyright 2013 Philip Warner * @license GNU General Public License * * This file is part of Book Catalogue. * * Book Catalogue 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 3 of the License, or * (at your option) any later version. * * Book Catalogue 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 Book Catalogue. If not, see <http://www.gnu.org/licenses/>. */ package com.eleybourn.bookcatalogue; import java.util.ArrayList; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.eleybourn.bookcatalogue.Fields.AfterFieldChangeListener; import com.eleybourn.bookcatalogue.Fields.Field; import com.eleybourn.bookcatalogue.compat.BookCatalogueFragment; import com.eleybourn.bookcatalogue.datamanager.DataEditor; import com.eleybourn.bookcatalogue.datamanager.DataManager; import com.eleybourn.bookcatalogue.utils.BookUtils; import com.eleybourn.bookcatalogue.utils.Logger; import com.eleybourn.bookcatalogue.utils.Utils; /** * Based class for all fragments that appear in the BookEdit activity * * @author pjw */ public abstract class BookEditFragmentAbstract extends BookCatalogueFragment implements DataEditor { protected Fields mFields; private static final int DELETE_ID = 1; private static final int DUPLICATE_ID = 3; //2 is taken by populate in anthology private static final int SHARE_ID = 4; protected static final int THUMBNAIL_OPTIONS_ID = 5; private static final int EDIT_OPTIONS_ID = 6; /** * Interface that any containing activity must implement. * * @author pjw */ public interface BookEditManager { //public Fields getFields(); public void setShowAnthology(boolean showAnthology); public void setDirty(boolean isDirty); public boolean isDirty(); public BookData getBookData(); public void setRowId(Long id); public ArrayList<String> getFormats(); public ArrayList<String> getGenres(); public ArrayList<String> getLanguages(); public ArrayList<String> getPublishers(); } /** A link to the BookEditManager for this fragment (the activity) */ protected BookEditManager mEditManager; /** Database instance */ protected CatalogueDBAdapter mDbHelper; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setHasOptionsMenu(true); } @Override public void onAttach(Activity a) { super.onAttach(a); if (! (a instanceof BookEditManager)) throw new RuntimeException("Activity " + a.getClass().getSimpleName() + " must implement BookEditManager"); mEditManager = (BookEditManager)a; mDbHelper = new CatalogueDBAdapter(a); mDbHelper.open(); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mFields = new Fields(this); } /** * Define the common menu options; each subclass can add more as necessary */ @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); //menu.clear(); final Long currRow = mEditManager.getBookData().getRowId(); if (currRow != null && currRow != 0) { MenuItem delete = menu.add(0, DELETE_ID, 0, R.string.menu_delete); delete.setIcon(android.R.drawable.ic_menu_delete); MenuItem duplicate = menu.add(0, DUPLICATE_ID, 0, R.string.menu_duplicate); duplicate.setIcon(android.R.drawable.ic_menu_add); } // TODO: Consider allowing Tweets (or other sharing methods) to work on un-added books. MenuItem tweet = menu.add(0, SHARE_ID, 0, R.string.menu_share_this); tweet.setIcon(R.drawable.ic_menu_twitter); // Very rarely used, and easy to miss-click. //tweet.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); if(this instanceof BookDetailsReadOnly){ menu.add(0, EDIT_OPTIONS_ID, 0, R.string.edit_book) .setIcon(android.R.drawable.ic_menu_edit) .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); ; } boolean hasAuthor = mEditManager.getBookData().getAuthorList().size() > 0; if (hasAuthor) { MenuItem item = menu.add(0, R.id.MENU_AMAZON_BOOKS_BY_AUTHOR, 0, R.string.amazon_books_by_author); item.setIcon(R.drawable.ic_www_search_2_holo_dark); } if (mEditManager.getBookData().getSeriesList().size() > 0) { if (hasAuthor) { MenuItem item = menu.add(0, R.id.MENU_AMAZON_BOOKS_BY_AUTHOR_IN_SERIES, 0, R.string.amazon_books_by_author_in_series); item.setIcon(R.drawable.ic_www_search_2_holo_dark); } { MenuItem item = menu.add(0, R.id.MENU_AMAZON_BOOKS_IN_SERIES, 0, R.string.amazon_books_in_series); item.setIcon(R.drawable.ic_www_search_2_holo_dark); } } } /** * This will be called when a menu item is selected. A large switch * statement to call the appropriate functions (or other activities) */ @Override public boolean onOptionsItemSelected(MenuItem item) { final Long currRow = mEditManager.getBookData().getRowId(); try { switch (item.getItemId()) { case THUMBNAIL_OPTIONS_ID: if (this instanceof BookEditFields) { ((BookEditFields) this).showCoverContextMenu(); return true; } break; case SHARE_ID: BookUtils.shareBook(getActivity(), mDbHelper, currRow); return true; case DELETE_ID: BookUtils.deleteBook(getActivity(), mDbHelper, currRow, new Runnable() { @Override public void run() { getActivity().finish(); } }); return true; case DUPLICATE_ID: BookUtils.duplicateBook(getActivity(), mDbHelper, currRow); return true; case EDIT_OPTIONS_ID: BookEdit.editBook(getActivity(), currRow, BookEdit.TAB_EDIT); return true; case R.id.MENU_AMAZON_BOOKS_BY_AUTHOR: { String author = getAuthorFromBook(); Utils.openAmazonSearchPage(getActivity(), author, null); return true; } case R.id.MENU_AMAZON_BOOKS_IN_SERIES: { String series = getSeriesFromBook(); Utils.openAmazonSearchPage(getActivity(), null, series); return true; } case R.id.MENU_AMAZON_BOOKS_BY_AUTHOR_IN_SERIES: { String author = getAuthorFromBook(); String series = getSeriesFromBook(); Utils.openAmazonSearchPage(getActivity(), author, series); return true; } } } catch (NullPointerException e) { Logger.logError(e); } return false; } private String getAuthorFromBook() { ArrayList<Author> authors = mEditManager.getBookData().getAuthorList(); if (authors.size() > 0) return authors.get(0).getDisplayName(); else return null; } private String getSeriesFromBook() { ArrayList<Series> list = mEditManager.getBookData().getSeriesList(); if (list.size() > 0) return list.get(0).name; else return null; } @Override public void onPause() { super.onPause(); // This is now done in onPause() since the view may have been deleted when this is called onSaveBookDetails(mEditManager.getBookData()); } /** * Called to load data from the BookData object when needed. * * @param book BookData to load from * @param setAllDone Flag indicating setAll() has already been called on the mFields object */ abstract protected void onLoadBookDetails(BookData book, boolean setAllDone); /** * Default implementation of code to save existing data to the BookData object * * @param book */ protected void onSaveBookDetails(BookData book) { mFields.getAll(book); } @Override public void onResume() { //double t0 = System.currentTimeMillis(); super.onResume(); // Load the data and preserve the isDirty() setting mFields.setAfterFieldChangeListener(null); final boolean wasDirty = mEditManager.isDirty(); BookData book = mEditManager.getBookData(); onLoadBookDetails(book, false); mEditManager.setDirty(wasDirty); // Set the listener to monitor edits mFields.setAfterFieldChangeListener(new AfterFieldChangeListener(){ @Override public void afterFieldChange(Field field, String newValue) { mEditManager.setDirty(true); }}); //System.out.println("BEFA resume: " + (System.currentTimeMillis() - t0)); } /** * Cleanup */ @Override public void onDestroy() { super.onDestroy(); mDbHelper.close(); } @Override public void saveAllEdits(DataManager data) { mFields.getAll(mEditManager.getBookData()); } /** * This is 'final' because we want inheritors to implement onLoadBookDetails() */ @Override public final void reloadData(DataManager data) { final boolean wasDirty = mEditManager.isDirty(); onLoadBookDetails(mEditManager.getBookData(), false); mEditManager.setDirty(wasDirty); } /** * Show or Hide text field if it has not any useful data. * Don't show a field if it is already hidden (assumed by user preference) * @param hideIfEmpty TODO * @param resId layout resource id of the field * @param relatedFields list of fields whose visibility will also be set based on the first field * * @return The resulting visibility setting value (VISIBLE or GONE) */ protected int showHideField(boolean hideIfEmpty, int resId, int...relatedFields) { // Get the base view final View v = getView().findViewById(resId); int visibility; if (v == null) { visibility = View.GONE; } else { visibility = v.getVisibility(); if (hideIfEmpty) { if (v.getVisibility() != View.GONE) { // Determine if we should hide it if (v instanceof ImageView) { visibility = v.getVisibility(); } else { final String value = mFields.getField(resId).getValue().toString(); final boolean isExist = value != null && !value.equals(""); visibility = isExist ? View.VISIBLE : View.GONE; v.setVisibility(visibility); } } } // Set the related views for(int i: relatedFields) { View rv = getView().findViewById(i); if (rv != null) rv.setVisibility(visibility); } } return visibility; } /** * Hides unused fields if they have not any useful data. Checks all text fields * except of author, series and loaned. */ protected void showHideFields(boolean hideIfEmpty) { mFields.resetVisibility(); // Check publishing information; in reality only one of these fields will exist showHideField(hideIfEmpty, R.id.publishing_details, R.id.lbl_publishing, R.id.row_publisher); showHideField(hideIfEmpty, R.id.publisher, R.id.lbl_publishing, R.id.row_publisher); showHideField(hideIfEmpty, R.id.date_published, R.id.row_date_published); // if (showHideFieldIfEmpty(R.id.publisher) == View.GONE && showHideFieldIfEmpty(R.id.date_published) == View.GONE) { // getView().findViewById(R.id.lbl_publishing).setVisibility(View.GONE); // } showHideField(hideIfEmpty, R.id.row_img, R.id.image_wrapper); // boolean hasImage = getView().findViewById(R.id.row_img).getVisibility() != View.GONE; // if (!hasImage) { // getView().findViewById(R.id.image_wrapper).setVisibility(View.GONE); // } // Check format information showHideField(hideIfEmpty, R.id.pages, R.id.row_pages); //boolean hasPages = (showHideField(true, R.id.pages) == View.VISIBLE); //if (!hasPages) { // getView().findViewById(R.id.pages).setVisibility(View.GONE); //} showHideField(hideIfEmpty, R.id.format, R.id.row_format); // Check genre showHideField(hideIfEmpty, R.id.genre, R.id.lbl_genre, R.id.row_genre); // Check language showHideField(hideIfEmpty, R.id.language, R.id.lbl_language, R.id.row_language); // Check ISBN showHideField(hideIfEmpty, R.id.isbn, R.id.row_isbn); // Check ISBN showHideField(hideIfEmpty, R.id.series, R.id.row_series, R.id.lbl_series); // Check list price showHideField(hideIfEmpty, R.id.list_price, R.id.row_list_price); // Check description showHideField(hideIfEmpty, R.id.description, R.id.descriptionLabel, R.id.description_divider); // **** MY COMMENTS SECTION **** // Check notes showHideField(hideIfEmpty, R.id.notes, R.id.lbl_notes, R.id.row_notes); // Check date start reading showHideField(hideIfEmpty, R.id.read_start, R.id.row_read_start); // Check date end reading showHideField(hideIfEmpty, R.id.read_end, R.id.row_read_end); // Check location showHideField(hideIfEmpty, R.id.location, R.id.row_location, R.id.row_location); // Check signed flag showHideField(hideIfEmpty, R.id.signed, R.id.row_signed); } }