com.flowzr.activity.Report2DChartActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.flowzr.activity.Report2DChartActivity.java

Source

/*******************************************************************************
 * Copyright (c) 2010 Denis Solonenko.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Denis Solonenko - initial API and implementation
 *     Abdsandryk Souza - implementing 2D chart reports
 *     Emmanuel Florent - port to Android API 11+
 ******************************************************************************/

package com.flowzr.activity;

import java.util.Calendar;
import java.util.Collection;
import java.util.GregorianCalendar;

import com.flowzr.R;
import com.flowzr.db.DatabaseAdapter;
import com.flowzr.db.MyEntityManager;
import com.flowzr.filter.DateTimeCriteria;
import com.flowzr.filter.WhereFilter;
import com.flowzr.graph.Report2DChart;
import com.flowzr.model.Currency;
import com.flowzr.model.ReportDataByPeriod;
import com.flowzr.report.*;
import com.flowzr.utils.CurrencyCache;
import com.flowzr.utils.MyPreferences;
import com.flowzr.utils.PinProtection;
import com.flowzr.utils.Utils;
import com.flowzr.view.Report2DChartView;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.ListAdapter;
import android.widget.TextView;

public class Report2DChartActivity extends AbstractListFragment {

    // option menu references
    private static final int MENU_PREFERENCES = 1;

    // activity result identifier to get results back
    public static final int REPORT_PREFERENCES = 1;

    // Data to display 
    private Report2DChart reportData;
    private DatabaseAdapter dbAdapter;
    private MyEntityManager em;

    // user interface elements
    private ImageButton bPrevious;
    private ImageButton bNext;
    private int selectedPeriod;
    private Currency currency;
    private Calendar startPeriod;
    private int reportType;

    // array of string report preferences to identify changes
    String[] initialPrefs;

    // boolean to check if preferred currency is set
    private boolean prefCurNotSet = false;
    // boolean to check if preferred period is set
    private boolean prefPerNotSet = false;

    public Report2DChartActivity() {
        super(R.layout.report_2d);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // get report type
        int type = 0;

        Bundle bundle = getArguments();
        if (bundle != null) {
            db = new DatabaseAdapter(getActivity());
            db.open();
            type = bundle.getInt(Report2DChart.REPORT_TYPE, 0);
        }

        this.reportType = type;

    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        init();
    }

    /**
     * Initialize activity.
     */
    private void init() {
        // database adapter to query data
        dbAdapter = new DatabaseAdapter(this.getActivity());
        dbAdapter.open();

        em = dbAdapter.em();

        // get report preferences to display chart
        // Reference Currency
        currency = getReferenceCurrency();
        // Period of Reference
        int periodLength = getPeriodOfReference();
        selectedPeriod = periodLength - 3;

        // check report preferences for reference month different of current month
        setStartPeriod(periodLength);

        boolean built = false;
        switch (reportType) {
        case Report2DChart.REPORT_ACCOUNT_BY_PERIOD:
            reportData = new AccountByPeriodReport(this.getActivity(), em, startPeriod, periodLength, currency);
            ((EntityListActivity) getActivity())
                    .setMyTitle(getResources().getString(R.string.report_by_account_by_period_summary));
            break;
        case Report2DChart.REPORT_CATEGORY_BY_PERIOD:
            reportData = new CategoryByPeriodReport(this.getActivity(), em, startPeriod, periodLength, currency);
            ((EntityListActivity) getActivity())
                    .setMyTitle(getResources().getString(R.string.report_by_category_by_period_summary));
            break;
        case Report2DChart.REPORT_PAYEE_BY_PERIOD:
            reportData = new PayeeByPeriodReport(this.getActivity(), em, startPeriod, periodLength, currency);
            ((EntityListActivity) getActivity())
                    .setMyTitle(getResources().getString(R.string.report_by_payee_by_period_summary));
            break;
        case Report2DChart.REPORT_LOCATION_BY_PERIOD:
            reportData = new LocationByPeriodReport(this.getActivity(), em, startPeriod, periodLength, currency);
            ((EntityListActivity) getActivity())
                    .setMyTitle(getResources().getString(R.string.report_by_location_by_period_summary));
            break;
        case Report2DChart.REPORT_PROJECT_BY_PERIOD:
            reportData = new ProjectByPeriodReport(this.getActivity(), em, startPeriod, periodLength, currency);
            ((EntityListActivity) getActivity())
                    .setMyTitle(getResources().getString(R.string.report_by_project_by_period_summary));
            break;
        }

        if (reportData != null && reportData.hasFilter()) {
            refreshView();
            built = true;
        } else {
            //  There is no <location, project or category> available for filtering data. 
            alertNoFilter(reportData.getNoFilterMessage(this.getActivity()));
            adjustLabels();
        }

        if (built && (prefCurNotSet || prefPerNotSet)) {
            alertPreferencesNotSet(prefCurNotSet, prefPerNotSet);
        }

        // period length
        ((TextView) getView().findViewById(R.id.report_period)).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0) {
                // pop up options to choose the period
                changePeriodLength(selectedPeriod);
            }
        });
        ((TextView) getView().findViewById(R.id.report_period)).setFocusable(true);

    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        menu.clear();
        inflater.inflate(R.menu.report2d_actions, menu);
        super.onCreateOptionsMenu(menu, inflater);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle presses on the action bar items
        switch (item.getItemId()) {
        case R.id.bt_filter_previous:
            if (reportData.previousFilter()) {
                refreshView();
            }
            return true;
        case R.id.bt_filter_next:
            if (reportData.nextFilter()) {
                refreshView();
            }
            return true;
        case R.id.settings:
            Intent intent = new Intent(this.getActivity(), ReportPreferencesActivity.class);
            startActivityForResult(intent, REPORT_PREFERENCES);
            return true;
        default:
            return false;

        }
    }

    /**
     * Display a message when preferences not set to alert the use of default values.
     * @param isCurrency Inform if currency is not set on report preferences.
     * @param isPeriod Inform if period is not set on report preferences.
     */
    private void alertPreferencesNotSet(boolean isCurrency, boolean isPeriod) {
        // display message: preferences not set
        String message = "";
        if (isCurrency) {
            if (isPeriod) {
                // neither currency neither period is set
                message = getResources().getString(R.string.report_preferences_not_set);
            } else {
                // only currency not set
                message = getResources().getString(R.string.currency_not_set);
            }
        } else {
            if (isPeriod) {
                // only period not set
                message = getResources().getString(R.string.period_not_set);
            }
        }
        AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this.getActivity());
        dlgAlert.setMessage(message);
        dlgAlert.setTitle(R.string.reports);
        dlgAlert.setPositiveButton(R.string.ok, null);
        dlgAlert.setCancelable(true);
        dlgAlert.create().show();
    }

    /**
     * Alert message to warn that there is no filter available (no category, no project, no account or no location)
     * @param message Message warning the lack of filters by report type.
     */
    private void alertNoFilter(String message) {
        AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this.getActivity());
        dlgAlert.setMessage(message);
        dlgAlert.setTitle(R.string.reports);
        dlgAlert.setPositiveButton(R.string.ok, null);
        dlgAlert.setCancelable(true);
        dlgAlert.create().show();
    }

    /**
     * Display a list of period length options to redefine period, rebuild data and refresh view.
     * @param previousPeriod The previous selected period to check if data changed, rebuild data and refresh view.
     */
    private void changePeriodLength(final int previousPeriod) {
        final Context context = this.getActivity();
        new AlertDialog.Builder(this.getActivity()).setTitle(R.string.period)
                .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        processPeriodLengthChange(previousPeriod, true);
                    }
                }).setSingleChoiceItems(reportData.getPeriodStrings(context), selectedPeriod,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                selectedPeriod = which;
                            }
                        })
                .show();
    }

    /**
     * Process the period length change
     * @param previousPeriod The selected period length before changing
     * @param refresh True if requires refresh, false if refresh will be processed later
     */
    private void processPeriodLengthChange(int previousPeriod, boolean refresh) {
        if (previousPeriod != selectedPeriod) {
            reportData.changePeriodLength(reportData.getPeriodOptions()[selectedPeriod]);
            setStartPeriod(reportData.getPeriodOptions()[selectedPeriod]);
            reportData.changeStartPeriod(startPeriod);
            if (refresh)
                refreshView();
        }
    }

    /**
     * Update the view reflecting data changes
     */
    private void refreshView() {
        // set data to plot
        if (reportData.hasDataToPlot()) {
            getView().findViewById(R.id.report_empty).setVisibility(View.GONE);
            Report2DChartView view = (Report2DChartView) getView().findViewById(R.id.report_2d_chart);

            view.setDataToPlot(reportData.getPoints(), reportData.getDataBuilder().getMaxValue(),
                    reportData.getDataBuilder().getMinValue(), reportData.getDataBuilder().getAbsoluteMaxValue(),
                    reportData.getDataBuilder().getAbsoluteMinValue(),
                    reportData.getDataBuilder().getMeanExcludingNulls());
            ((Report2DChartView) getView().findViewById(R.id.report_2d_chart)).setCurrency(currency);
            ((Report2DChartView) getView().findViewById(R.id.report_2d_chart)).setVisibility(View.VISIBLE);

            // set labels
            view.refresh();
        } else {
            ((TextView) getView().findViewById(R.id.report_empty)).setVisibility(View.VISIBLE);
            ((Report2DChartView) getView().findViewById(R.id.report_2d_chart)).setVisibility(View.GONE);
        }
        // adjust report 2D user interface elements
        adjustLabels();
        fillStatistics();

    }

    /**
     * Adjust labels after changing report parameters
     */
    private void adjustLabels() {
        // Period 
        ((TextView) getView().findViewById(R.id.report_period))
                .setText(reportData.getFilterName() + " " + reportData.getPeriodLengthString(this.getActivity()));
    }

    /**
     * Fill statistics panel based on report data
     */
    private void fillStatistics() {
        boolean considerNull = MyPreferences.considerNullResultsInReport(this.getActivity());
        Double max;
        Double min;
        Double mean;
        Double sum = new Double(reportData.getDataBuilder().getSum());
        if (considerNull) {
            max = new Double(reportData.getDataBuilder().getMaxValue());
            min = new Double(reportData.getDataBuilder().getMinValue());
            mean = new Double(reportData.getDataBuilder().getMean());
            if ((min * max >= 0)) {
                // absolute calculation (all points over the x axis)
                max = new Double(reportData.getDataBuilder().getAbsoluteMaxValue());
                min = new Double(reportData.getDataBuilder().getAbsoluteMinValue());
                mean = Math.abs(mean);
                sum = Math.abs(sum);
            }
        } else {
            // exclude impact of null values in statistics
            max = new Double(reportData.getDataBuilder().getMaxExcludingNulls());
            min = new Double(reportData.getDataBuilder().getMinExcludingNulls());
            mean = new Double(reportData.getDataBuilder().getMeanExcludingNulls());
            if ((min * max >= 0)) {
                // absolute calculation (all points over the x axis)
                max = new Double(reportData.getDataBuilder().getAbsoluteMaxExcludingNulls());
                min = new Double(reportData.getDataBuilder().getAbsoluteMinExcludingNulls());
                mean = Math.abs(mean);
                sum = Math.abs(sum);
            }
        }
        // chart limits
        ((TextView) getView().findViewById(R.id.report_max_result))
                .setText(Utils.amountToString(reportData.getCurrency(), max.longValue()));
        ((TextView) getView().findViewById(R.id.report_min_result))
                .setText(Utils.amountToString(reportData.getCurrency(), min.longValue()));
        // sum and mean
        ((TextView) getView().findViewById(R.id.report_mean_result))
                .setText(Utils.amountToString(reportData.getCurrency(), mean.longValue()));
        ((TextView) getView().findViewById(R.id.report_mean_result)).setTextColor(Report2DChartView.meanColor);
        //((TextView)getView().findViewById(R.id.report_sum_result)).setText(Utils.amountToString(reportData.getCurrency(), sum.longValue()));
    }

    /**
     * Gets the reference currency registered on preferences or, if not registered, gets the default currency.
     * @return The currency registered as a reference to display chart reports or the default currency if not configured yet.
     */
    private Currency getReferenceCurrency() {
        Currency c = MyPreferences.getReferenceCurrency(this.getActivity());
        if (c == null) {
            prefCurNotSet = true;
            Collection<Currency> currencies = CurrencyCache.getAllCurrencies();
            if (currencies != null && currencies.size() > 0) {
                for (Currency currency : currencies) {
                    if (currency.isDefault) {
                        c = currency;
                        break;
                    }
                }
                if (c == null) {
                    c = getNewDefaultCurrency();
                }
            } else {
                c = getNewDefaultCurrency();
            }
        }
        return c;
    }

    /**
     * Gets default currency when currency is not set in report preferences.
     * @return Default currency
     */
    private Currency getNewDefaultCurrency() {
        return Currency.defaultCurrency();
    }

    //   @Override
    //   public boolean onCreateOptionsMenu(Menu menu) {
    //      super.onCreateOptionsMenu(menu);
    //      MenuItem menuItem = menu.add(0, MENU_PREFERENCES, 0, R.string.preferences);
    //      menuItem.setIcon(android.R.drawable.ic_menu_preferences);
    //      return true;
    //   }
    //   
    //   @Override
    //   public boolean onOptionsItemSelected(MenuItem item) {
    //      super.onOptionsItemSelected(item);
    //      switch (item.getItemId()) {
    //      case MENU_PREFERENCES:
    //         // save preferences status before call report preferences activity
    //         initialPrefs = MyPreferences.getReportPreferences(this);
    //         // call report preferences activity asking for result when closed
    //         Intent intent = new Intent(this, ReportPreferencesActivity.class);
    //          startActivityForResult(intent, REPORT_PREFERENCES);
    //         break;
    //      }
    //      return false;
    //
    //   }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        // See which child activity is calling us back.
        if (initialPrefs != null) {
            boolean changed = preferencesChanged(initialPrefs,
                    MyPreferences.getReportPreferences(this.getActivity()));
            if (changed) {
                // rebuild data
                reportData.rebuild(this.getActivity(), em, startPeriod,
                        reportData.getPeriodOptions()[selectedPeriod], currency);
                refreshView();
            }
        }
    }

    /**
     * Check if preferences changed
     * @param initial Preferences status before call Report Preferences Activity.
     * @param actual Current preferences status.
     * @return True if preferences changed, false otherwise.
     */
    private boolean preferencesChanged(String[] initial, String[] actual) {
        boolean changed = false;
        // general report preferences
        // 0 reference currency
        if (!initial[0].equals(actual[0])) {
            // set reference currency
            currency = getReferenceCurrency();
            changed = true;
        }
        // 1 period of reference
        if (!initial[1].equals(actual[1])) {
            // change period length to the one set in report preferences
            int refPeriodLength = getPeriodOfReference();
            int previousPeriod = selectedPeriod;
            selectedPeriod = refPeriodLength - 3;
            processPeriodLengthChange(previousPeriod, false);
            changed = true;
        }
        // 2 reference month
        if (!initial[2].equals(actual[2])) {
            setStartPeriod(reportData.getPeriodOptions()[selectedPeriod]);
            changed = true;
        }
        // 3 consider nulls in statistics (affects statistics only > recalculate)
        if (!initial[3].equals(actual[3])) {
            // affects statistics only - recalculate
            changed = true;
        }
        // 4 include <no filter> (rebuild will regenerate the filter Ids list)
        if (!initial[4].equals(actual[4])) {
            // the change will be processed in rebuild
            changed = true;
        }

        if (reportType == Report2DChart.REPORT_CATEGORY_BY_PERIOD) {
            // include sub categories in list (rebuild will regenerate the filter Ids list)
            if (!initial[5].equals(actual[5])) {
                // the change will be processed in rebuild
                changed = true;
            }
            // add sub categories result to root categories result (affects statistics only > recalculate)
            if (!initial[6].equals(actual[6]))
                changed = true;
        }
        return changed;
    }

    /**
     * Set the start period based on given period length and reference month registered in report preferences.
     * Start period = Reference Month - periodLength months
     * @param periodLength The number of months to be represented in the 2D report.
     */
    private void setStartPeriod(int periodLength) {
        int refMonth = MyPreferences.getReferenceMonth(this.getActivity());
        Calendar now = Calendar.getInstance();
        startPeriod = new GregorianCalendar(now.get(Calendar.YEAR), now.get(Calendar.MONTH), 1);
        if (refMonth != 0) {
            startPeriod.add(Calendar.MONTH, refMonth);
        }
        // move to start period (reference month - <periodLength> months)
        startPeriod.add(Calendar.MONTH, (-1) * periodLength + 1);
    }

    /**
     * Get the period of reference set in report preferences.
     * @return The number of months to be represented in the 2D report.
     */
    private int getPeriodOfReference() {
        int periodLength = MyPreferences.getPeriodOfReference(this.getActivity());
        if (periodLength == 0) {
            periodLength = ReportDataByPeriod.DEFAULT_PERIOD;
            prefPerNotSet = true;
        }
        return periodLength;
    }

    @Override
    public void onDestroy() {
        dbAdapter.close();
        super.onDestroy();
    }

    @Override
    protected Cursor createCursor() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    protected ListAdapter createAdapter(Cursor cursor) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    protected void deleteItem(View v, int position, long id) {
        // TODO Auto-generated method stub

    }

    @Override
    protected void editItem(View v, int position, long id) {
        // TODO Auto-generated method stub

    }

    @Override
    protected void viewItem(View v, int position, long id) {
        // TODO Auto-generated method stub

    }

    @Override
    protected String getMyTitle() {
        // TODO Auto-generated method stub
        return null;
    }

}