/******************************************************************************* * 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 ******************************************************************************/ package ru.orangesoftware.financisto2.activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.ListAdapter; import android.widget.TextView; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import ru.orangesoftware.financisto2.R; import ru.orangesoftware.financisto2.model.Account; import ru.orangesoftware.financisto2.model.Budget; import ru.orangesoftware.financisto2.model.Category; import ru.orangesoftware.financisto2.model.Currency; import ru.orangesoftware.financisto2.model.MultiChoiceItem; import ru.orangesoftware.financisto2.model.MyEntity; import ru.orangesoftware.financisto2.model.Project; import ru.orangesoftware.financisto2.utils.RecurUtils; import ru.orangesoftware.financisto2.utils.RecurUtils.Recur; import ru.orangesoftware.financisto2.utils.Utils; import ru.orangesoftware.financisto2.widget.AmountInput; import ru.orangesoftware.financisto2.widget.AmountInput_; public class BudgetActivity extends AbstractActivity { public static final String BUDGET_ID_EXTRA = "budgetId"; private static final int NEW_CATEGORY_REQUEST = 1; private static final int NEW_PROJECT_REQUEST = 2; private static final int RECUR_REQUEST = 3; private AmountInput amountInput; private EditText titleText; private TextView categoryText; private TextView projectText; private TextView accountText; private TextView periodRecurText; private CheckBox cbMode; private CheckBox cbIncludeSubCategories; private CheckBox cbIncludeCredit; private CheckBox cbSavingBudget; private Budget budget = new Budget(); private List<AccountOption> accountOptions; private List<Category> categories; private List<Project> projects; private ListAdapter accountAdapter; private int selectedAccountOption; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.budget); accountOptions = createAccountsList(); accountAdapter = new ArrayAdapter<AccountOption>(this, android.R.layout.simple_spinner_dropdown_item, accountOptions); categories = categoryRepository.loadCategories().asFlatList(); projects = db.getActiveProjectsList(true); LinearLayout layout = (LinearLayout) findViewById(R.id.list); titleText = new EditText(this); x.addEditNode(layout, R.string.title, titleText); accountText = x.addListNode(layout, R.id.account, R.string.account, R.string.select_account); categoryText = x.addListNodePlus(layout, R.id.category, R.id.category_add, R.string.categories, R.string.no_categories); projectText = x.addListNodePlus(layout, R.id.project, R.id.project_add, R.string.projects, R.string.no_projects); cbIncludeSubCategories = x.addCheckboxNode(layout, R.id.include_subcategories, R.string.include_subcategories, R.string.include_subcategories_summary, true); cbMode = x.addCheckboxNode(layout, R.id.budget_mode, R.string.budget_mode, R.string.budget_mode_summary, false); cbIncludeCredit = x.addCheckboxNode(layout, R.id.include_credit, R.string.include_credit, R.string.include_credit_summary, true); cbSavingBudget = x.addCheckboxNode(layout, R.id.type, R.string.budget_type_saving, R.string.budget_type_saving_summary, true); amountInput = AmountInput_.build(this); amountInput.setOwner(this); amountInput.setIncome(); amountInput.disableIncomeExpenseButton(); x.addEditNode(layout, R.string.amount, amountInput); periodRecurText = x.addListNode(layout, R.id.period_recur, R.string.period_recur, R.string.no_recur); Button bOK = (Button) findViewById(R.id.bOK); bOK.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { if (checkSelected(budget.currency != null ? budget.currency : budget.account, R.string.select_account)) { updateBudgetFromUI(); long id = db.insertBudget(budget); Intent intent = new Intent(); intent.putExtra(BUDGET_ID_EXTRA, id); setResult(RESULT_OK, intent); finish(); } } }); Button bCancel = (Button) findViewById(R.id.bCancel); bCancel.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { setResult(RESULT_CANCELED); finish(); } }); Intent intent = getIntent(); if (intent != null) { long id = intent.getLongExtra(BUDGET_ID_EXTRA, -1); if (id != -1) { budget = db.load(Budget.class, id); editBudget(); } else { selectRecur(RecurUtils.createDefaultRecur().toString()); } } } private List<AccountOption> createAccountsList() { List<AccountOption> accounts = new ArrayList<AccountOption>(); List<Currency> currenciesList = db.getAllCurrenciesList("name"); for (Currency currency : currenciesList) { String title = getString(R.string.account_by_currency, currency.name); accounts.add(new AccountOption(title, currency, null)); } List<Account> accountsList = db.getAllAccountsList(); for (Account account : accountsList) { accounts.add(new AccountOption(account.title, null, account)); } return accounts; } private void editBudget() { titleText.setText(budget.title); amountInput.setAmount(budget.amount); updateEntities(this.categories, budget.categories); selectCategories(); updateEntities(this.projects, budget.projects); selectProjects(); selectAccount(budget); selectRecur(budget.recur); cbIncludeSubCategories.setChecked(budget.includeSubcategories); cbIncludeCredit.setChecked(budget.includeCredit); cbMode.setChecked(budget.expanded); cbSavingBudget.setChecked(budget.amount < 0); } private void updateEntities(List<? extends MyEntity> list, String selected) { if (!Utils.isEmpty(selected)) { String[] a = selected.split(","); for (String s : a) { long id = Long.parseLong(s); for (MyEntity e : list) { if (e.id == id) { e.checked = true; break; } } } } } private String getSelectedAsString(List<? extends MyEntity> list) { StringBuilder sb = new StringBuilder(); for (MyEntity e : list) { if (e.checked) { if (sb.length() > 0) { sb.append(","); } sb.append(e.id); } } return sb.length() > 0 ? sb.toString() : ""; } protected void updateBudgetFromUI() { budget.title = titleText.getText().toString(); budget.amount = amountInput.getAmount(); if (cbSavingBudget.isChecked()) { budget.amount = -budget.amount; } budget.includeSubcategories = cbIncludeSubCategories.isChecked(); budget.includeCredit = cbIncludeCredit.isChecked(); budget.expanded = cbMode.isChecked(); budget.categories = getSelectedAsString(categories); budget.projects = getSelectedAsString(projects); } @Override protected void onClick(View v, int id) { switch (id) { case R.id.include_subcategories: cbIncludeSubCategories.performClick(); break; case R.id.include_credit: cbIncludeCredit.performClick(); break; case R.id.budget_mode: cbMode.performClick(); break; case R.id.type: cbSavingBudget.performClick(); break; case R.id.category: x.selectMultiChoice(this, R.id.category, R.string.categories, categories); break; case R.id.category_add: CategoryActivity_.intent(this).startForResult(NEW_CATEGORY_REQUEST); break; case R.id.project: x.selectMultiChoice(this, R.id.project, R.string.projects, projects); break; case R.id.project_add: ProjectActivity_.intent(this).startForResult(NEW_PROJECT_REQUEST); break; case R.id.account: x.selectPosition(this, R.id.account, R.string.account, accountAdapter, selectedAccountOption); break; case R.id.period_recur: { Intent intent = new Intent(this, RecurActivity.class); if (budget.recur != null) { intent.putExtra(RecurActivity.EXTRA_RECUR, budget.recur); } startActivityForResult(intent, RECUR_REQUEST); } break; } } @Override public void onSelectedPos(int id, int selectedPos) { switch (id) { case R.id.account: selectAccount(selectedPos); break; } } @Override public void onSelected(int id, List<? extends MultiChoiceItem> items) { switch (id) { case R.id.category: selectCategories(); break; case R.id.project: selectProjects(); break; } } private void selectAccount(Budget budget) { for (int i=0; i<accountOptions.size(); i++) { AccountOption option = accountOptions.get(i); if (option.matches(budget)) { selectAccount(i); break; } } } private void selectAccount(int selectedPos) { AccountOption option = accountOptions.get(selectedPos); option.updateBudget(budget); selectedAccountOption = selectedPos; accountText.setText(option.title); if (option.currency != null) { amountInput.setCurrency(option.currency); } else { amountInput.setCurrency(option.account.currency); } } private void selectProjects() { String selectedProjects = getCheckedEntities(this.projects); if (Utils.isEmpty(selectedProjects)) { projectText.setText(R.string.no_projects); } else { projectText.setText(selectedProjects); } } private void selectCategories() { String selectedCategories = getCheckedEntities(this.categories); if (Utils.isEmpty(selectedCategories)) { categoryText.setText(R.string.no_categories); } else { categoryText.setText(selectedCategories); } } private String getCheckedEntities(List<? extends MyEntity> list) { StringBuilder sb = new StringBuilder(); for (MyEntity e : list) { if (e.checked) { if (sb.length() > 0) { sb.append(", "); } sb.append(e.title); } } return sb.toString(); } private void selectRecur(String recur) { if (recur != null) { budget.recur = recur; Recur r = RecurUtils.createFromExtraString(recur); periodRecurText.setText(r.toString(this)); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { if (amountInput.processActivityResult(requestCode, data)) { return; } switch (requestCode) { case NEW_CATEGORY_REQUEST: categories = merge(categories, categoryRepository.loadCategories().asFlatList()); break; case NEW_PROJECT_REQUEST: projects = merge(projects, db.getActiveProjectsList(true)); break; case RECUR_REQUEST: String recur = data.getStringExtra(RecurActivity.EXTRA_RECUR); if (recur != null) { selectRecur(recur); } break; default: break; } } } private static <T extends MyEntity> List<T> merge(List<T> oldList, List<T> newList) { for (T newT : newList) { for (Iterator<T> i = oldList.iterator(); i.hasNext(); ) { T oldT = i.next(); if (newT.id == oldT.id) { newT.checked = oldT.checked; i.remove(); break; } } } return newList; } private static class AccountOption { public final String title; public final Currency currency; public final Account account; private AccountOption(String title, Currency currency, Account account) { this.title = title; this.currency = currency; this.account = account; } @Override public String toString() { return title; } public boolean matches(Budget budget) { return (currency != null && budget.currency != null && currency.id == budget.currency.id) || (account != null && budget.account != null && account.id == budget.account.id); } public void updateBudget(Budget budget) { budget.currency = currency; budget.account = account; } } }