/******************************************************************************* * Copyright (c) 2004, 2007 Boeing. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Boeing - initial API and implementation *******************************************************************************/ package org.eclipse.nebula.widgets.xviewer.customize; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.nebula.widgets.xviewer.IXViewerFactory; import org.eclipse.nebula.widgets.xviewer.IXViewerLabelProvider; import org.eclipse.nebula.widgets.xviewer.XViewer; import org.eclipse.nebula.widgets.xviewer.XViewerComputedColumn; import org.eclipse.nebula.widgets.xviewer.XViewerSorter; import org.eclipse.nebula.widgets.xviewer.XViewerText; import org.eclipse.nebula.widgets.xviewer.XViewerTextFilter; import org.eclipse.nebula.widgets.xviewer.core.model.ColumnDateFilter; import org.eclipse.nebula.widgets.xviewer.core.model.ColumnFilterData; import org.eclipse.nebula.widgets.xviewer.core.model.CustomizeData; import org.eclipse.nebula.widgets.xviewer.core.model.DateRangeType; import org.eclipse.nebula.widgets.xviewer.core.model.XViewerAlign; import org.eclipse.nebula.widgets.xviewer.core.model.XViewerColumn; import org.eclipse.nebula.widgets.xviewer.core.util.Strings; import org.eclipse.nebula.widgets.xviewer.util.Pair; import org.eclipse.nebula.widgets.xviewer.util.XViewerException; import org.eclipse.nebula.widgets.xviewer.util.internal.XViewerLib; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.widgets.TreeColumn; /** * This manages the default table column definitions versus the user modified column data, sorter and filters. * * @author Donald G. Dunne */ public class CustomizeManager { private final IXViewerFactory xViewerFactory; private final XViewer xViewer; private XViewerTextFilter xViewerTextFilter; private CustomizeData currentCustData; public final static String CURRENT_LABEL = XViewerText.get("label.current"); //$NON-NLS-1$ public final static String TABLE_DEFAULT_LABEL = XViewerText.get("label.default"); //$NON-NLS-1$ // Added to keep filter, sorter from working till finished loading public boolean loading = true; public CustomizeManager(XViewer xViewer, IXViewerFactory xViewerFactory) throws XViewerException { this.xViewer = xViewer; this.xViewerFactory = xViewerFactory; // Set customize to be user default, if selected, or table default CustomizeData userCustData = xViewerFactory.getXViewerCustomizations().getUserDefaultCustData(); if (userCustData != null) { currentCustData = resolveLoadedCustomizeData(userCustData); } else { currentCustData = getTableDefaultCustData(); currentCustData.setNameSpace(xViewerFactory.getNamespace()); } xViewerFactory.getXViewerCustomMenu().init(xViewer); } private final Map<String, XViewerColumn> oldNameToColumnId = new HashMap<String, XViewerColumn>(); /** * Since saved customize data is stored as xml, all the columns need to be resolved to the columns available from the * factory */ public CustomizeData resolveLoadedCustomizeData(CustomizeData loadedCustData) { // Otherwise, have to resolve what was saved with what is valid for this table and available from the factory CustomizeData resolvedCustData = new CustomizeData(); resolvedCustData.setName(loadedCustData.getName()); resolvedCustData.setPersonal(loadedCustData.isPersonal()); resolvedCustData.setGuid(loadedCustData.getGuid()); resolvedCustData.setNameSpace(loadedCustData.getNameSpace()); /* * Need to resolve columns with what factory has which gets correct class/subclass of XViewerColumn and allows for * removal of old and addition of new columns */ List<XViewerColumn> resolvedColumns = new ArrayList<XViewerColumn>(); for (XViewerColumn storedCol : loadedCustData.getColumnData().getColumns()) { XViewerColumn resolvedCol = xViewer.getXViewerFactory().getDefaultXViewerColumn(storedCol.getId()); // Handle known stored values if (resolvedCol == null) { resolvedCol = getKnownStoredValue(storedCol, resolvedCol); } // if not found, may have been stored without namespace; try to resolve for backward compatibility if (resolvedCol == null) { resolvedCol = resolveByName(storedCol); } // Resolve computed columns if (resolvedCol == null) { resolvedCol = resolveComputedColumns(storedCol, resolvedCol); } // Only handle columns that the factory supports and only resolve shown columns (rest will be loaded later) if (resolvedCol != null && resolvedCol.getWidth() > 0) { if (storedCol.getWidth() > 0) { resolvedCol.setWidth(storedCol.getWidth()); } resolvedCol.setName(storedCol.getName()); resolvedCol.setShow(storedCol.isShow()); resolvedCol.setSortForward(storedCol.isSortForward()); resolvedColumns.add(resolvedCol); } } addNewlyCreatedColumns(resolvedColumns); resolveComputedColumnsAgain(resolvedColumns); resolvedCustData.getColumnData().setColumns(resolvedColumns); resolvedCustData.getColumnFilterData().setFromXml(loadedCustData.getColumnFilterData().getXml()); resolvedCustData.getFilterData().setFromXml(loadedCustData.getFilterData().getXml()); resolvedCustData.getSortingData().setFromXml(loadedCustData.getSortingData().getXml()); return resolvedCustData; } private void resolveComputedColumnsAgain(List<XViewerColumn> resolvedColumns) { /* * Resolve computed columns, again, to enable source column to get set */ for (XViewerColumn resolveCol : resolvedColumns) { if (resolveCol instanceof XViewerComputedColumn) { ((XViewerComputedColumn) resolveCol).setSourceXViewerColumnFromColumns(resolvedColumns); } } } private void addNewlyCreatedColumns(List<XViewerColumn> resolvedColumns) { /* * Add extra columns that were added to the table since storage of this custData */ for (XViewerColumn extraCol : xViewer.getXViewerFactory().getDefaultTableCustomizeData().getColumnData().getColumns()) { if (!resolvedColumns.contains(extraCol)) { // Since column wasn't saved, don't show it extraCol.setShow(false); resolvedColumns.add(extraCol); } } } private XViewerColumn resolveComputedColumns(XViewerColumn storedCol, XViewerColumn resolvedCol) { for (XViewerComputedColumn xViewerComputedCol : xViewer.getComputedColumns()) { if (xViewerComputedCol.isApplicableFor(storedCol.getId())) { resolvedCol = xViewerComputedCol.createFromStored(storedCol); } } return resolvedCol; } private XViewerColumn resolveByName(XViewerColumn storedCol) { XViewerColumn resolvedCol; String name = storedCol.getName().replaceAll(" ", ""); //$NON-NLS-1$ //$NON-NLS-2$ resolvedCol = oldNameToColumnId.get(name); // First try to match by .<oldname> if (resolvedCol == null) { for (XViewerColumn xCol : xViewer.getXViewerFactory().getDefaultTableCustomizeData().getColumnData().getColumns()) { String colId = xCol.getId().toLowerCase(); String oldName = "." + name.toLowerCase(); //$NON-NLS-1$ if (colId.endsWith(oldName)) { resolvedCol = xCol; oldNameToColumnId.put(name, resolvedCol); oldNameToColumnId.put(storedCol.getName(), resolvedCol); break; } } } // Then try to match by id endswith name if (resolvedCol == null) { for (XViewerColumn xCol : xViewer.getXViewerFactory().getDefaultTableCustomizeData().getColumnData().getColumns()) { if (xCol.getId().endsWith(name)) { resolvedCol = xCol; oldNameToColumnId.put(name, resolvedCol); oldNameToColumnId.put(storedCol.getName(), resolvedCol); break; } } } return resolvedCol; } private XViewerColumn getKnownStoredValue(XViewerColumn storedCol, XViewerColumn resolvedCol) { String name = storedCol.getName(); if (name.equals("Impacted Items")) { resolvedCol = xViewer.getXViewerFactory().getDefaultXViewerColumn("ats.column.actionableItems"); //$NON-NLS-1$ } else if (name.equals("State Percent")) { resolvedCol = xViewer.getXViewerFactory().getDefaultXViewerColumn("ats.column.statePercentComplete"); //$NON-NLS-1$ } return resolvedCol; } public void setFilterText(String text, boolean regex) { currentCustData.getFilterData().setFilterText(text, regex); try { xViewer.getTree().setRedraw(false); xViewerTextFilter.update(); xViewer.refresh(); } finally { xViewer.getTree().setRedraw(true); } } public String getFilterText() { return currentCustData.getFilterData().getFilterText(); } public void setColumnFilterText(String colId, String text) { if (text == null || text.equals("")) { //$NON-NLS-1$ currentCustData.getColumnFilterData().removeFilterText(colId); } else { currentCustData.getColumnFilterData().setFilterText(colId, text); } xViewerTextFilter.update(); xViewer.refresh(); } public void clearFilters() { xViewer.getFilterDataUI().clear(); currentCustData.getColumnFilterData().clear(); xViewerTextFilter.update(); xViewer.refresh(); } public void clearAllColumnFilters() { currentCustData.getColumnFilterData().clear(); xViewerTextFilter.update(); xViewer.refresh(); } public String getColumnFilterText(String colId) { return currentCustData.getColumnFilterData().getFilterText(colId); } public ColumnFilterData getColumnFilterData() { return currentCustData.getColumnFilterData(); } /** * Clears out current columns, sorting and filtering and loads table customization */ public void loadCustomization() { loadCustomization(currentCustData); } public void resetDefaultSorter() { XViewerSorter sorter = xViewer.getXViewerFactory().createNewXSorter(xViewer); xViewer.setSorter(sorter); } public void clearSorter() { currentCustData.getSortingData().clearSorter(); xViewer.setSorter(null); xViewer.updateStatusLabel(); } public void handleTableCustomization() { Dialog dialog = xViewerFactory.getCustomizeDialog(xViewer); if (dialog != null) { dialog.open(); } } public void appendToStatusLabel(StringBuffer sb) { if (currentCustData != null && currentCustData.getName() != null) { sb.append(XViewerText.get("label.custom", currentCustData.getName())); //$NON-NLS-1$ } } /** * @return the currentCustData; makes a copy of columns so they don't collide with each other */ public CustomizeData generateCustDataFromTable() { CustomizeData custData = new CustomizeData(); custData.setName(CustomizeManager.CURRENT_LABEL); custData.setNameSpace(xViewer.getXViewerFactory().getNamespace()); List<XViewerColumn> columns = new ArrayList<XViewerColumn>(15); for (Integer index : xViewer.getTree().getColumnOrder()) { TreeColumn treeCol = xViewer.getTree().getColumn(index); XViewerColumn xCol = (XViewerColumn) treeCol.getData(); XViewerColumn newXCol = xCol.copy(); newXCol.setWidth(treeCol.getWidth()); newXCol.setShow(treeCol.getWidth() > 0); columns.add(newXCol); } // Add all columns that are not visible for (XViewerColumn xCol : xViewer.getCustomizeMgr().getCurrentTableColumns()) { if (!columns.contains(xCol)) { XViewerColumn newXCol = xCol.copy(); newXCol.setShow(false); columns.add(newXCol); } } custData.getColumnData().setColumns(columns); custData.getSortingData().setFromXml(currentCustData.getSortingData().getXml()); custData.getFilterData().setFromXml(currentCustData.getFilterData().getXml()); custData.getColumnFilterData().setFromXml(currentCustData.getColumnFilterData().getXml()); return custData; } public List<XViewerColumn> getCurrentTableColumns() { return currentCustData.getColumnData().getColumns(); } public XViewerColumn getCurrentTableColumn(String id) { return currentCustData.getColumnData().getXColumn(id); } public List<XViewerColumn> getCurrentTableColumnsInOrder() { List<XViewerColumn> columns = new ArrayList<XViewerColumn>(15); for (Integer index : xViewer.getTree().getColumnOrder()) { TreeColumn treeCol = xViewer.getTree().getColumn(index); XViewerColumn xCol = (XViewerColumn) treeCol.getData(); columns.add(xCol); } return columns; } public List<XViewerColumn> getCurrentVisibleTableColumns() { List<XViewerColumn> columns = new ArrayList<XViewerColumn>(15); for (XViewerColumn xCol : getCurrentTableColumns()) { if (xCol.isShow()) { columns.add(xCol); } } return columns; } public List<XViewerColumn> getCurrentHiddenTableColumns() { List<XViewerColumn> columns = new ArrayList<XViewerColumn>(15); for (XViewerColumn xCol : getCurrentTableColumns()) { if (!xCol.isShow()) { columns.add(xCol); } } return columns; } /** * Return index of XColumn to original column index on creation of table. Since table allows drag re-ordering of * columns, this index will provide the map back to the original column index. Used for label providers * getColumnText(object, index) */ public Map<XViewerColumn, Integer> getCurrentTableColumnsIndex() { int[] index = xViewer.getTree().getColumnOrder(); Map<XViewerColumn, Integer> xColToColumnIndex = new HashMap<XViewerColumn, Integer>(index.length); for (int x = 0; x < index.length; x++) { TreeColumn treeCol = xViewer.getTree().getColumn(index[x]); XViewerColumn xCol = (XViewerColumn) treeCol.getData(); xColToColumnIndex.put(xCol, index[x]); } return xColToColumnIndex; } public int getColumnNumFromXViewerColumn(XViewerColumn xCol) { for (Integer index : xViewer.getTree().getColumnOrder()) { TreeColumn treeCol = xViewer.getTree().getColumn(index); XViewerColumn treeXCol = (XViewerColumn) treeCol.getData(); if (xCol.equals(treeXCol)) { return index; } } return 0; } public Pair<XViewerColumn, Integer> getColumnNumFromXViewerColumn(String columnId) { if (!xViewer.getTree().isDisposed()) { for (Integer index : xViewer.getTree().getColumnOrder()) { TreeColumn treeCol = xViewer.getTree().getColumn(index); XViewerColumn treeXCol = (XViewerColumn) treeCol.getData(); if (treeXCol.getId().equals(columnId)) { return new Pair<XViewerColumn, Integer>(treeXCol, index); } } } return null; } public CustomizeData getTableDefaultCustData() { CustomizeData custData = xViewer.getXViewerFactory().getDefaultTableCustomizeData(); if (custData.getName() == null || custData.getName().equals("")) { //$NON-NLS-1$ custData.setName(TABLE_DEFAULT_LABEL); } custData.setNameSpace(xViewer.getViewerNamespace()); return custData; } public void getSortingStr(StringBuffer sb) { if (currentCustData.getSortingData().isSorting()) { List<XViewerColumn> cols = getSortXCols(); if (cols.isEmpty()) { return; } sb.append(XViewerText.get("label.status.sort")); //$NON-NLS-1$ for (XViewerColumn col : getSortXCols()) { if (col != null) { sb.append(XViewerText.get("label.status.sort.start")); //$NON-NLS-1$ sb.append(col.getName()); sb.append(col.isSortForward() ? XViewerText.get("label.status.sort.fwd") : XViewerText.get( //$NON-NLS-1$ "label.status.sort.rev")); //$NON-NLS-1$ } } } } public int getDefaultWidth(String id) { XViewerColumn xCol = xViewerFactory.getDefaultXViewerColumn(id); if (xCol == null) { return 75; } else { return xCol.getWidth(); } } public boolean isCustomizationUserDefault(CustomizeData custData) throws XViewerException { return xViewerFactory.getXViewerCustomizations().isCustomizationUserDefault(custData); } public List<XViewerColumn> getSortXCols() { // return sort columns depending on default/customize return currentCustData.getSortingData().getSortXCols(oldNameToColumnId); } public boolean isLoading() { return loading; } public List<CustomizeData> getSavedCustDatas() throws Exception { List<CustomizeData> custDatas = new ArrayList<CustomizeData>(); for (CustomizeData savedCustData : xViewerFactory.getXViewerCustomizations().getSavedCustDatas()) { custDatas.add(resolveLoadedCustomizeData(savedCustData)); } return custDatas; } public void saveCustomization(CustomizeData custData) throws Exception { xViewerFactory.getXViewerCustomizations().saveCustomization(custData); } /** * Set to newName or clear if newName == "" */ public void customizeColumnName(XViewerColumn xCol, String newName) { if (newName.equals("")) { //$NON-NLS-1$ XViewerColumn defaultXCol = xViewerFactory.getDefaultXViewerColumn(xCol.getId()); if (defaultXCol == null) { XViewerLib.popup(XViewerText.get("error"), XViewerText.get("error.column_undefined")); //$NON-NLS-1$ //$NON-NLS-2$ return; } xCol.setName(defaultXCol.getName()); } else { xCol.setName(newName); } } public void setUserDefaultCustData(CustomizeData newCustData, boolean set) throws Exception { xViewerFactory.getXViewerCustomizations().setUserDefaultCustData(newCustData, set); } public void deleteCustomization(CustomizeData custData) throws Exception { xViewerFactory.getXViewerCustomizations().deleteCustomization(custData); } public boolean isSorting() { return currentCustData.getSortingData().isSorting(); } /** * Clears out current columns, sorting and filtering and loads table customization */ public void loadCustomization(final CustomizeData newCustData) { loading = true; if (xViewerTextFilter == null) { xViewerTextFilter = xViewer.getXViewerTextFilter(); xViewer.addFilter(xViewerTextFilter); } if (xViewer.getTree().isDisposed()) { return; } currentCustData = newCustData; if (currentCustData.getName() == null || currentCustData.getName().equals("")) { //$NON-NLS-1$ currentCustData.setName(CURRENT_LABEL); } currentCustData.setNameSpace(xViewer.getViewerNamespace()); if (currentCustData.getSortingData().isSorting()) { xViewer.resetDefaultSorter(); } else { xViewer.setSorter(null); } if (xViewer.getFilterDataUI() != null) { xViewer.getFilterDataUI().update(); } xViewerTextFilter.update(); // Dispose all existing columns for (TreeColumn treeCol : xViewer.getTree().getColumns()) { treeCol.dispose(); } // Create new columns addColumns(); xViewer.updateStatusLabel(); if (xViewer.getLabelProvider() instanceof IXViewerLabelProvider) { ((IXViewerLabelProvider) xViewer.getLabelProvider()).clearXViewerColumnIndexCache(); } loading = false; } public void addColumns() { for (final XViewerColumn xCol : currentCustData.getColumnData().getColumns()) { // Only add visible columns if (!xCol.isShow()) { continue; } xCol.setXViewer(xViewer); TreeColumn column = new TreeColumn(xViewer.getTree(), getSwtAlign(xCol.getAlign())); column.setMoveable(true); column.setData(xCol); StringBuffer sb = new StringBuffer(); sb.append(xCol.getName()); if (Strings.isValid(xCol.getDescription()) && !xCol.getDescription().equals(xCol.getName())) { sb.append("\n"); //$NON-NLS-1$ sb.append(xCol.getDescription()); } if (Strings.isValid(xCol.getToolTip()) && !xCol.getToolTip().equals( xCol.getName()) && !xCol.getToolTip().equals(xCol.getDescription())) { sb.append("\n"); //$NON-NLS-1$ sb.append(xCol.getToolTip()); } // Only show id if different from name and non-null if (xCol.getId() != null && !"".equals(xCol.getId()) && !xCol.getName().equals(xCol.getId())) { //$NON-NLS-1$ sb.append("\n"); //$NON-NLS-1$ sb.append(xCol.getId()); } column.setToolTipText(sb.toString()); column.setText(xCol.getName()); column.setWidth(xCol.getWidth()); column.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { super.widgetSelected(e); // Add sorter if doesn't exist if (xViewer.getSorter() == null) { resetDefaultSorter(); } if (xViewer.isAltKeyDown()) { xViewer.getColumnFilterDataUI().promptSetFilter(xCol); } else if (xViewer.isCtrlKeyDown()) { List<XViewerColumn> currSortCols = currentCustData.getSortingData().getSortXCols(oldNameToColumnId); if (currSortCols == null) { currSortCols = new ArrayList<XViewerColumn>(); currSortCols.add(xCol); } else { // If already selected this item, reverse the sort if (currSortCols.contains(xCol)) { for (XViewerColumn currXCol : currSortCols) { if (currXCol.equals(xCol)) { currXCol.reverseSort(); } } } else { currSortCols.add(xCol); } } currentCustData.getSortingData().setSortXCols(currSortCols); } else { List<XViewerColumn> cols = new ArrayList<XViewerColumn>(); cols.add(xCol); // If sorter already has this column sorted, reverse the sort List<XViewerColumn> currSortCols = currentCustData.getSortingData().getSortXCols(oldNameToColumnId); if (currSortCols != null && currSortCols.size() == 1 && currSortCols.iterator().next().equals(xCol)) { xCol.reverseSort(); } // Set the newly sorted column currentCustData.getSortingData().setSortXCols(cols); } xViewer.refresh(); } }); } } public static int getSwtAlign(XViewerAlign align) { if (align == XViewerAlign.Center) { return SWT.CENTER; } else if (align == XViewerAlign.Right) { return SWT.RIGHT; } return SWT.LEFT; } public boolean isFilterTextRegularExpression() { return currentCustData.getFilterData().isRegularExpression(); } public void setColumnDateFilter(String columnId, DateRangeType dateRangeType, Date date1, Date date2) { if (dateRangeType == null || dateRangeType == DateRangeType.None) { //$NON-NLS-1$ currentCustData.getColumnFilterData().removeDateFilter(columnId); } else { currentCustData.getColumnFilterData().setDateFilter(columnId, dateRangeType, date1, date2); } xViewerTextFilter.update(); xViewer.refresh(); } public ColumnDateFilter getColumnDateFilter(String columnId) { return currentCustData.getColumnFilterData().getDateFilter(columnId); } public CustomizeData getCurrentCustomizeData() { return currentCustData; } }