Skip to content

Traversing Data

Yogi1967 edited this page Aug 4, 2026 · 4 revisions

Home>Moneydance>Traversing Data

Traversing the Data Model

Context

When Moneydance starts up it creates an 'Application Context' for extensions. This is effectively the connection between extensions and the underlying data (objects).

You gain access to the context by calling

FeatureModuleContext context = getContext();

The Moneydance 'database' is accessed via objects. Moneydance takes care of obtaining the data from the file system and presenting it as a series of instances of the Moneydance classes.

You traverse the data by calling the appropriate methods within the 'context' to gain access to the first level and then you traverse the data model by accessing objects and calling the appropriate methods (see Data Model for the heirarchy).

In 2014 all data was accessed via the RootAccount. In 2015 only the Account heirarchy is accessed via the RootAccount. The rest of the data is accessed via the AccountBook.

RootAccount

Each Account and Category, within Moneydance, is held in an Account object. T There is one special Account called the RootAccount. This is the owner of account data within Moneydance and to gain access to that data you need to have access to the RootAccount.

This is done by calling:

Account root = context().getRootAccount();

AccountBook

The current AccountBook is no longer contained within an AccountBookModel. In fact you should not try and access any AccountBook other than the current one. To gain access to the current AccountBook use:

AccountBook acctBook = context().getCurrentAccountBook();

Accounts and Categories

As mentioned accounts and categories are the same, they are all Accounts. With 2015 a nested class called Account.AccountType has been introduced. This is an enumeration and it determines what type of Account it is.

Accounts are held in a heirarchy, i.e. Each Account can have 0 or more subaccounts but only 1 parent account. You traverse the accounts by getting a list of accounts for a particular Account and then iterating for each account in the list, e.g:

Account Hierarchy

You use getSubAccountCount() to tell you how many subaccounts there are and then you can run through each account using getSubAccount(i).

example:

Account root = context().getRootAccount();
int sz = root.getSubAccountCount();
for(int i=0; i<sz; i++) {
	Account acct = root.getSubAccount(i);
	Account.AccountType accounttype = acct.getAccountType();
	List<Account> l = accounts.get(accounttype);
	if (l == null)
	 accounts.put(accounttype, l=new ArrayList<Account>());
	l.add(acct);
}

This creates a list of accounts at the highest level by AccountType, i.e those below the Root Account.

You can then take each of those accounts and repeat the process, e.g in the above diagram you loop through Account1, Account2 up to Accountn. For Account1 it will give you a subaccount count of 2.

Budgets

When you create a Budget using Budget Manager a BudgetList object is created plus 1 or more Budget objects.

When you enter a value in your budget using the UI it creates a BudgetItem object for that account and that period.

You can gain access to Budget data from the AccountBook:

BudgetList lb = acctBook.getBudgets();
List<Budget> listBudget = lb.getAllBudgets();
int lbc = listBudget.size();
if (lbc > 0) {
	for (int i=0;i<lbc;i++) {
		myNodeObject mynode = new myNodeObject (EXTRAS_BUDGET_ENTRY,listBudget.get(i).getName());
		mynode.setobject(listBudget.get(i));
		dataitem = new DefaultMutableTreeNode(mynode);
		node.add(dataitem);  				
	}
}    		

Address Book

There is one AddressBook and 1 or more AddressEntry.

You access the data from the AccountBook:

AddressBook lab = acctBook.getAddresses();
List<AddressBookEntry> listAddresses = lab.getAllEntries();
int labc = listAddresses.size();
if (labc > 0) {
	for (int i=0;i<labc;i++) {
		myNodeObject mynode = new myNodeObject (EXTRAS_ADDRESS_ENTRY,listAddresses.get(i).getName());
		mynode.setobject(listAddresses.get(i));
		dataitem = new DefaultMutableTreeNode(mynode);
		node.add(dataitem);  				
	}
}

Currencies

The currencies within Moneydance are held within a CurrencyTable. This will be populated with all predefined currencies, not just the ones you have selected. In addition there are entries for securities. If one of your investment accounts holds shares for say, IBM, there will be a currency for IBM. The account will have a balance of the number of shares and a currency of IBM.

The data is accessed via theAccountBook, it is held as an array of CurrencyType. There is a nested class called CurrencyType.Type that determines whether the CurrencyType is a currency or a security.

CurrencyTable lct = acctBook.getCurrencies();
List<CurrencyType> listCurr = lct.getAllCurrencies();
long lctc = lct.getCurrencyCount();
if (node.isLeaf()) {
	if (lctc > 0) {
		for (int i=0;i<lctc;i++) {
			if (listCurr.get(i).getCurrencyType() == CurrencyType.Type.CURRENCY) {
				myNodeObject mynode = new myNodeObject (EXTRAS_CURRENCY_ENTRY,listCurr.get(i).getName());
				mynode.setobject(listCurr.get(i));
				dataitem = new DefaultMutableTreeNode(mynode);
				node.add(dataitem);
			}
		}
	}
}	

Reminders

Reminders are held as a ReminderSet. The set does not exist until there is at least one Reminder.

The data is accessed via the AccountBook, it is held as a list of Reminder:

ReminderSet ls =acctBook.getReminders();
	List<Reminder> listRem = ls.getAllReminders();
	long lsc = listRem.size();
	if (lsc > 0) {
		for (int i=0;i<lsc;i++) {
			myNodeObject mynode = new myNodeObject (EXTRAS_REMINDER_ENTRY,listRem.get(i).getDescription());
			mynode.setobject(listRem.get(i));
			dataitem = new DefaultMutableTreeNode(mynode);
			node.add(dataitem);  				
		}
	}    		

Memorized Items

There are two types of memorized items. Graphs and Reports. With 2015 these are all held within a ReportSpecManager. This not only includes the items you have memorized but also the standard reports, though you can get a list of just the memorized items. There is a separate list for each type.

The data is accessed via the AccountBook, each type is held as a List of ReportSpec:

// list memorized items
ReportSpecManager lm = acctBook.getMemorizedItems();
List<ReportSpec> graphs = lm.getAllGraphs();   // use getMemorizedGraphs for sublist
List<ReportSpec> reports = lm.getAllReports(); // use getMemorizedReports for sublist
/*
 * two types of memorized items, Graphs and Reports
 */
int graphsSize = graphs.size();
int reportsSize = reports.size();
if (graphsSize > 0) {
	/*
	 * add graphs to the tree
	 */
	for (int i=0;i<graphsSize;i++) {
		if (graphs.get(i).isMemorized()) {
			myNodeObject mynode = new myNodeObject (EXTRAS_MEMORIZED_GRAPH_ENTRY,lmgraphs.get(i).getName());
			mynode.setobject(lmgraphs.get(i));
			dataitem = new DefaultMutableTreeNode(mynode);
			node.add(dataitem);  				
		}
	}
}    		
if (reportsSize > 0) {
	/*
	 * add reports to the tree
	 */
	for (int i=0;i<reportsSize;i++) {
		if (reports.get(i).isMemorized()) {
			myNodeObject mynode = new myNodeObject (EXTRAS_MEMORIZED_REPORT_ENTRY,lmreports.get(i).getName());
			mynode.setobject(lmreports.get(i));
			dataitem = new DefaultMutableTreeNode(mynode);
			node.add(dataitem);
		}
	}
}    		

Transactions

Transactions are accessed from the RootAccount. They are held in a TransactionSet. To gain access to them use:

TransactionSet  txnSet = root.getTransactionSet();

You can access the transactions in a number of ways, either as a Enumeration or as a TxnSet. Transactions can be obtained for the whole file or by Account No matter which way you access them the base class is AbstractTxn. This is not an object, it is abstraction. A transaction will either be a ParentTxn or a SplitTxn. You determine what type of transaction it is using the Instanceof operator.

For example:

TransactionSet  txnSet = root.getTransactionSet();
TxnSet e;
e = txnSet.getAllTxns();
for (int i=0;i<e.getSize();i++) {
	AbstractTxn txn = e.getTxn(i);
	AbstractTxn txn2 = null;
	Vector<String> vec = new Vector<String>();
	vec.add(new DecimalFormat("#").format(txn.getTxnId())+" ");
	if (txn.getAccount() == null) {
		vec.add("None");
		ctype = ctgbp;
	}
	else {
		vec.add(txn.getAccount().getAccountName());
		ctype = txn.getAccount().getCurrencyType();
	}
	vec.add(txn.getDescription());
	vec.add(cdate.format(txn.getDateInt()));
	vec.add(ctype.formatFancy(txn.getValue(),'.'));
	if (txn instanceof ParentTxn)
		vec.add("Parent");
	else
		vec.add("Split");
	tranmodel.addRow(vec);
}

Moneydance Development

Mike Bray's migrated Wiki

Clone this wiki locally