/*
* Copyright (c) 2015 Ngewi Fet <ngewif@gmail.com>
*
* 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 org.gnucash.android.ui.account;
import android.database.Cursor;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v4.widget.SimpleCursorAdapter;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.RadioButton;
import android.widget.Spinner;
import android.widget.TextView;
import org.gnucash.android.R;
import org.gnucash.android.app.GnuCashApplication;
import org.gnucash.android.db.DatabaseSchema;
import org.gnucash.android.db.adapter.AccountsDbAdapter;
import org.gnucash.android.db.adapter.SplitsDbAdapter;
import org.gnucash.android.db.adapter.TransactionsDbAdapter;
import org.gnucash.android.model.AccountType;
import org.gnucash.android.ui.common.Refreshable;
import org.gnucash.android.ui.homescreen.WidgetConfigurationActivity;
import org.gnucash.android.util.QualifiedAccountNameCursorAdapter;
import java.util.List;
/**
* Delete confirmation dialog for accounts.
* It is displayed when deleting an account which has transactions or sub-accounts, and the user
* has the option to either move the transactions/sub-accounts, or delete them.
* If an account has no transactions, it is deleted immediately with no confirmation required
*
* @author Ngewi Fet <ngewif@gmail.com>
*/
public class DeleteAccountDialogFragment extends DialogFragment {
/**
* Spinner for selecting the account to move the transactions to
*/
private Spinner mTransactionsDestinationAccountSpinner;
private Spinner mAccountsDestinationAccountSpinner;
/**
* Dialog positive button. Ok to moving the transactions
*/
private Button mOkButton;
/**
* Cancel button
*/
private Button mCancelButton;
/**
* GUID of account from which to move the transactions
*/
private String mOriginAccountUID = null;
private RadioButton mMoveAccountsRadioButton;
private RadioButton mMoveTransactionsRadioButton;
private RadioButton mDeleteAccountsRadioButton;
private RadioButton mDeleteTransactionsRadioButton;
private int mTransactionCount;
private int mSubAccountCount;
/**
* Creates new instance of the delete confirmation dialog and provides parameters for it
* @param accountUID GUID of the account to be deleted
* @return New instance of the delete confirmation dialog
*/
public static DeleteAccountDialogFragment newInstance(String accountUID) {
DeleteAccountDialogFragment fragment = new DeleteAccountDialogFragment();
fragment.mOriginAccountUID = accountUID;
fragment.mSubAccountCount = AccountsDbAdapter.getInstance().getSubAccountCount(accountUID);
fragment.mTransactionCount = TransactionsDbAdapter.getInstance().getTransactionsCount(accountUID);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NORMAL, R.style.CustomDialog);
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_account_delete, container, false);
View transactionOptionsView = view.findViewById(R.id.transactions_options);
((TextView) transactionOptionsView.findViewById(R.id.title_content)).setText(R.string.section_header_transactions);
((TextView) transactionOptionsView.findViewById(R.id.description)).setText(R.string.label_delete_account_transactions_description);
mDeleteTransactionsRadioButton = (RadioButton) transactionOptionsView.findViewById(R.id.radio_delete);
mDeleteTransactionsRadioButton.setText(R.string.label_delete_transactions);
mMoveTransactionsRadioButton = (RadioButton) transactionOptionsView.findViewById(R.id.radio_move);
mTransactionsDestinationAccountSpinner = (Spinner) transactionOptionsView.findViewById(R.id.target_accounts_spinner);
View accountOptionsView = view.findViewById(R.id.accounts_options);
((TextView) accountOptionsView.findViewById(R.id.title_content)).setText(R.string.section_header_subaccounts);
((TextView) accountOptionsView.findViewById(R.id.description)).setText(R.string.label_delete_account_subaccounts_description);
mDeleteAccountsRadioButton = (RadioButton) accountOptionsView.findViewById(R.id.radio_delete);
mDeleteAccountsRadioButton.setText(R.string.label_delete_sub_accounts);
mMoveAccountsRadioButton = (RadioButton) accountOptionsView.findViewById(R.id.radio_move);
mAccountsDestinationAccountSpinner = (Spinner) accountOptionsView.findViewById(R.id.target_accounts_spinner);
transactionOptionsView.setVisibility(mTransactionCount > 0 ? View.VISIBLE : View.GONE);
accountOptionsView.setVisibility(mSubAccountCount > 0 ? View.VISIBLE : View.GONE);
mCancelButton = (Button) view.findViewById(R.id.btn_cancel);
mOkButton = (Button) view.findViewById(R.id.btn_save);
mOkButton.setText(R.string.alert_dialog_ok_delete);
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String accountName = AccountsDbAdapter.getInstance().getAccountName(mOriginAccountUID);
getDialog().setTitle(getString(R.string.alert_dialog_ok_delete) + ": " + accountName);
AccountsDbAdapter accountsDbAdapter = AccountsDbAdapter.getInstance();
List<String> descendantAccountUIDs = accountsDbAdapter.getDescendantAccountUIDs(mOriginAccountUID, null, null);
String currencyCode = accountsDbAdapter.getCurrencyCode(mOriginAccountUID);
AccountType accountType = accountsDbAdapter.getAccountType(mOriginAccountUID);
String transactionDeleteConditions = "(" + DatabaseSchema.AccountEntry.COLUMN_UID + " != ? AND "
+ DatabaseSchema.AccountEntry.COLUMN_CURRENCY + " = ? AND "
+ DatabaseSchema.AccountEntry.COLUMN_TYPE + " = ? AND "
+ DatabaseSchema.AccountEntry.COLUMN_PLACEHOLDER + " = 0 AND "
+ DatabaseSchema.AccountEntry.COLUMN_UID + " NOT IN ('" + TextUtils.join("','", descendantAccountUIDs) + "')"
+ ")";
Cursor cursor = accountsDbAdapter.fetchAccountsOrderedByFullName(transactionDeleteConditions,
new String[]{mOriginAccountUID, currencyCode, accountType.name()});
SimpleCursorAdapter mCursorAdapter = new QualifiedAccountNameCursorAdapter(getActivity(), cursor);
mTransactionsDestinationAccountSpinner.setAdapter(mCursorAdapter);
//target accounts for transactions and accounts have different conditions
String accountMoveConditions = "(" + DatabaseSchema.AccountEntry.COLUMN_UID + " != ? AND "
+ DatabaseSchema.AccountEntry.COLUMN_CURRENCY + " = ? AND "
+ DatabaseSchema.AccountEntry.COLUMN_TYPE + " = ? AND "
+ DatabaseSchema.AccountEntry.COLUMN_UID + " NOT IN ('" + TextUtils.join("','", descendantAccountUIDs) + "')"
+ ")";
cursor = accountsDbAdapter.fetchAccountsOrderedByFullName(accountMoveConditions,
new String[]{mOriginAccountUID, currencyCode, accountType.name()});
mCursorAdapter = new QualifiedAccountNameCursorAdapter(getActivity(), cursor);
mAccountsDestinationAccountSpinner.setAdapter(mCursorAdapter);
setListeners();
//this comes after the listeners because of some useful bindings done there
if (cursor.getCount() == 0){
mMoveAccountsRadioButton.setEnabled(false);
mMoveAccountsRadioButton.setChecked(false);
mDeleteAccountsRadioButton.setChecked(true);
mMoveTransactionsRadioButton.setEnabled(false);
mMoveTransactionsRadioButton.setChecked(false);
mDeleteTransactionsRadioButton.setChecked(true);
mAccountsDestinationAccountSpinner.setVisibility(View.GONE);
mTransactionsDestinationAccountSpinner.setVisibility(View.GONE);
}
}
/**
* Binds click listeners for the dialog buttons
*/
protected void setListeners(){
mMoveAccountsRadioButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mAccountsDestinationAccountSpinner.setEnabled(isChecked);
}
});
mMoveTransactionsRadioButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mTransactionsDestinationAccountSpinner.setEnabled(isChecked);
}
});
mCancelButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
mOkButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AccountsDbAdapter accountsDbAdapter = AccountsDbAdapter.getInstance();
if ((mTransactionCount > 0) && mMoveTransactionsRadioButton.isChecked()){
long targetAccountId = mTransactionsDestinationAccountSpinner.getSelectedItemId();
//move all the splits
SplitsDbAdapter.getInstance().updateRecords(DatabaseSchema.SplitEntry.COLUMN_ACCOUNT_UID + " = ?",
new String[]{mOriginAccountUID}, DatabaseSchema.SplitEntry.COLUMN_ACCOUNT_UID, accountsDbAdapter.getUID(targetAccountId));
}
if ((mSubAccountCount > 0) && mMoveAccountsRadioButton.isChecked()){
long targetAccountId = mAccountsDestinationAccountSpinner.getSelectedItemId();
AccountsDbAdapter.getInstance().reassignDescendantAccounts(mOriginAccountUID, accountsDbAdapter.getUID(targetAccountId));
}
if (GnuCashApplication.isDoubleEntryEnabled()){ //reassign splits to imbalance
TransactionsDbAdapter.getInstance().deleteTransactionsForAccount(mOriginAccountUID);
}
//now kill them all!!
accountsDbAdapter.recursiveDeleteAccount(accountsDbAdapter.getID(mOriginAccountUID));
WidgetConfigurationActivity.updateAllWidgets(getActivity());
((Refreshable)getTargetFragment()).refresh();
dismiss();
}
});
}
}