+
+ static class AccountListLoader extends Thread {
+ MobileLedgerProfile profile;
+ AccountListLoader(MobileLedgerProfile profile) {
+ this.profile = profile;
+ }
+ @Override
+ public void run() {
+ Logger.debug("async-acc", "AccountListLoader::run() entered");
+ String profileUUID = profile.getUuid();
+ ArrayList<LedgerAccount> list = new ArrayList<>();
+ HashMap<String, LedgerAccount> map = new HashMap<>();
+
+ String sql = "SELECT a.name, a.expanded, a.amounts_expanded";
+ sql += " from accounts a WHERE a.profile = ?";
+ sql += " ORDER BY a.name";
+
+ SQLiteDatabase db = App.getDatabase();
+ Logger.debug("async-acc", "AccountListLoader::run() connected to DB");
+ try (Cursor cursor = db.rawQuery(sql, new String[]{profileUUID})) {
+ Logger.debug("async-acc", "AccountListLoader::run() executed query");
+ while (cursor.moveToNext()) {
+ if (isInterrupted())
+ return;
+
+ final String accName = cursor.getString(0);
+// debug("accounts",
+// String.format("Read account '%s' from DB [%s]", accName,
+// profileUUID));
+ String parentName = LedgerAccount.extractParentName(accName);
+ LedgerAccount parent;
+ if (parentName != null) {
+ parent = map.get(parentName);
+ if (parent == null)
+ throw new IllegalStateException(
+ String.format("Can't load account '%s': parent '%s' not loaded",
+ accName, parentName));
+ parent.setHasSubAccounts(true);
+ }
+ else
+ parent = null;
+
+ LedgerAccount acc = new LedgerAccount(profile, accName, parent);
+ acc.setExpanded(cursor.getInt(1) == 1);
+ acc.setAmountsExpanded(cursor.getInt(2) == 1);
+ acc.setHasSubAccounts(false);
+
+ try (Cursor c2 = db.rawQuery(
+ "SELECT value, currency FROM account_values WHERE profile = ?" + " " +
+ "AND account = ?", new String[]{profileUUID, accName}))
+ {
+ while (c2.moveToNext()) {
+ acc.addAmount(c2.getFloat(0), c2.getString(1));
+ }
+ }
+
+ list.add(acc);
+ map.put(accName, acc);
+ }
+ Logger.debug("async-acc", "AccountListLoader::run() query execution done");
+ }
+
+ if (isInterrupted())
+ return;
+
+ Logger.debug("async-acc", "AccountListLoader::run() posting new list");
+ profile.allAccounts = list;
+ profile.updateAccountsMap(list);
+ profile.updateDisplayedAccounts();
+ }
+ }
+
+ static class AccountListDisplayedFilter extends Thread {
+ private final MobileLedgerProfile profile;
+ private final List<LedgerAccount> list;
+ AccountListDisplayedFilter(MobileLedgerProfile profile, List<LedgerAccount> list) {
+ this.profile = profile;
+ this.list = list;
+ }
+ @Override
+ public void run() {
+ List<LedgerAccount> newDisplayed = new ArrayList<>();
+ Logger.debug("dFilter", "waiting for synchronized block");
+ Logger.debug("dFilter", String.format(Locale.US,
+ "entered synchronized block (about to examine %d accounts)", list.size()));
+ for (LedgerAccount a : list) {
+ if (isInterrupted()) {
+ return;
+ }
+
+ if (a.isVisible()) {
+ newDisplayed.add(a);
+ }
+ }
+ if (!isInterrupted()) {
+ profile.displayedAccounts.postValue(newDisplayed);
+ }
+ Logger.debug("dFilter", "left synchronized block");
+ }
+ }
+
+ private static class AccountListSaver extends Thread {
+ private final MobileLedgerProfile profile;
+ private final List<LedgerAccount> list;
+ private final boolean storeUiFields;
+ AccountListSaver(MobileLedgerProfile profile, List<LedgerAccount> list,
+ boolean storeUiFields) {
+ this.list = list;
+ this.profile = profile;
+ this.storeUiFields = storeUiFields;
+ }
+ @Override
+ public void run() {
+ SQLiteDatabase db = App.getDatabase();
+ db.beginTransactionNonExclusive();
+ try {
+ profile.markAccountsAsNotPresent(db);
+ if (isInterrupted())
+ return;
+ for (LedgerAccount acc : list) {
+ profile.storeAccount(db, acc, storeUiFields);
+ if (isInterrupted())
+ return;
+ }
+ profile.deleteNotPresentAccounts(db);
+ if (isInterrupted())
+ return;
+ profile.setLastUpdateStamp();
+ db.setTransactionSuccessful();
+ }
+ finally {
+ db.endTransaction();
+ }
+ }
+ }
+
+ private static class TransactionListSaver extends Thread {
+ private final MobileLedgerProfile profile;
+ private final List<LedgerTransaction> list;
+ TransactionListSaver(MobileLedgerProfile profile, List<LedgerTransaction> list) {
+ this.list = list;
+ this.profile = profile;
+ }
+ @Override
+ public void run() {
+ SQLiteDatabase db = App.getDatabase();
+ db.beginTransactionNonExclusive();
+ try {
+ profile.markTransactionsAsNotPresent(db);
+ if (isInterrupted())
+ return;
+ for (LedgerTransaction tr : list) {
+ profile.storeTransaction(db, tr);
+ if (isInterrupted())
+ return;
+ }
+ profile.deleteNotPresentTransactions(db);
+ if (isInterrupted())
+ return;
+ profile.setLastUpdateStamp();
+ db.setTransactionSuccessful();
+ }
+ finally {
+ db.endTransaction();
+ }
+ }
+ }
+
+ private static class AccountAndTransactionListSaver extends Thread {
+ private final MobileLedgerProfile profile;
+ private final List<LedgerAccount> accounts;
+ private final List<LedgerTransaction> transactions;
+ private final boolean storeAccUiFields;
+ AccountAndTransactionListSaver(MobileLedgerProfile profile, List<LedgerAccount> accounts,
+ List<LedgerTransaction> transactions,
+ boolean storeAccUiFields) {
+ this.accounts = accounts;
+ this.transactions = transactions;
+ this.profile = profile;
+ this.storeAccUiFields = storeAccUiFields;
+ }
+ @Override
+ public void run() {
+ SQLiteDatabase db = App.getDatabase();
+ db.beginTransactionNonExclusive();
+ try {
+ profile.markAccountsAsNotPresent(db);
+ if (isInterrupted())
+ return;
+
+ profile.markTransactionsAsNotPresent(db);
+ if (isInterrupted()) {
+ return;
+ }
+
+ for (LedgerAccount acc : accounts) {
+ profile.storeAccount(db, acc, storeAccUiFields);
+ if (isInterrupted())
+ return;
+ }
+
+ for (LedgerTransaction tr : transactions) {
+ profile.storeTransaction(db, tr);
+ if (isInterrupted()) {
+ return;
+ }
+ }
+
+ profile.deleteNotPresentAccounts(db);
+ if (isInterrupted()) {
+ return;
+ }
+ profile.deleteNotPresentTransactions(db);
+ if (isInterrupted())
+ return;
+
+ profile.setLastUpdateStamp();
+
+ db.setTransactionSuccessful();
+ }
+ finally {
+ db.endTransaction();
+ }
+ }
+ }