package com.hdweiss.morgand.gui.outline; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import com.hdweiss.morgand.R; import com.hdweiss.morgand.data.dao.OrgNode; import com.hdweiss.morgand.data.dao.OrgNodeRepository; import com.hdweiss.morgand.gui.theme.DefaultTheme; import com.hdweiss.morgand.utils.Utils; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; public class OutlineAdapter extends ArrayAdapter<OrgNode> { private ArrayList<Boolean> expanded = new ArrayList<Boolean>(); private ArrayList<Integer> level = new ArrayList<Integer>(); private DefaultTheme theme; private boolean agendaMode = false; public OutlineAdapter(Context context) { super(context, R.layout.outline_item); this.theme = DefaultTheme.getTheme(context); init(); } public void init() { clear(); for (OrgNode node : OrgNodeRepository.getRootNodes()) add(node); notifyDataSetInvalidated(); } public long[] getNodeState() { int count = getCount(); long[] state = new long[count]; for(int i = 0; i < count; i++) state[i] = getItem(i).Id; return state; } public ArrayList<Integer> getLevelState() { return this.level; } public boolean[] getExpandedState() { return Utils.toPrimitiveArray(this.expanded); } public void setState(long[] state, ArrayList<Integer> levels, boolean[] expanded) { clear(); for(int i = 0; i < state.length; i++) { try { OrgNode node = OrgNodeRepository.queryForId((int) state[i]); if (node == null) throw new IllegalStateException("Give OutlineAdapter state is invalid, node with id " + state[i] + " not found"); add(node); } catch(Exception ex) {} } this.expanded.clear(); for(boolean expand: expanded) this.expanded.add(expand); this.level = levels; } public void refresh() { ArrayList<Long> expandedNodeIds = new ArrayList<Long>(); int size = this.expanded.size(); for(int i = 0; i < size; i++) { if(this.expanded.get(i)) expandedNodeIds.add(getItemId(i)); } init(); expandNodes(expandedNodeIds); } private void expandNodes(ArrayList<Long> nodeIds) { while (nodeIds.size() != 0) { Long nodeId = nodeIds.get(0); for (int nodesPosition = 0; nodesPosition < getCount(); nodesPosition++) { if (getItemId(nodesPosition) == nodeId) { expand(nodesPosition); break; } } nodeIds.remove(0); } } @Override public View getView(int position, View convertView, ViewGroup parent) { OutlineItemView outlineItemView = (OutlineItemView) convertView; if (convertView == null) outlineItemView = new OutlineItemView(getContext()); outlineItemView.setAgendaMode(agendaMode); OrgNode node = getItem(position); if (node != null) outlineItemView.setup(node, getExpanded(position), getLevel(position), theme); return outlineItemView; } public void setAgendaMode(boolean agendaMode) { this.agendaMode = agendaMode; } @Override public void clear() { super.clear(); this.expanded.clear(); this.level.clear(); } @Override public void add(OrgNode node) { super.add(node); this.expanded.add(false); this.level.add(0); } @Override public void insert(OrgNode node, int index) { super.insert(node, index); this.expanded.add(index, false); int level = index > 0 ? this.level.get(index - 1) + 1 : 0; this.level.add(index, level); } public void insertAll(Collection<OrgNode> nodes, int position) { ArrayList<OrgNode> orgNodes = new ArrayList<OrgNode>(nodes); Collections.reverse(orgNodes); for(OrgNode node: orgNodes) insert(node, position); notifyDataSetInvalidated(); } @Override public void remove(OrgNode node) { int position = getPosition(node); this.expanded.remove(position); this.level.remove(position); super.remove(node); } public boolean getExpanded(int position) { if(position < 0 || position > this.expanded.size()) return false; return this.expanded.get(position); } public int getLevel(int position) { if (position < 0 || position > this.level.size()) return 0; return this.level.get(position); } public void collapseExpand(int position) { if(position >= getCount() || position >= this.expanded.size() || position < 0) return; if(this.expanded.get(position)) collapse(position); else expand(position); } /** * @param doubleClicked Whether user clicked node the second time * @return true expandAll was called */ public boolean collapseExpandExpandAll(int position, boolean doubleClicked) { if(position >= getCount() || position >= this.expanded.size() || position < 0) return false; if(this.expanded.get(position)) { if (doubleClicked) { expandAll(position); return true; } else { collapse(position); return false; } } else { expand(position); return false; } } public void collapse(int position) { int activePos = position + 1; while(activePos < this.expanded.size()) { if(getLevel(activePos) <= getLevel(position)) break; collapse(activePos); remove(getItem(activePos)); } this.expanded.set(position, false); } public void collapseAll() { for(int activePos = 0; activePos < expanded.size(); activePos++) { if (expanded.get(activePos)) collapse(activePos); } } public ArrayList<OrgNode> expand(int position) { OrgNode node = getItem(position); ArrayList<OrgNode> children = node.getDisplayChildren(); if (node.type == OrgNode.Type.Directory) Collections.sort(children, new OrgNode.OrgNodeCompare()); insertAll(children, position + 1); this.expanded.set(position, true); return children; } public void expandAll(int position) { collapse(position); // TODO Hack ArrayList<OrgNode> expandedChildren = expand(position); for(OrgNode node: expandedChildren) { int nodePosition = getPosition(node); expandAll(nodePosition); } } @Override public long getItemId(int position) { return getItem(position).Id; } public int findParent(int position) { if(position >= getCount() || position < 0) return -1; for(int activePos = position - 1; activePos >= 0; activePos--) { if(getLevel(activePos) < getLevel(position)) return activePos; } return -1; } }