package com.openMap1.mapper.views; import java.util.Hashtable; import java.util.Iterator; import java.util.Vector; import java.util.Comparator; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.ui.IActionBars; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.ViewPart; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EAttribute; import org.w3c.dom.Document; import org.w3c.dom.Element; import com.openMap1.mapper.query.MatchResult; import com.openMap1.mapper.query.CellContent; import com.openMap1.mapper.util.XMLUtil; import com.openMap1.mapper.core.MapperException; import com.openMap1.mapper.core.XMLException; /** * A tabular view of the results of the last query run. * * @author robert * */ public class QueryResultView extends ViewPart implements SortableView,SaveableView { private TableViewer viewer; private Table table; private Hashtable<String,Vector<CellContent>> result; public void setResult(Hashtable<String,Vector<CellContent>> result) {this.result = result;} private RowSorter qrSorter; public RowSorter rowSorter() {return qrSorter;} private Vector<String> columnHeaders = new Vector<String>(); protected Action saveQueryResultAction; private String queryText = ""; public void setQueryText(String text) {queryText = text;} private DataSourceView dataSourceView; /** for use in testing to stop it going to the workbench to get the view */ public void setDataSourceView(DataSourceView dataSourceView) {this.dataSourceView = dataSourceView;} //--------------------------------------------------------------------------------------------- // Initialisation //--------------------------------------------------------------------------------------------- /** * Callback to create the viewer and initialize it. */ public void createPartControl(Composite parent) { // create the viewer and its table createViewer(parent); // make the actions that will be items on the menu of this view makeActions(); // attach the menu to this view contributeToActionBars(); } /** this method is used in testing, to create a viewer, * without trying to contribute to the action bars */ public void createViewer(Composite parent) { viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); viewer.setLabelProvider(new QueryResultTableLabelProvider()); table = viewer.getTable(); table.setHeaderVisible(true); table.setLinesVisible(true); qrSorter = new RowSorter(viewer, this); viewer.setSorter(qrSorter); } class QueryResultTableLabelProvider extends LabelProvider implements ITableLabelProvider { public String getColumnText(Object element, int index) { String text = ""; if ((element instanceof Vector<?>) && (index < ((Vector<?>)element).size())) { Object obj = ((Vector<?>)element).elementAt(index); if (obj instanceof CellContent) text = ((CellContent)obj).getText(); } return text; } public Image getColumnImage(Object element, int index) {return null;} } //--------------------------------------------------------------------------------------------- // Receiving and showing query results //--------------------------------------------------------------------------------------------- /** * make table columns as follows: * a column for the data source codes * if addPairColumn = true (fast matching), a column for the pair number * if addScoreColumn = true (fast matching), a column for the matching score * The same set of table header names must be made by MatchResult.makeTableHeaders */ public void makeTableColumns(Vector<String[]> headers, boolean addMatchColumns, boolean addCountColumn) throws MapperException { // build these up to tell the query sorter which columns might be sorted on Vector<Comparator<String>> comparators = new Vector<Comparator<String>>(); Vector<TableColumn> usedTableColumns = new Vector<TableColumn>(); // clear previous column headers columnHeaders = new Vector<String>(); for (int i = 0; i < table.getColumnCount(); i++) table.getColumn(i).setText(""); // make or reuse the first column, for the codes of the query sources which contributed a row TableColumn firstCol = makeOrReuseColumn(0,"Codes", 60); comparators.add(RowSorter.stringComparator); usedTableColumns.add(firstCol); int extraColumns = 1; //make columns used for fast matching results if (addMatchColumns) { for (int i = 0; i < MatchResult.matchColumnNames.length; i++) { TableColumn pairCol = makeOrReuseColumn(extraColumns,MatchResult.matchColumnNames[i], 60); comparators.add(RowSorter.numberComparator); usedTableColumns.add(pairCol); extraColumns++; } } // set other new column headers, reusing columns or making new ones for (int c = 0; c < headers.size(); c++) { String className= headers.get(c)[0]; String attributeName= headers.get(c)[1]; String header = className + "." + attributeName; TableColumn col = makeOrReuseColumn(extraColumns + c, header, 120); // choose the comparator for sorting based on the type of the EAttribute comparators.add(getComparator(className,attributeName)); usedTableColumns.add(col); } // add a count column if (addCountColumn) { TableColumn lastCol = makeOrReuseColumn(extraColumns + headers.size(),"Count", 60); comparators.add(RowSorter.numberComparator); usedTableColumns.add(lastCol); } // tell the query sorter about this set of columns qrSorter.initialiseForResult(usedTableColumns, comparators); } /** * create a new table column, or reuse an existing one, * and set its parameters * @param columnIndex * @param columnName * @param columnWidth * @return the TableColumn */ private TableColumn makeOrReuseColumn(int columnIndex, String columnName, int columnWidth) { TableColumn col = null; if (columnIndex < table.getColumnCount()) col = table.getColumn(columnIndex); // reuse a column else {col = new TableColumn(table,SWT.LEFT);} // make a new column col.setText(columnName); columnHeaders.add(columnName); col.setWidth(columnWidth); return col; } /** * choose the comparator for sorting based on the type of the EAttribute * @param className * @param attributeName * @return */ private Comparator<String> getComparator(String className, String attributeName) { // default: compare the Strings as Strings if anything goes wrong Comparator<String> comp = RowSorter.stringComparator; // catch any Exception (eg missing class model) silently try{ EPackage classModel= WorkBenchUtil.getDataSourceView(true).getClassModelPackage(); EClass ec = (EClass)classModel.getEClassifier(className); EAttribute ea = (EAttribute)ec.getEStructuralFeature(attributeName); String attTypeName = ea.getEAttributeType().getName(); // cater for any non-String types that are recognised if (attTypeName.equals("EInt")) comp = RowSorter.numberComparator; } catch (Exception ex) {} return comp; } /** * Having set up the column headers, show a new set of results. * @param unorderedResults */ public void showNewUnorderedResult(Hashtable<String,Vector<CellContent>> unorderedResults) { // if there are any previous results showing, remove them table.removeAll(); setResult(unorderedResults); // resets the cached query result // add new rows for (Iterator<String> it = result.keySet().iterator();it.hasNext();) {viewer.add(result.get(it.next()));} } /** * Having set up the column headers, show a new set of results. * @param unorderedResults */ public void showNewOrderedResult(Vector<Vector<CellContent>> orderedResults) { // if there are any previous results showing, remove them table.removeAll(); result = new Hashtable<String,Vector<CellContent>>(); // add new rows, saving them in sortable form int order = 0; for (Iterator<Vector<CellContent>> it = orderedResults.iterator();it.hasNext();) { Vector<CellContent> next = it.next(); result.put("k_"+ order, next); viewer.add(next); order++; } } /** * Use the locally cached results to show them again - with a new sort order */ public void showResultAgain() { // if there are any previous results showing, remove them table.removeAll(); // add new rows for (Iterator<String> it = result.keySet().iterator();it.hasNext();) {viewer.add(result.get(it.next()));} } //--------------------------------------------------------------------------------------------- // Menu and methods for saving query results //--------------------------------------------------------------------------------------------- private void makeActions() { saveQueryResultAction = new Action() { public void run() { doSaveViewContents(); } }; saveQueryResultAction.setText("Save Query Results"); saveQueryResultAction.setToolTipText("Save the results of the query as XML or tab-separated values"); saveQueryResultAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages(). getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK)); } protected void doSaveViewContents() { ViewSaver vs = new ViewSaver(this,"Save query results", "Choose a new file in which to save the query results"); vs.saveResults(); } public Element getViewContents(Document doc) { ViewSaver vs = new ViewSaver(this,"Title not shown", "Title not shown"); return vs.resultDOM(doc); } private void contributeToActionBars() { IActionBars bars = getViewSite().getActionBars(); fillLocalPullDown(bars.getMenuManager()); } private void fillLocalPullDown(IMenuManager manager) { manager.add(saveQueryResultAction); } //--------------------------------------------------------------------------------------------- // Implementing the interface SaveableView //--------------------------------------------------------------------------------------------- /** @return the menu item to save the contents of the view */ public Action saveViewContentsAction() {return saveQueryResultAction;} /** headers of columns in the view */ public Vector<String> columnHeaders() {return columnHeaders;} /** the label provider for the view */ public ITableLabelProvider labelProvider() {return new QueryResultTableLabelProvider();} /** the TableViewer for the view */ public TableViewer tableViewer() {return viewer;} public void fillHeaderElement(Document doc, Element header) { try { // save query text Element queryTextElement = XMLUtil.textElement(doc, "QueryText", queryText); header.appendChild(queryTextElement); // save the set of defined sort columns Element sortElement = XMLUtil.newElement(doc, "Sort"); header.appendChild(sortElement); for (int s = 0; s < qrSorter.selectedSorters().size();s++) { SortInfo si = qrSorter.selectedSorters().get(s); Element column = XMLUtil.newElement(doc, "Column"); column.setAttribute("index", new Integer(si.columnIndex()).toString()); if (si.descending()) column.setAttribute("descending","true"); sortElement.appendChild(column); } // save the set of data sources used if (dataSourceView == null) dataSourceView = WorkBenchUtil.getDataSourceView(true); // the header of this save file includes the save file for the query source view ViewSaver vs = new ViewSaver(dataSourceView,"Title not shown", "Title not shown"); header.appendChild(vs.resultDOM(doc)); } catch (XMLException ex) {System.out.println("Cannot write query view header: " + ex.getMessage());} } /** * for testing purposes, restore the selection of sort columns from * a saved query result view * @param sortEl the <Sort> element of a saved query result view */ public void restoreSortColumns(Element sortEl) { qrSorter.restoreSortColumns(sortEl); } //--------------------------------------------------------------------------------------------- // Using the view to write out errors in parsing, strategising or executing the query //--------------------------------------------------------------------------------------------- /** * display messages for all errors found when parsing, finding strategy, or executing the query */ public void writeErrors(Vector<String[]> errors) { // if there are any previous results showing, remove them table.removeAll(); String[] header = {"Code","Error"}; int[] width = {40,500}; setQueryText("Errors in query"); // build these up to tell the query sorter which columns might be sorted on Vector<Comparator<String>> comparators = new Vector<Comparator<String>>(); Vector<TableColumn> usedTableColumns = new Vector<TableColumn>(); // clear previous column headers columnHeaders = new Vector<String>(); for (int i = 0; i < table.getColumnCount(); i++) table.getColumn(i).setText(""); int existingColumns = table.getColumnCount(); // may be more or less than you need for (int i = 0; i < 2; i++) { TableColumn col = null; if (i < existingColumns) col = table.getColumn(i); // reuse a column else {col = new TableColumn(table,SWT.LEFT);} // make a new column col.setText(header[i]); columnHeaders.add(header[i]); col.setWidth(width[i]); comparators.add(RowSorter.stringComparator); usedTableColumns.add(col); } // tell the query sorter about this set of columns qrSorter.initialiseForResult(usedTableColumns, comparators); for (Iterator<String[]> it = errors.iterator();it.hasNext();) { String[] next = it.next(); Vector<CellContent> row = new Vector<CellContent>(); for (int i= 0; i < 2; i++) row.add(new CellContent(next[i])); viewer.add(row); } } //--------------------------------------------------------------------------------------------- // Odds and ends //--------------------------------------------------------------------------------------------- /** * Passing the focus request to the viewer's control. */ public void setFocus() { viewer.getControl().setFocus(); } }