/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.pms.ui.dialog;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.pentaho.pms.locale.Locales;
import org.pentaho.pms.messages.Messages;
import org.pentaho.pms.schema.SchemaMeta;
import org.pentaho.pms.schema.concept.ConceptInterface;
import org.pentaho.pms.schema.concept.ConceptUtilityInterface;
import org.pentaho.pms.ui.concept.editor.ConceptModelRegistry;
import org.pentaho.pms.ui.concept.editor.Constants;
import org.pentaho.pms.ui.concept.editor.IConceptModel;
import org.pentaho.pms.ui.concept.editor.ITableModel;
import org.pentaho.pms.ui.concept.editor.PropertyNavigationWidget;
import org.pentaho.pms.ui.concept.editor.PropertyWidgetManager2;
import org.pentaho.pms.ui.concept.editor.TableColumnTreeWidget;
/**
* Parent of <code>PhysicalTableDialog</code> and <code>BusinessTableDialog</code>.
*
* <p>A note about <code>lastSelection</code>:</p>
* <p>lastSelection keeps track of the last concept to which we successfully transitioned. Why is this necessary?
* Because state on the screen may be invalid (e.g. user entered bogus value) then we must stop the transition, alert
* the user, and switch back to the offending screen. Here, "screen" is a card in a stack layout.</p>
*
* @author mlowery
*/
public abstract class AbstractTableDialog extends Dialog implements ISelectionChangedListener {
protected ITableModel tableModel;
protected String activeLocale;
protected Composite detailsComposite;
protected StackLayout stackLayout;
protected Composite cardComposite;
protected Map<String,Locales> propertyEditorContext = new HashMap<String,Locales>();
protected ConceptModelRegistry conceptModelRegistry = new ConceptModelRegistry();
protected Map cards = new HashMap();
protected Control defaultCard;
protected TableColumnTreeWidget tableColumnTree;
protected SchemaMeta schemaMeta;
protected ToolItem viewButton;
protected Text conceptIdText;
private static final Log logger = LogFactory.getLog(AbstractTableDialog.class);
protected ConceptUtilityInterface initialTableOrColumnSelection;
protected ToolItem delButton;
protected ConceptUtilityInterface lastSelection;
protected Composite conceptEditor;
PropertyWidgetManager2 propertyWidgetManager;
PropertyNavigationWidget propertyNavigationWidget;
public AbstractTableDialog(Shell parent) {
super(parent);
}
protected void init(ITableModel tableModel, SchemaMeta schemaMeta, ConceptUtilityInterface selectedTableOrColumn) {
this.tableModel = tableModel;
this.schemaMeta = schemaMeta;
Locales locales = schemaMeta.getLocales();
activeLocale = locales.getActiveLocale();
propertyEditorContext.put("locales", locales);
initialTableOrColumnSelection = selectedTableOrColumn;
}
protected void setShellStyle(int newShellStyle) {
super.setShellStyle(newShellStyle | SWT.RESIZE);
}
protected Point getInitialSize() {
return new Point(1200, 800);
}
protected final Control createDialogArea(final Composite parent) {
Composite c0 = (Composite) super.createDialogArea(parent);
Composite container = new Composite(c0, SWT.NONE);
container.setLayout(new GridLayout(2, true));
GridData gridData = new GridData(GridData.FILL_BOTH);
container.setLayoutData(gridData);
SashForm s0 = new SashForm(container, SWT.HORIZONTAL);
gridData = new GridData(GridData.FILL_BOTH);
gridData.horizontalSpan = 2;
gridData.heightHint = 20;
gridData.minimumWidth = 500;
s0.setLayoutData(gridData);
detailsComposite = new Composite(s0, SWT.NONE);
detailsComposite.setLayout(new GridLayout(2, false));
Label wlList = new Label(detailsComposite, SWT.NONE);
wlList.setText(Messages.getString("PhysicalTableDialog.USER_SUBJECT")); //$NON-NLS-1$
ToolBar tb = new ToolBar(detailsComposite, SWT.FLAT);
gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.horizontalAlignment = SWT.END;
tb.setLayoutData(gridData);
viewButton = new ToolItem(tb, SWT.CHECK);
viewButton.setToolTipText("Show IDs");
viewButton.setImage(Constants.getImageRegistry(Display.getCurrent()).get("show-id-button"));
viewButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
changeViewPressed();
}
});
ToolItem sep = new ToolItem(tb, SWT.SEPARATOR);
ToolItem addButton = new ToolItem(tb, SWT.PUSH);
addButton.setToolTipText(Messages.getString("PhysicalTableDialog.USER_ADD_NEW_COLUMN")); //$NON-NLS-1$
addButton.setImage(Constants.getImageRegistry(Display.getCurrent()).get("column-add-button"));
addButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
addColumnPressed();
}
});
delButton = new ToolItem(tb, SWT.PUSH);
delButton.setToolTipText(Messages.getString("PhysicalTableDialog.USER_DELETE_COLUMN")); //$NON-NLS-1$
delButton.setImage(Constants.getImageRegistry(Display.getCurrent()).get("column-del-button"));
delButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
delColumnPressed();
}
});
tableColumnTree = new TableColumnTreeWidget(detailsComposite, SWT.SINGLE | SWT.BORDER, tableModel, true, schemaMeta.getActiveLocale());
gridData = new GridData(GridData.FILL_BOTH);
gridData.horizontalSpan = 2;
tableColumnTree.getTree().setLayoutData(gridData);
tableColumnTree.addSelectionChangedListener(this);
cardComposite = new Composite(s0, SWT.NONE);
stackLayout = new StackLayout();
cardComposite.setLayout(stackLayout);
defaultCard = new DefaultCard(cardComposite, SWT.NONE);
conceptEditor = createConceptEditor();
showConceptUtility(null);
s0.setWeights(new int[] { 1, 3 });
if (initialTableOrColumnSelection != null) {
tableColumnTree.setSelection(new StructuredSelection(initialTableOrColumnSelection));
conceptIdText.forceFocus();
conceptIdText.selectAll();
}
return c0;
}
protected abstract void addColumnPressed();
protected void okPressed() {
cleanup();
super.okPressed();
}
protected void cleanup() {
tableColumnTree.removeSelectionChangedListener(this);
}
protected void delColumnPressed() {
// get the currently selected column
TreeSelection treeSel = (TreeSelection) tableColumnTree.getSelection();
ConceptUtilityInterface conceptHolder = (ConceptUtilityInterface) treeSel.getFirstElement();
boolean delete = MessageDialog.openConfirm(getShell(), "Confirm Column Delete",
"Are you sure you want to delete the column with id '" + conceptHolder.getId() + "'?");
if (delete) {
tableModel.removeColumn(conceptHolder.getId());
}
}
protected void changeViewPressed() {
tableColumnTree.showId(viewButton.getSelection());
if (viewButton.getSelection()) {
viewButton.setToolTipText("Show Names");
} else {
viewButton.setToolTipText("Show IDs");
}
}
protected void showConceptUtility(ConceptUtilityInterface cu) {
if (cu == null) {
if (stackLayout.topControl != defaultCard) {
stackLayout.topControl = defaultCard;
cardComposite.layout();
}
} else {
if (stackLayout.topControl == defaultCard){
stackLayout.topControl = conceptEditor;
cardComposite.layout();
}
editConcept(cu);
}
lastSelection = cu;
}
protected abstract Composite createConceptEditor();
protected void cancelPressed() {
cleanup();
super.cancelPressed();
}
/**
* The card that shows when there is no selection in the table-column tree.
*/
private class DefaultCard extends Composite {
public DefaultCard(final Composite parent, final int style) {
super(parent, style);
createContents();
}
private void createContents() {
setLayout(new GridLayout());
Label lab0 = new Label(this, SWT.CENTER);
lab0.setText("Select the table or any of its columns to begin editing properties.");
GridData gd = new GridData();
gd.verticalAlignment = GridData.CENTER;
gd.horizontalAlignment = GridData.CENTER;
gd.grabExcessHorizontalSpace = true;
gd.grabExcessVerticalSpace = true;
lab0.setLayoutData(gd);
}
}
public void selectionChanged(SelectionChangedEvent e) {
if (!e.getSelection().isEmpty()) {
TreeSelection treeSel = (TreeSelection) e.getSelection();
if (treeSel.getFirstElement() instanceof ConceptUtilityInterface) {
ConceptUtilityInterface cu = (ConceptUtilityInterface) treeSel.getFirstElement();
if (tableModel.isColumn(cu)) {
delButton.setEnabled(true);
} else {
delButton.setEnabled(false);
}
showConceptUtility(cu);
} else {
showConceptUtility(null);
}
} else {
showConceptUtility(null);
}
}
protected void configureShell(Shell arg0) {
super.configureShell(arg0);
arg0.setImage(null);
}
protected void editConcept(ConceptUtilityInterface cu) {
ConceptInterface concept = cu.getConcept();
IConceptModel conceptModel = conceptModelRegistry.getConceptModel(concept);
propertyNavigationWidget.removeSelectionChangedListener(propertyWidgetManager);
propertyNavigationWidget.setConceptModel(conceptModel);
propertyWidgetManager.setConceptModel(conceptModel);
propertyNavigationWidget.addSelectionChangedListener(propertyWidgetManager);
conceptIdText.setText(cu.getId());
}
protected boolean popupValidationErrorDialogIfNecessary() {
List<String> errorMessages = propertyWidgetManager.validateWidgets();
if (errorMessages.isEmpty()) {
return false;
} else {
StringBuilder buf = new StringBuilder();
for (String errorMessage : errorMessages) {
buf.append(errorMessage + "\n");
}
MessageDialog.openError(getShell(), "Errors", buf.toString());
return true;
}
}
}