001: /*
002: *
003: * JMoney - A Personal Finance Manager
004: * Copyright (c) 2006 Nigel Westbury <westbury@users.sourceforge.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.reconciliation.reconcilePage;
024:
025: import java.net.URL;
026: import java.util.Iterator;
027: import java.util.regex.Pattern;
028: import java.util.regex.PatternSyntaxException;
029:
030: import net.sf.jmoney.fields.AccountControl;
031: import net.sf.jmoney.isolation.TransactionManager;
032: import net.sf.jmoney.model2.Account;
033: import net.sf.jmoney.model2.AccountCellEditor;
034: import net.sf.jmoney.model2.ExtendableObject;
035: import net.sf.jmoney.model2.IncomeExpenseAccount;
036: import net.sf.jmoney.model2.ObjectCollection;
037: import net.sf.jmoney.model2.ScalarPropertyAccessor;
038: import net.sf.jmoney.reconciliation.MemoPattern;
039: import net.sf.jmoney.reconciliation.MemoPatternInfo;
040: import net.sf.jmoney.reconciliation.ReconciliationAccount;
041: import net.sf.jmoney.reconciliation.ReconciliationAccountInfo;
042: import net.sf.jmoney.reconciliation.ReconciliationPlugin;
043:
044: import org.eclipse.jface.dialogs.Dialog;
045: import org.eclipse.jface.dialogs.DialogMessageArea;
046: import org.eclipse.jface.dialogs.IDialogConstants;
047: import org.eclipse.jface.dialogs.IMessageProvider;
048: import org.eclipse.jface.resource.ImageDescriptor;
049: import org.eclipse.jface.viewers.CellEditor;
050: import org.eclipse.jface.viewers.ColumnLabelProvider;
051: import org.eclipse.jface.viewers.ColumnViewerEditor;
052: import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
053: import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy;
054: import org.eclipse.jface.viewers.EditingSupport;
055: import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter;
056: import org.eclipse.jface.viewers.IStructuredContentProvider;
057: import org.eclipse.jface.viewers.IStructuredSelection;
058: import org.eclipse.jface.viewers.TableViewer;
059: import org.eclipse.jface.viewers.TableViewerColumn;
060: import org.eclipse.jface.viewers.TableViewerEditor;
061: import org.eclipse.jface.viewers.TableViewerFocusCellManager;
062: import org.eclipse.jface.viewers.TextCellEditor;
063: import org.eclipse.jface.viewers.Viewer;
064: import org.eclipse.jface.viewers.ViewerSorter;
065: import org.eclipse.swt.SWT;
066: import org.eclipse.swt.custom.StackLayout;
067: import org.eclipse.swt.events.SelectionAdapter;
068: import org.eclipse.swt.events.SelectionEvent;
069: import org.eclipse.swt.graphics.Image;
070: import org.eclipse.swt.graphics.Rectangle;
071: import org.eclipse.swt.layout.GridData;
072: import org.eclipse.swt.layout.GridLayout;
073: import org.eclipse.swt.widgets.Button;
074: import org.eclipse.swt.widgets.Composite;
075: import org.eclipse.swt.widgets.Control;
076: import org.eclipse.swt.widgets.Label;
077: import org.eclipse.swt.widgets.Shell;
078: import org.eclipse.swt.widgets.Table;
079: import org.eclipse.swt.widgets.Text;
080:
081: /**
082: * An input dialog that allows the user to configure the methods for importing statement data
083: * for a particular account.
084: *
085: * @author Nigel Westbury
086: */
087: class ImportOptionsDialog extends Dialog {
088:
089: private TransactionManager transactionManager;
090:
091: /**
092: * The account for which we are configuring, which is in our own transaction.
093: */
094: ReconciliationAccount account;
095:
096: private DialogMessageArea messageArea;
097:
098: Button reconcilableButton;
099:
100: // The table viewer
101: TableViewer viewer;
102:
103: private AccountControl<IncomeExpenseAccount> defaultAccountControl;
104:
105: /**
106: * Ok button widget.
107: */
108: private Button okButton;
109:
110: /**
111: * Error message label widget.
112: */
113: private Text errorMessageText;
114:
115: Image errorImage;
116:
117: /**
118: * When adding new patterns, we add to the end by default.
119: * We must set an index that is more than all prior ordering
120: * indexes. This field contains the lowest integer that is
121: * more than all existing values (or 0 if no patterns
122: * currently exist).
123: */
124: int nextOrderingIndex;
125:
126: /**
127: * Creates an input dialog with OK and Cancel buttons. Note that the dialog
128: * will have no visual representation (no widgets) until it is told to open.
129: * <p>
130: * Note that the <code>open</code> method blocks for input dialogs.
131: * </p>
132: *
133: * @param parentShell
134: * the parent shell
135: */
136: public ImportOptionsDialog(Shell parentShell,
137: ReconciliationAccount account) {
138: super (parentShell);
139: /*
140: * All changes within this dialog are made within a transaction, so cancelling
141: * is trivial (the transaction is simply not committed).
142: */
143: transactionManager = new TransactionManager(account
144: .getDataManager());
145: ExtendableObject accountInTransaction = transactionManager
146: .getCopyInTransaction(account.getBaseObject());
147: this .account = accountInTransaction.getExtension(
148: ReconciliationAccountInfo.getPropertySet(), true);
149:
150: // Load the error indicator
151: URL installURL = ReconciliationPlugin.getDefault().getBundle()
152: .getEntry("/icons/error.gif");
153: errorImage = ImageDescriptor.createFromURL(installURL)
154: .createImage();
155:
156: // Find an ordering index that is greater than all existing ordering indexes,
157: // so new patterns can be added after all others.
158: nextOrderingIndex = 0;
159: for (MemoPattern pattern : account.getPatternCollection()) {
160: if (nextOrderingIndex <= pattern.getOrderingIndex()) {
161: nextOrderingIndex = pattern.getOrderingIndex() + 1;
162: }
163: }
164: }
165:
166: @Override
167: protected void buttonPressed(int buttonId) {
168: if (buttonId == IDialogConstants.OK_ID) {
169:
170: boolean isReconcilable = reconcilableButton.getSelection();
171: account.setReconcilable(isReconcilable);
172:
173: if (isReconcilable) {
174: // TODO: implement decorators etc. and stop OK being pressed if
175: // no account is selected.
176: IncomeExpenseAccount defaultCategory = defaultAccountControl
177: .getAccount();
178:
179: if (defaultCategory == null) {
180: // TODO: Set the error message.
181: return;
182: }
183:
184: account.setDefaultCategory(defaultCategory);
185: } else {
186: account.setDefaultCategory(null);
187: }
188:
189: transactionManager.commit("Change Import Options");
190: }
191: super .buttonPressed(buttonId);
192: }
193:
194: @Override
195: protected void configureShell(Shell shell) {
196: super .configureShell(shell);
197: shell.setText("Import Options for " + account.getName());
198: }
199:
200: @Override
201: public boolean close() {
202: boolean closed = super .close();
203:
204: // Dispose the image
205: if (closed) {
206: errorImage.dispose();
207: }
208:
209: return closed;
210: }
211:
212: @Override
213: protected void createButtonsForButtonBar(Composite parent) {
214: // create OK and Cancel buttons by default
215: okButton = createButton(parent, IDialogConstants.OK_ID,
216: IDialogConstants.OK_LABEL, true);
217: createButton(parent, IDialogConstants.CANCEL_ID,
218: IDialogConstants.CANCEL_LABEL, false);
219: }
220:
221: @Override
222: protected Control createDialogArea(Composite parent) {
223: Composite composite = (Composite) super
224: .createDialogArea(parent);
225: composite.setLayout(new GridLayout(1, false));
226:
227: // Message label
228: messageArea = new DialogMessageArea();
229: messageArea.createContents(composite);
230:
231: // What are these for?
232: // messageArea.setTitleLayoutData(createMessageAreaData());
233: // messageArea.setMessageLayoutData(createMessageAreaData());
234:
235: Label label = new Label(composite, SWT.WRAP);
236: label
237: .setText("JMoney allows you to import bank account statements from the bank's servers. "
238: + "Before these records can be imported into JMoney, categories must be assigned to each entry "
239: + "because a requirement of JMoney is that all entries have an account or category assigned. "
240: + "Select here the category that is to be initially assigned to each imported entry.");
241:
242: GridData messageData = new GridData();
243: Rectangle rect = getShell().getMonitor().getClientArea();
244: messageData.widthHint = rect.width / 2;
245: label.setLayoutData(messageData);
246:
247: reconcilableButton = new Button(composite, SWT.CHECK);
248: reconcilableButton.setText("Statements can be imported?");
249:
250: final Composite stackContainer = new Composite(composite, 0);
251:
252: final StackLayout stackLayout = new StackLayout();
253: stackContainer.setLayout(stackLayout);
254:
255: GridData containerData = new GridData(GridData.FILL_BOTH);
256: containerData.grabExcessHorizontalSpace = true;
257: containerData.grabExcessVerticalSpace = true;
258: stackContainer.setLayoutData(containerData);
259:
260: // Create the control containing the controls to be shown when 'is reconcilable'
261: final Control whenIsReconcilableControl = createCategoryControls(stackContainer);
262:
263: reconcilableButton.addSelectionListener(new SelectionAdapter() {
264: @Override
265: public void widgetSelected(SelectionEvent e) {
266: if (reconcilableButton.getSelection()) {
267: stackLayout.topControl = whenIsReconcilableControl;
268: } else {
269: stackLayout.topControl = null;
270: }
271: stackContainer.layout(false);
272: }
273: });
274:
275: reconcilableButton.setSelection(account.isReconcilable());
276: if (account.isReconcilable()) {
277: stackLayout.topControl = whenIsReconcilableControl;
278: defaultAccountControl.setAccount(account
279: .getDefaultCategory());
280: }
281:
282: defaultAccountControl
283: .addSelectionListener(new SelectionAdapter() {
284: @Override
285: public void widgetSelected(SelectionEvent e) {
286: updateErrorMessage();
287: }
288: });
289: applyDialogFont(composite);
290: return composite;
291: }
292:
293: private Control createCategoryControls(Composite parent) {
294: Composite composite = new Composite(parent, SWT.NONE);
295: composite.setLayout(new GridLayout(2, false));
296:
297: // Create the table of patterns
298: Control patternMatchingTableControl = createPatternMatchingTableControl(composite);
299: GridData tableData = new GridData(GridData.FILL_BOTH);
300: tableData.horizontalSpan = 2;
301: tableData.grabExcessHorizontalSpace = true;
302: tableData.grabExcessVerticalSpace = true;
303: patternMatchingTableControl.setLayoutData(tableData);
304:
305: // The default category, if no rule matches
306:
307: new Label(composite, SWT.NONE).setText("Default category:");
308: defaultAccountControl = new AccountControl<IncomeExpenseAccount>(
309: composite, account.getSession(),
310: IncomeExpenseAccount.class);
311: GridData accountData = new GridData();
312: accountData.widthHint = 200;
313: defaultAccountControl.setLayoutData(accountData);
314:
315: return composite;
316: }
317:
318: private Control createPatternMatchingTableControl(Composite parent) {
319: Composite composite = new Composite(parent, SWT.NONE);
320: composite.setLayout(new GridLayout(2, false));
321:
322: // Create the table viewer to display the pattern matching rules
323: viewer = new TableViewer(composite, SWT.BORDER
324: | SWT.FULL_SELECTION);
325:
326: // Set up the table
327: final Table table = viewer.getTable();
328: table.setLayoutData(new GridData(GridData.FILL, GridData.FILL,
329: true, true));
330:
331: TableViewerFocusCellManager focusCellManager = new TableViewerFocusCellManager(
332: viewer, new FocusCellOwnerDrawHighlighter(viewer));
333: ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(
334: viewer) {
335: @Override
336: protected boolean isEditorActivationEvent(
337: ColumnViewerEditorActivationEvent event) {
338: return event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL
339: || event.eventType == ColumnViewerEditorActivationEvent.MOUSE_CLICK_SELECTION
340: || (event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED && event.keyCode == SWT.CR)
341: || event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC;
342: }
343: };
344:
345: TableViewerEditor
346: .create(
347: viewer,
348: focusCellManager,
349: actSupport,
350: ColumnViewerEditor.TABBING_HORIZONTAL
351: | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR
352: | ColumnViewerEditor.TABBING_VERTICAL
353: | ColumnViewerEditor.KEYBOARD_ACTIVATION);
354:
355: // Set the content and label providers
356: viewer.setContentProvider(new PatternContentProvider());
357: viewer.setSorter(new PatternSorter());
358:
359: // Add the columns
360: TableViewerColumn column1 = new TableViewerColumn(viewer,
361: SWT.LEFT);
362: column1.getColumn().setWidth(40);
363: column1.getColumn().setText("");
364: column1.setLabelProvider(new ColumnLabelProvider() {
365: @Override
366: public Image getImage(Object element) {
367: MemoPattern pattern = (MemoPattern) element;
368: return isMemoPatternValid(pattern) ? null : errorImage;
369: }
370:
371: @Override
372: public String getText(Object element) {
373: return null;
374: }
375: });
376:
377: column1.setEditingSupport(new EditingSupport(viewer) {
378: @Override
379: protected boolean canEdit(Object element) {
380: return false;
381: }
382:
383: @Override
384: protected CellEditor getCellEditor(Object element) {
385: return null;
386: }
387:
388: @Override
389: protected Object getValue(Object element) {
390: return null;
391: }
392:
393: @Override
394: protected void setValue(Object element, Object value) {
395: }
396: });
397:
398: addColumn(
399: MemoPatternInfo.getPatternAccessor(),
400: "<html>The pattern is a Java regular expression that is matched against the memo in the downloadable file.<br>For each record from the bank, the first row in this table with a matching pattern is used.</html>");
401: addColumn(
402: MemoPatternInfo.getCheckAccessor(),
403: "The value to be put in the check field. The values in this table may contain {0}, [1} etc. where the number matches the group number in the Java regular expression.");
404: addColumn(
405: MemoPatternInfo.getMemoAccessor(),
406: "The value to be put in the memo field. The values in this table may contain {0}, [1} etc. where the number matches the group number in the Java regular expression.");
407: addColumn(MemoPatternInfo.getAccountAccessor(),
408: "The account to be used for entries that match this pattern.");
409: addColumn(
410: MemoPatternInfo.getDescriptionAccessor(),
411: "The value to be put in the description field. The values in this table may contain {0}, [1} etc. where the number matches the group number in the Java regular expression.");
412:
413: /*
414: * Set the account as the input object that contains the list of pattern
415: * matching rules.
416: */
417: viewer.setInput(account);
418:
419: // Pack the columns
420: for (int i = 0, n = table.getColumnCount(); i < n; i++) {
421: table.getColumn(i).pack();
422: }
423:
424: // Turn on the header and the lines
425: table.setHeaderVisible(true);
426: table.setLinesVisible(true);
427:
428: // Create the button area
429: Control buttonAreaControl = createButtonArea(composite);
430: buttonAreaControl.setLayoutData(new GridData(
431: GridData.FILL_VERTICAL));
432:
433: return composite;
434: }
435:
436: protected boolean isMemoPatternValid(MemoPattern pattern) {
437: String patternString = pattern.getPattern();
438: if (patternString != null) {
439: try {
440: Pattern.compile(patternString);
441: return true;
442: } catch (PatternSyntaxException e) {
443: return false;
444: }
445: } else {
446: return true;
447: }
448: }
449:
450: private void addColumn(
451: final ScalarPropertyAccessor<?> propertyAccessor,
452: String tooltip) {
453: TableViewerColumn column = new TableViewerColumn(viewer,
454: SWT.LEFT);
455: column.getColumn().setWidth(propertyAccessor.getMinimumWidth());
456: column.getColumn().setText(propertyAccessor.getDisplayName());
457: column.getColumn().setToolTipText(tooltip);
458:
459: column.setLabelProvider(new ColumnLabelProvider() {
460: @Override
461: public String getText(Object element) {
462: MemoPattern pattern = (MemoPattern) element;
463: return propertyAccessor.formatValueForTable(pattern);
464: }
465:
466: });
467: column.setEditingSupport(new EditingSupport(viewer) {
468: @Override
469: protected boolean canEdit(Object element) {
470: return true;
471: }
472:
473: @Override
474: protected CellEditor getCellEditor(Object element) {
475: if (propertyAccessor == MemoPatternInfo
476: .getAccountAccessor()) {
477: return new AccountCellEditor<Account>(viewer
478: .getTable(), account.getSession(),
479: Account.class);
480: } else {
481: return new TextCellEditor(viewer.getTable());
482: }
483: }
484:
485: @Override
486: protected Object getValue(Object element) {
487: // The text cell editor requires that null is never returned
488: // by this method.
489: MemoPattern pattern = (MemoPattern) element;
490: Object value = pattern
491: .getPropertyValue(propertyAccessor);
492: if (value == null
493: && propertyAccessor.getClassOfValueObject() == String.class) {
494: value = "";
495: }
496: return value;
497: }
498:
499: @Override
500: protected void setValue(Object element, Object value) {
501: MemoPattern pattern = (MemoPattern) element;
502: setValue(pattern, propertyAccessor, value);
503: viewer.update(element, null);
504: }
505:
506: private <V> void setValue(MemoPattern pattern,
507: ScalarPropertyAccessor<V> property, Object value) {
508: V typedValue = property.getClassOfValueObject().cast(
509: value);
510: pattern.setPropertyValue(property, typedValue);
511: }
512: });
513: }
514:
515: private Composite createButtonArea(Composite parent) {
516: Composite container = new Composite(parent, SWT.NONE);
517: GridLayout layout = new GridLayout();
518: layout.marginWidth = 0;
519: layout.marginHeight = 30;
520: container.setLayout(layout);
521:
522: Button button;
523:
524: button = new Button(container, SWT.PUSH);
525: button.setText("Add...");
526: button.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
527: button.addSelectionListener(new SelectionAdapter() {
528: @Override
529: public void widgetSelected(SelectionEvent e) {
530: ObjectCollection<MemoPattern> patterns = account
531: .getPatternCollection();
532: MemoPattern newPattern = patterns
533: .createNewElement(MemoPatternInfo
534: .getPropertySet());
535:
536: newPattern.setOrderingIndex(nextOrderingIndex++);
537:
538: /*
539: * Add the new pattern to the end of the table.
540: */
541: viewer.add(newPattern);
542: }
543: });
544:
545: button = new Button(container, SWT.PUSH);
546: button.setText("Remove");
547: button.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
548: button.addSelectionListener(new SelectionAdapter() {
549: @Override
550: public void widgetSelected(SelectionEvent e) {
551: IStructuredSelection ssel = (IStructuredSelection) viewer
552: .getSelection();
553: if (ssel.size() > 0) {
554: ObjectCollection<MemoPattern> patterns = account
555: .getPatternCollection();
556: for (Iterator<?> iter = ssel.iterator(); iter
557: .hasNext();) {
558: MemoPattern pattern = (MemoPattern) iter.next();
559: patterns.remove(pattern);
560: }
561:
562: /*
563: * We have deleted patterns but remaining patterns are
564: * not affected so labels for the remaining patterns do not
565: * need updating.
566: */
567: viewer.refresh(false);
568: }
569: }
570: });
571:
572: button = new Button(container, SWT.PUSH);
573: button.setText("Up");
574: button.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
575: button.addSelectionListener(new SelectionAdapter() {
576: @Override
577: public void widgetSelected(SelectionEvent e) {
578: IStructuredSelection ssel = (IStructuredSelection) viewer
579: .getSelection();
580: if (ssel.size() == 1) {
581: MemoPattern this Pattern = (MemoPattern) ssel
582: .getFirstElement();
583:
584: // Find the previous MemoPattern in the order.
585: MemoPattern abovePattern = null;
586: ObjectCollection<MemoPattern> patterns = account
587: .getPatternCollection();
588: for (MemoPattern pattern : patterns) {
589: if (pattern.getOrderingIndex() < this Pattern
590: .getOrderingIndex()) {
591: if (abovePattern == null
592: || pattern.getOrderingIndex() > abovePattern
593: .getOrderingIndex()) {
594: abovePattern = pattern;
595: }
596: }
597: }
598:
599: if (abovePattern != null) {
600: swapOrderOfPatterns(this Pattern, abovePattern);
601: }
602:
603: /*
604: * The patterns are re-ordered but the labels are not
605: * affected so do not request a refresh of the labels.
606: */
607: viewer.refresh(false);
608: }
609: }
610: });
611:
612: button = new Button(container, SWT.PUSH);
613: button.setText("Down");
614: button.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
615: button.addSelectionListener(new SelectionAdapter() {
616: @Override
617: public void widgetSelected(SelectionEvent e) {
618: IStructuredSelection ssel = (IStructuredSelection) viewer
619: .getSelection();
620: if (ssel.size() == 1) {
621: MemoPattern this Pattern = (MemoPattern) ssel
622: .getFirstElement();
623:
624: // Find the next MemoPattern in the order.
625: MemoPattern belowPattern = null;
626: ObjectCollection<MemoPattern> patterns = account
627: .getPatternCollection();
628: for (MemoPattern pattern : patterns) {
629: if (pattern.getOrderingIndex() > this Pattern
630: .getOrderingIndex()) {
631: if (belowPattern == null
632: || pattern.getOrderingIndex() < belowPattern
633: .getOrderingIndex()) {
634: belowPattern = pattern;
635: }
636: }
637: }
638:
639: if (belowPattern != null) {
640: swapOrderOfPatterns(this Pattern, belowPattern);
641: }
642:
643: /*
644: * The patterns are re-ordered but the labels are not
645: * affected so do not request a refresh of the labels.
646: */
647: viewer.refresh(false);
648: }
649: }
650: });
651:
652: return container;
653: }
654:
655: /**
656: * Sets or clears the error message.
657: * If not <code>null</code>, the OK button is disabled.
658: *
659: * @param errorMessage
660: * the error message, or <code>null</code> to clear
661: */
662: public void updateErrorMessage() {
663: String errorMessage = null;
664:
665: if (reconcilableButton.getSelection()) {
666: if (defaultAccountControl.getAccount() == null) {
667: errorMessage = "All reconcilable accounts must have a default category set.";
668: } else {
669: // Check the patterns
670: for (MemoPattern pattern : account
671: .getPatternCollection()) {
672: if (!isMemoPatternValid(pattern)) {
673: errorMessage = "There are errors in the patterns below. Hover over the error image to see details.";
674: break;
675: }
676: }
677: }
678: }
679:
680: if (errorMessage == null) {
681: messageArea.clearErrorMessage();
682: } else {
683: messageArea
684: .updateText(errorMessage, IMessageProvider.ERROR);
685: }
686:
687: // errorMessageText.setText(errorMessage == null ? "" : errorMessage); //$NON-NLS-1$
688:
689: // If called during createDialogArea, the okButton
690: // will not have been created yet.
691: if (okButton != null) {
692: okButton.setEnabled(errorMessage == null);
693: }
694: // errorMessageText.getParent().update();
695: }
696:
697: void swapOrderOfPatterns(MemoPattern this Pattern,
698: MemoPattern abovePattern) {
699: // Swap the ordering indexes
700: int this Index = this Pattern.getOrderingIndex();
701: int aboveIndex = abovePattern.getOrderingIndex();
702: abovePattern.setOrderingIndex(this Index);
703: this Pattern.setOrderingIndex(aboveIndex);
704: }
705:
706: /**
707: * This class provides the content for the table
708: */
709: class PatternContentProvider implements IStructuredContentProvider {
710:
711: /**
712: * Gets the elements for the table. The elements are the MemoPattern
713: * objects for the account.
714: */
715: public Object[] getElements(Object input) {
716: ReconciliationAccount account = (ReconciliationAccount) input;
717: return account.getPatternCollection().toArray(
718: new MemoPattern[0]);
719: }
720:
721: /**
722: * Disposes any resources
723: */
724: public void dispose() {
725: // We don't create any resources, so we don't dispose any
726: }
727:
728: /**
729: * Called when the input changes
730: */
731: public void inputChanged(Viewer arg0, Object arg1, Object arg2) {
732: // Nothing to do
733: }
734: }
735:
736: /**
737: * This class implements the sorting for the type catalog table.
738: */
739: class PatternSorter extends ViewerSorter {
740: @Override
741: public int compare(Viewer viewer, Object e1, Object e2) {
742: MemoPattern pattern1 = (MemoPattern) e1;
743: MemoPattern pattern2 = (MemoPattern) e2;
744:
745: return pattern1.getOrderingIndex()
746: - pattern2.getOrderingIndex();
747: }
748: }
749: }
|