001: /*
002: *
003: * JMoney - A Personal Finance Manager
004: * Copyright (c) 2008 Nigel Westbury <westbury@users.sf.net>
005: *
006: *
007: * This program is free software; you can redistribute it and/or modify
008: * it under the terms of the GNU General Public License as published by
009: * the Free Software Foundation; either version 2 of the License, or
010: * (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
020: *
021: */
022:
023: package net.sf.jmoney.entrytable;
024:
025: import java.util.HashMap;
026: import java.util.Map;
027:
028: import net.sf.jmoney.model2.SessionChangeListener;
029:
030: import org.eclipse.swt.SWT;
031: import org.eclipse.swt.events.FocusListener;
032: import org.eclipse.swt.events.PaintEvent;
033: import org.eclipse.swt.events.PaintListener;
034: import org.eclipse.swt.graphics.Color;
035: import org.eclipse.swt.widgets.Composite;
036: import org.eclipse.swt.widgets.Control;
037: import org.eclipse.swt.widgets.Display;
038:
039: /**
040: * This is used in rows only, not for headers.
041: * (anything to be gained by using it in headers too????)
042: */
043: public class StackControl<T extends EntryData, R extends RowControl<T, R>>
044: extends Composite implements ICellControl<T> {
045:
046: private R rowControl;
047:
048: private StackBlock<T, R> stackBlock;
049:
050: /**
051: * Maps each child block to the child control of the stack composite
052: * that shows that block in the header.
053: */
054: private Map<Block, Composite> childControls = new HashMap<Block, Composite>();
055:
056: private CompressedStackLayout stackLayout;
057:
058: // private Composite blankControl = null;
059:
060: private T entryData;
061:
062: /* Listen for changes that might affect the top block.
063: * Changes may originate from within this row control, or the
064: * changes may come from other parts that have committed changes
065: * and those changes are then seen in this transaction.
066: */
067: private SessionChangeListener transactionChangeListener = null;
068:
069: public StackControl(Composite parent, R rowControl,
070: StackBlock<T, R> stackBlock) {
071: super (parent, SWT.NONE);
072: this .rowControl = rowControl;
073: this .stackBlock = stackBlock;
074:
075: stackLayout = new CompressedStackLayout();
076: setLayout(stackLayout);
077: }
078:
079: public void load(final T entryData) {
080: // TODO: this should be done in a 'row release' method??
081: if (this .entryData != null) {
082: this .entryData.getEntry().getDataManager()
083: .removeChangeListener(transactionChangeListener);
084: }
085:
086: this .entryData = entryData;
087:
088: Block<? super T, ? super R> topBlock = stackBlock
089: .getTopBlock(entryData);
090: setTopBlock(topBlock);
091:
092: transactionChangeListener = stackBlock.createListener(
093: entryData, this );
094: entryData.getEntry().getDataManager().addChangeListener(
095: transactionChangeListener);
096: }
097:
098: public void save() {
099: // TODO Do we need to pass this on to the child controls?
100: }
101:
102: /**
103: * This method may change the preferred height of the row. It is
104: * the caller's responsibility to resize the row to its preferred
105: * height after calling this method.
106: *
107: * @param topBlock
108: */
109: public void setTopBlock(Block<? super T, ? super R> topBlock) {
110: // First set the top control in this row
111: Composite topControl;
112: if (topBlock == null) {
113: // if (blankControl == null) {
114: // blankControl = new Composite(this, SWT.NULL);
115: // }
116: // topControl = blankControl;
117: topControl = null; // Causes nothing to show in stacked composite
118: } else {
119: topControl = childControls.get(topBlock);
120: if (topControl == null) {
121: topControl = new Composite(this , SWT.NULL);
122: final BlockLayout<T> childLayout = new BlockLayout<T>(
123: topBlock, false);
124: topControl.setLayout(childLayout);
125:
126: for (CellBlock<? super T, ? super R> cellBlock : topBlock
127: .buildCellList()) {
128: rowControl.createCellControl(topControl, cellBlock);
129: }
130:
131: final Composite finalTopControl = topControl;
132: topControl.addPaintListener(new PaintListener() {
133: public void paintControl(PaintEvent e) {
134: Color oldColor = e.gc.getBackground();
135: // TODO: move colors to single location
136: Color secondaryColor = Display.getDefault()
137: .getSystemColor(
138: SWT.COLOR_WIDGET_NORMAL_SHADOW);
139:
140: try {
141: e.gc.setBackground(secondaryColor);
142: childLayout.paintRowLines(e.gc,
143: finalTopControl);
144: } finally {
145: e.gc.setBackground(oldColor);
146: }
147: }
148: });
149:
150: childControls.put(topBlock, topControl);
151: }
152: }
153: stackLayout.topControl = topControl;
154:
155: // Fire event that tells header to change
156: if (rowControl instanceof BaseEntryRowControl
157: && ((BaseEntryRowControl) rowControl).isSelected()) {
158: stackBlock.setTopHeaderBlock(topBlock, entryData);
159: }
160: }
161:
162: public Control getControl() {
163: return this ;
164: }
165:
166: public void setFocusListener(FocusListener controlFocusListener) {
167: // TODO Auto-generated method stub
168:
169: }
170: }
|