/* * Copyright 2004-2007 IDCA. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the * following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and * the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are those of the authors and * should not be interpreted as representing official policies, either expressed or implied, of IDCA. */ package com.idcanet.vasc.frontends.swt; import java.io.FileOutputStream; import java.io.OutputStream; import java.util.logging.Level; import java.util.logging.Logger; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; import com.idcanet.vasc.core.AbstractVascFrontend; import com.idcanet.vasc.core.VascEntry; import com.idcanet.vasc.core.VascEntryField; import com.idcanet.vasc.core.VascException; import com.idcanet.vasc.core.VascFrontendData; import com.idcanet.vasc.core.actions.GlobalVascAction; import com.idcanet.vasc.core.actions.RowVascAction; import com.idcanet.vasc.core.entry.VascEntryFrontendEventListener; import com.idcanet.vasc.core.entry.VascEntryExporter; import com.idcanet.vasc.core.entry.VascEntryFrontendEventListener.VascFrontendEventType; import com.idcanet.vasc.core.ui.VascOptionValueModelListener; import com.idcanet.vasc.core.ui.VascUIComponent; import com.idcanet.vasc.core.ui.VascValueModel; import com.idcanet.vasc.core.ui.VascValueModelListener; import com.idcanet.vasc.frontends.swt.ui.SwtBoolean; import com.idcanet.vasc.frontends.swt.ui.SwtButton; import com.idcanet.vasc.frontends.swt.ui.SwtLabel; import com.idcanet.vasc.frontends.swt.ui.SwtList; import com.idcanet.vasc.frontends.swt.ui.SwtText; import com.idcanet.vasc.frontends.swt.ui.SwtTextArea; /** * * @author Willem Cazander * @version 1.0 Mar 21, 2007 */ public class SwtVascFrontend extends AbstractVascFrontend { private Logger logger = null; private Composite parent = null; private boolean renderGlobalActions = true; public SwtVascFrontend(Composite parent) { logger = Logger.getLogger(SwtVascFrontend.class.getName()); this.parent=parent; } /** * Add swt implmented ui components */ protected void addUiComponents() { VascFrontendData vfd = getVascEntry().getVascFrontendData(); // required UI components vfd.putVascUIComponent(VascUIComponent.VASC_LABEL,SwtLabel.class.getName()); vfd.putVascUIComponent(VascUIComponent.VASC_TEXT, SwtText.class.getName()); vfd.putVascUIComponent(VascUIComponent.VASC_BUTTON, SwtButton.class.getName()); vfd.putVascUIComponent(VascUIComponent.VASC_LIST, SwtList.class.getName()); // optional UI components vfd.putVascUIComponent(VascUIComponent.VASC_BOOLEAN , SwtBoolean.class.getName()); //vfd.putVascUIComponent(VascUIComponent.VASC_DATE , SwtDate.class.getName()); vfd.putVascUIComponent(VascUIComponent.VASC_TEXTAREA, SwtTextArea.class.getName()); //vfd.putVascUIComponent(VascUIComponent.VASC_COLOR, SwtColorChooser.class.getName()); } /** * @return the renderGlobalActions */ public boolean isRenderGlobalActions() { return renderGlobalActions; } /** * @param renderGlobalActions the renderGlobalActions to set */ public void setRenderGlobalActions(boolean renderGlobalActions) { this.renderGlobalActions = renderGlobalActions; } @Override protected Object i18nImage(String key) { if (entry.getVascFrontendData().getVascEntryResourceImageResolver()==null) { return null; } return entry.getVascFrontendData().getVascEntryResourceImageResolver().getImageValue(entry,key); } private static final String[] FILTER_NAMES = { "All Files (*.*)", "Comma Separated Values Files (*.csv)", "Microsoft Excel Spreadsheet Files (*.xls)", }; /** These filter extensions are used to filter which files are displayed. */ private static final String[] FILTER_EXTS = { "*.*","*.csv","*.xls" }; public void renderExport(VascEntryExporter exporter) throws Exception { FileDialog dlg = new FileDialog(Display.getCurrent().getActiveShell(), SWT.SAVE); dlg.setFilterNames(FILTER_NAMES); dlg.setFilterExtensions(FILTER_EXTS); dlg.setFileName(entry.getName()+".csv"); String fileName = dlg.open(); logger.fine("FileName: "+fileName); if (fileName == null) { return; } OutputStream out = new FileOutputStream(fileName); try { exporter.doExport(out, entry); } catch (Exception e) { //MessageDialog.openError(Display.getCurrent().getActiveShell(),crudTable.i18n("crud.event.export.error.title"),crudTable.i18n("crud.event.export.error.message")); logger.log(Level.WARNING,"Error: "+e.getMessage(),e); } finally { if (out!=null) { out.close(); } } } public void renderEdit() throws Exception { logger.fine("Rending Edit View"); SwtVascEditDialog dialog = new SwtVascEditDialog(entry); dialog.open(); } public void renderDelete() throws Exception { boolean del = askDelete( Display.getCurrent().getActiveShell() ); if (del==false) { return; } // yes entry.getVascFrontendData().getVascFrontendHelper().deleteObject(entry); } private boolean askDelete(Shell shell) { logger.finest("Asking for delete"); MessageBox askDelete = new MessageBox(shell,SWT.ICON_QUESTION|SWT.YES|SWT.NO); askDelete.setText(i18n("crud.event.delete.confim.title")); askDelete.setMessage(i18n("crud.event.delete.confim.question")); int state = askDelete.open(); if (state == SWT.YES) { return true; } return false; } public void renderView() throws Exception { GridLayout layout = new GridLayout(); layout.marginHeight = 0; layout.marginWidth = 0; parent.setLayout(layout); Composite header = new Composite(parent, SWT.NONE); GridLayout headerLayout = new GridLayout(); headerLayout.numColumns = 6; header.setLayout(headerLayout); header.setLayoutData(new GridData(SWT.NONE)); Composite body = new Composite(parent, SWT.NONE); GridLayout bodyLayout = new GridLayout(); bodyLayout.numColumns = 1; body.setLayout(bodyLayout); body.setLayoutData(new GridData(GridData.FILL_BOTH)); Composite footer = new Composite(parent, SWT.NONE); GridLayout footerLayout = new GridLayout(); footerLayout.numColumns = 6; footer.setLayout(footerLayout); footer.setLayoutData(new GridData(SWT.NONE)); createHeader(header); createBody(body); createFooter(footer); } public void createHeader(Composite header) { logger.finest("Creating header"); Color c = header.getDisplay().getSystemColor(SWT.COLOR_WHITE); GridLayout layout = new GridLayout(); layout.marginHeight = 0; layout.marginWidth = 0; layout.marginTop = 0; header.setLayout(layout); header.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); header.setBackground(c); if (isRenderGlobalActions()) { Composite headerBar = new Composite(header, SWT.NONE); //GridLayout headerLayout = new GridLayout(); //headerLayout.numColumns = 1; headerBar.setLayout(new FillLayout()); //headerBar.setLayoutData(new GridData(GridData.FILL_BOTH)); ToolBar toolBar = new ToolBar(headerBar, SWT.NONE); for (GlobalVascAction action:entry.getGlobalActions()) { if (entry.getVascFrontendData().getVascFrontendHelper().renderGlobalVascAction(action)==false) { continue; } ToolItem item = new ToolItem(toolBar, SWT.PUSH); item.setText(i18n(action.getName())); item.setToolTipText(i18n(action.getDescription())); item.setImage((Image)i18nImage(action.getImage())); item.addSelectionListener(new GlobalActionListener(action)); } } Composite headerName = new Composite(header, SWT.NONE); GridLayout bodyLayout = new GridLayout(); bodyLayout.numColumns = 2; headerName.setLayout(bodyLayout); headerName.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); headerName.setBackground(c); Label l = new Label(headerName, SWT.CENTER); l.setImage((Image)i18nImage(entry.getListImage())); l.setBackground(c); Font headerFont = new Font(header.getDisplay(), "verdana", 16, SWT.BOLD); l = new Label(headerName, SWT.CENTER); l.setFont(headerFont); l.setText(i18n(entry.getName())); l.setBackground(c); Composite headerText = new Composite(header, SWT.NONE); bodyLayout = new GridLayout(); bodyLayout.numColumns = 1; headerText.setLayout(bodyLayout); headerText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); headerText.setBackground(c); l = new Label(headerText, SWT.CENTER); l.setText(i18n(entry.getListDescription())); l.setBackground(c); Composite headerSplit = new Composite(header, SWT.NONE); GridLayout headerSplitLayout = new GridLayout(); headerSplitLayout.numColumns = 2; headerSplit.setLayout(headerSplitLayout); headerSplit.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); Composite headerOptions = new Composite(headerSplit, SWT.NONE); GridLayout headerOptionsLayout = new GridLayout(); headerOptionsLayout.numColumns = 2; headerOptions.setLayout(headerOptionsLayout); headerOptions.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); try { for (VascEntryField option:entry.getListOptions()) { for (int i=0;i<option.getVascEntryFieldType().getUIComponentCount(option);i++) { com.idcanet.vasc.core.ui.VascUIComponent label = option.getVascEntryFieldType().provideLabelUIComponent(i,option); VascValueModel model = new VascValueModel(); model.setValue(i18n(option.getName())); label.createComponent(entry,option,model,headerOptions); com.idcanet.vasc.core.ui.VascUIComponent editor = option.getVascEntryFieldType().provideEditorUIComponent(i,option); model = new VascValueModel(option.getVascEntryFieldType().provideEditorVascValueModel(i,option)); model.addListener(new VascOptionValueModelListener(option)); model.setValue(null); model.addListener(new VascValueModelListener() { public void valueUpdate(VascValueModel model) throws VascException { entry.getVascFrontendData().getVascFrontendHelper().refreshData(entry);// mm } }); Object edit = editor.createComponent(entry,option,model,headerOptions); // i==0 is for multi field editor support... which is stell very in progress if (i==0) { entry.getVascFrontendData().addFieldVascUIComponents(option, editor,edit); } } } Composite headerRightOptions = new Composite(headerSplit, SWT.NONE | SWT.RIGHT | SWT.TOP ); GridLayout headerRightOptionsLayout = new GridLayout(); headerRightOptionsLayout.numColumns = 2; headerRightOptions.setLayout(headerRightOptionsLayout); headerRightOptions.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); Label searchLabel = new Label(headerRightOptions, SWT.CENTER); searchLabel.setText("Zoeken:"); final Text text = new Text(headerRightOptions, SWT.NONE | SWT.BORDER ); text.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { String value = text.getText(); try { entry.getVascFrontendData().getVascFrontendHelper().searchAction(entry, value); } catch (Exception ee) { entry.getVascFrontendData().getVascFrontendHelper().handleException(entry,ee); } } }); entry.getVascFrontendData().getVascFrontendHelper().headerOptionsCreatedFillData(entry); } catch (Exception e) { e.printStackTrace(); } } class GlobalActionListener extends SelectionAdapter { private GlobalVascAction action = null; public GlobalActionListener(GlobalVascAction action) { this.action=action; } /** * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) */ @Override public void widgetSelected(SelectionEvent event) { logger.fine("Global Action"); try { action.doGlobalAction(entry); } catch (Exception e) { entry.getVascFrontendData().getVascFrontendHelper().handleException(entry,e); } } } public void createBody(Composite body) { logger.finer("Creating body"); // Create the table viewer to display the players // SWT.CHECK final TableViewer tableViewer = new TableViewer(body, SWT.SINGLE | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER ); final Table table2 = tableViewer.getTable(); table2.setLayoutData(new GridData(GridData.FILL_BOTH)); table2.setHeaderVisible(true); table2.setLinesVisible(true); body.addControlListener(new ResizeTableControlListener(body,table2)); table2.addSelectionListener(new SelectionListener() { /** * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent) */ public void widgetDefaultSelected(SelectionEvent e) { } /** * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent) */ public void widgetSelected(SelectionEvent e) { Object data = e.item.getData(); logger.fine("Slecting data: "+data); entry.getVascFrontendData().getVascEntryState().setEntryDataObject(data); } }); // Set the content and label providers tableViewer.setContentProvider(new ListConverterContentProvider()); tableViewer.setLabelProvider(new DefaultLabelProvider(entry)); //TODO: add renderer support //Add sort indicator and sort data when column selected Listener sortListener = new Listener() { public void handleEvent(Event e) { // determine new sort column and direction TableColumn sortColumn = table2.getSortColumn(); TableColumn currentColumn = (TableColumn) e.widget; int dir = table2.getSortDirection(); if (sortColumn == currentColumn) { dir = dir == SWT.UP ? SWT.DOWN : SWT.UP; } else { table2.setSortColumn(currentColumn); dir = SWT.UP; } table2.setSortDirection(dir); VascEntryField field = (VascEntryField)currentColumn.getData(); entry.getVascFrontendData().getVascFrontendHelper().sortAction(entry, field); } }; entry.getVascFrontendData().addVascEntryFrontendEventListener(new VascEntryFrontendEventListener() { public VascFrontendEventType[] getEventTypes() { VascFrontendEventType[] result = {VascEntryFrontendEventListener.VascFrontendEventType.DATA_LIST_UPDATE}; return result; } public void vascEvent(VascEntry entry,Object data) { tableViewer.refresh(); table2.deselectAll(); } }); for (VascEntryField c:entry.getVascEntryFields()) { if (entry.getVascFrontendData().getVascFrontendHelper().renderList(c)==false) { continue; } TableColumn tc = new TableColumn(table2, SWT.LEFT); tc.setText(i18n(c.getName())); tc.setData(c); tc.setToolTipText(i18n(c.getDescription())); tc.setImage((Image)i18nImage(c.getImage())); tc.addListener(SWT.Selection, sortListener); tc.setMoveable(true); tc.setResizable(true); } int totalWidth = entry.getVascFrontendData().getVascFrontendHelper().getTotalColumnsWidth(entry); logger.finer("Total size: "+totalWidth); TableColumn[] columns = table2.getColumns(); for (int i = 0; i < columns.length; i++) { VascEntryField c = (VascEntryField)columns[i].getData(); Integer cWidth = c.getSizeList(); if (cWidth!=null) { //int w = (int)((double)totalSize/(double)totalSize)*cWidth; columns[i].setWidth(cWidth); //logger.finest("Setting column width: "+w+" total: "+totalSize+" c: "+cWidth+" of column: "+i); } else { columns[i].pack(); } } logger.fine("Table with columns created: "+table2.getColumnCount()); tableViewer.setInput(entry); tableViewer.refresh(); } class ResizeTableControlListener implements ControlListener { Composite comp = null; Table table = null; public ResizeTableControlListener(Composite comp,Table table) { this.comp=comp; this.table=table; } public void controlResized(ControlEvent e) { Rectangle area = comp.getClientArea(); Point preferredSize = table.computeSize(SWT.DEFAULT, SWT.DEFAULT); int width = area.width - 2*table.getBorderWidth(); if (preferredSize.y > area.height + table.getHeaderHeight()) { // Subtract the scrollbar width from the total column width // if a vertical scrollbar will be required Point vBarSize = table.getVerticalBar().getSize(); width -= vBarSize.x; } Point oldSize = table.getSize(); if (oldSize.x > area.width) { // table is getting smaller so make the columns // smaller first and then resize the table to // match the client area width table.setSize(area.width, area.height); } else { // table is getting bigger so make the table // bigger first and then make the columns wider // to match the client area width table.setSize(area.width, area.height); //column1.setWidth(width/3); //column2.setWidth(width - column1.getWidth()); } } public void controlMoved(ControlEvent e) { } } public void createFooter(Composite footer) { logger.finest("Creating footer"); for( RowVascAction action:entry.getRowActions()) { if (entry.getVascFrontendData().getVascFrontendHelper().renderRowVascAction(action)==false) { continue; } Button actionButton = new Button(footer, SWT.NONE); actionButton.setText(i18n(action.getName())); actionButton.setToolTipText(i18n(action.getDescription())); actionButton.setImage((Image)i18nImage(action.getImage())); actionButton.addSelectionListener(new ActionListener(action)); } } class ActionListener extends SelectionAdapter { private RowVascAction action = null; public ActionListener(RowVascAction action) { this.action=action; } /** * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) */ @Override public void widgetSelected(SelectionEvent event) { logger.fine("Row Action"); try { action.doRowAction(entry, entry.getVascFrontendData().getVascEntryState().getEntryDataObject()); } catch (Exception e) { entry.getVascFrontendData().getVascFrontendHelper().handleException(entry,e); } } } class DefaultLabelProvider implements ITableLabelProvider { private VascEntry entry = null; public DefaultLabelProvider(VascEntry entry) { this.entry=entry; } /** * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int) */ public Image getColumnImage(Object arg0, int arg1) { return null; } /** * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int) */ public String getColumnText(Object bean, int columnNumber) { int col=0; VascEntryField vtc = null; for (VascEntryField c:entry.getVascEntryFields()) { if (entry.getVascFrontendData().getVascFrontendHelper().renderList(c)==false) { continue; } if (col==columnNumber) { vtc = c; break; } col++; } if (vtc==null) { // should not happen vtc = entry.getVascEntryFields().get(columnNumber); } //if (vtc.getVascColumnRenderer()==null) { try { return vtc.getVascEntryFieldValue().getDisplayValue(vtc,bean); } catch (Exception e) { logger.log(Level.WARNING,"Error in get value: '"+vtc.getVascEntryFieldValue()+"' error: "+e.getMessage(),e); return "Err"; } //} // see custem column renderer, so this code will never be called //return "CUSTEM_RENDER"; } /** * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener) */ public void addListener(ILabelProviderListener arg0) { } /** * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose() */ public void dispose() { } /** * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, java.lang.String) */ public boolean isLabelProperty(Object arg0, String arg1) { return false; } /** * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener) */ public void removeListener(ILabelProviderListener arg0) { } } class ListConverterContentProvider implements IStructuredContentProvider { /** * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object) */ public Object[] getElements(Object obj) { return ((VascEntry)obj).getVascFrontendData().getVascEntryState().getEntryDataList().toArray(); } /** * @see org.eclipse.jface.viewers.IContentProvider#dispose() */ public void dispose() { } /** * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object) */ public void inputChanged(Viewer arg0, Object arg1, Object arg2) { } } }