/*******************************************************************************
* Copyright (c) 2003, 2009 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
* Benjamin Cabe <benjamin.cabe@anyware-tech.com> - bug 251339
*******************************************************************************/
package com.liferay.ide.ui.form;
import com.liferay.ide.core.model.IBaseModel;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.dialogs.FilteredTree;
import org.eclipse.ui.forms.AbstractFormPart;
import org.eclipse.ui.forms.IFormPart;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.editor.FormEditor;
import org.eclipse.ui.forms.editor.FormPage;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.forms.widgets.Section;
public abstract class IDEFormPage extends FormPage {
private Control fLastFocusControl;
public IDEFormPage(FormEditor editor, String id, String title) {
super(editor, id, title);
fLastFocusControl = null;
}
public IDEFormEditor getLiferayFormEditor() {
return (IDEFormEditor) getEditor();
}
public void dispose() {
Control c = getPartControl();
if (c != null && !c.isDisposed()) {
Menu menu = c.getMenu();
if (menu != null)
resetMenu(menu, c);
}
super.dispose();
}
private void resetMenu(Menu menu, Control c) {
if (c instanceof Composite) {
Composite comp = (Composite) c;
Control[] children = comp.getChildren();
for (int i = 0; i < children.length; i++) {
resetMenu(menu, children[i]);
}
}
Menu cmenu = c.getMenu();
if (cmenu != null && cmenu.equals(menu)) {
c.setMenu(null);
}
}
protected void createFormContent(IManagedForm managedForm) {
final ScrolledForm form = managedForm.getForm();
FormToolkit toolkit = managedForm.getToolkit();
toolkit.decorateFormHeading(form.getForm());
IToolBarManager manager = form.getToolBarManager();
getFormEditor().contributeToToolbar(manager);
// final String href = getHelpResource();
// if (href != null) {
// Action helpAction = new Action("help") { //$NON-NLS-1$
// public void run() {
// BusyIndicator.showWhile(form.getDisplay(), new Runnable() {
// public void run() {
// PlatformUI.getWorkbench().getHelpSystem().displayHelpResource(href);
// }
// });
// }
// };
// helpAction.setToolTipText(PDEUIMessages.PDEFormPage_help);
// helpAction.setImageDescriptor(PDEPluginImages.DESC_HELP);
// manager.add(helpAction);
// }
//check to see if our form parts are contributing actions
IFormPart[] parts = managedForm.getParts();
for (int i = 0; i < parts.length; i++) {
if (parts[i] instanceof IAdaptable) {
IAdaptable adapter = (IAdaptable) parts[i];
IAction[] actions = (IAction[]) adapter.getAdapter(IAction[].class);
if (actions != null) {
for (int j = 0; j < actions.length; j++) {
form.getToolBarManager().add(actions[j]);
}
}
}
}
form.updateToolBar();
}
public IDEFormEditor getFormEditor() {
return (IDEFormEditor) getEditor();
}
protected String getHelpResource() {
return null;
}
public void contextMenuAboutToShow(IMenuManager menu) {
}
protected Control getFocusControl() {
IManagedForm form = getManagedForm();
if (form == null)
return null;
Control control = form.getForm();
if (control == null || control.isDisposed())
return null;
Display display = control.getDisplay();
Control focusControl = display.getFocusControl();
if (focusControl == null || focusControl.isDisposed())
return null;
return focusControl;
}
public boolean performGlobalAction(String actionId) {
Control focusControl = getFocusControl();
if (focusControl == null)
return false;
if (canPerformDirectly(actionId, focusControl))
return true;
AbstractFormPart focusPart = getFocusSection();
if (focusPart != null) {
if (focusPart instanceof IDESection)
return ((IDESection) focusPart).doGlobalAction(actionId);
if (focusPart instanceof FormDetails)
return ((FormDetails) focusPart).doGlobalAction(actionId);
}
return false;
}
public boolean canPaste(Clipboard clipboard) {
AbstractFormPart focusPart = getFocusSection();
if (focusPart != null) {
if (focusPart instanceof IDESection) {
return ((IDESection) focusPart).canPaste(clipboard);
}
if (focusPart instanceof FormDetails) {
return ((FormDetails) focusPart).canPaste(clipboard);
}
}
return false;
}
public boolean canCopy(ISelection selection) {
AbstractFormPart focusPart = getFocusSection();
if (focusPart != null) {
if (focusPart instanceof IDESection) {
return ((IDESection) focusPart).canCopy(selection);
}
if (focusPart instanceof FormDetails) {
return ((FormDetails) focusPart).canCopy(selection);
}
}
return false;
}
public boolean canCut(ISelection selection) {
AbstractFormPart focusPart = getFocusSection();
if (focusPart != null) {
if (focusPart instanceof IDESection) {
return ((IDESection) focusPart).canCut(selection);
}
if (focusPart instanceof FormDetails) {
return ((FormDetails) focusPart).canCut(selection);
}
}
return false;
}
private AbstractFormPart getFocusSection() {
Control focusControl = getFocusControl();
if (focusControl == null)
return null;
Composite parent = focusControl.getParent();
AbstractFormPart targetPart = null;
while (parent != null) {
Object data = parent.getData("part"); //$NON-NLS-1$
if (data != null && data instanceof AbstractFormPart) {
targetPart = (AbstractFormPart) data;
break;
}
parent = parent.getParent();
}
return targetPart;
}
protected boolean canPerformDirectly(String id, Control control) {
if (control instanceof Text) {
Text text = (Text) control;
if (id.equals(ActionFactory.CUT.getId())) {
text.cut();
return true;
}
if (id.equals(ActionFactory.COPY.getId())) {
text.copy();
return true;
}
if (id.equals(ActionFactory.PASTE.getId())) {
text.paste();
return true;
}
if (id.equals(ActionFactory.SELECT_ALL.getId())) {
text.selectAll();
return true;
}
if (id.equals(ActionFactory.DELETE.getId())) {
int count = text.getSelectionCount();
if (count == 0) {
int caretPos = text.getCaretPosition();
text.setSelection(caretPos, caretPos + 1);
}
text.insert(""); //$NON-NLS-1$
return true;
}
}
return false;
}
public void cancelEdit() {
IFormPart[] parts = getManagedForm().getParts();
for (int i = 0; i < parts.length; i++) {
IFormPart part = parts[i];
if (part instanceof IContextPart)
((IContextPart) part).cancelEdit();
}
}
/* (non-Javadoc)
* @see org.eclipse.ui.forms.editor.FormPage#createPartControl(org.eclipse.swt.widgets.Composite)
*/
public void createPartControl(Composite parent) {
super.createPartControl(parent);
// Dynamically add focus listeners to all the forms children in order
// to track the last focus control
IManagedForm managedForm = getManagedForm();
if (managedForm != null) {
addLastFocusListeners(managedForm.getForm());
}
}
/**
* Programatically and recursively add focus listeners to the specified
* composite and its children that track the last control to have focus
* before a page change or the editor lost focus
*
* @param composite
*/
public void addLastFocusListeners(Composite composite) {
Control[] controls = composite.getChildren();
for (int i = 0; i < controls.length; i++) {
Control control = controls[i];
// Add a focus listener if the control is any one of the below types
// Note that the controls listed below represent all the controls
// currently in use by all form pages in PDE. In the future,
// more controls will have to be added.
// Could not add super class categories of controls because it
// would include things like tool bars that we don't want to track
// focus for.
if ((control instanceof Text) || (control instanceof Button) || (control instanceof Combo) || (control instanceof CCombo) || (control instanceof Tree) || (control instanceof Table) || (control instanceof Spinner) || (control instanceof Link) || (control instanceof List) || (control instanceof TabFolder) || (control instanceof CTabFolder) || (control instanceof Hyperlink) || (control instanceof FilteredTree)) {
addLastFocusListener(control);
}
if (control instanceof Composite) {
// Recursively add focus listeners to this composites children
addLastFocusListeners((Composite) control);
}
}
}
/**
* Add a focus listener to the specified control that tracks the last
* control to have focus on this page.
* When focus is gained by this control, it registers itself as the last
* control to have focus. The last control to have focus is stored in order
* to be restored after a page change or editor loses focus.
*
* @param control
*/
private void addLastFocusListener(final Control control) {
control.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
// NO-OP
}
public void focusLost(FocusEvent e) {
fLastFocusControl = control;
}
});
}
/**
* Set the focus on the last control to have focus before a page change
* or the editor lost focus.
*/
public void updateFormSelection() {
if ((fLastFocusControl != null) && (fLastFocusControl.isDisposed() == false)) {
Control lastControl = fLastFocusControl;
// Set focus on the control
lastControl.forceFocus();
// If the control is a Text widget, select its contents
if (lastControl instanceof Text) {
Text text = (Text) lastControl;
text.setSelection(0, text.getText().length());
}
} else {
// No focus control set
// Fallback on managed form selection mechanism by setting the
// focus on this page itself.
// The managed form will set focus on the first managed part.
// Most likely this will turn out to be a section.
// In order for this to work properly, we must override the
// sections setFocus() method and set focus on a child control
// (preferrably first) that can practically take focus.
setFocus();
}
}
public Control getLastFocusControl() {
return fLastFocusControl;
}
/**
* @param control
*/
public void setLastFocusControl(Control control) {
fLastFocusControl = control;
}
protected void createFormErrorContent(IManagedForm managedForm, String errorTitle, String errorMessage, Exception e) {
ScrolledForm form = managedForm.getForm();
FormToolkit toolkit = managedForm.getToolkit();
toolkit.decorateFormHeading(form.getForm());
Composite parent = form.getBody();
GridLayout layout = new GridLayout();
GridData data2 = new GridData(GridData.FILL_BOTH);
layout.marginWidth = 7;
layout.marginHeight = 7;
parent.setLayout(layout);
parent.setLayoutData(data2);
// Set the title and image of the form
form.setText(errorTitle);
form.setImage(JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_ERROR));
int sectionStyle = Section.DESCRIPTION | ExpandableComposite.TITLE_BAR;
// Create the message section
Section messageSection = createUISection(parent, Msgs.message, errorMessage, sectionStyle);
Composite messageClient = createUISectionContainer(messageSection, 1);
// Bind the widgets
toolkit.paintBordersFor(messageClient);
messageSection.setClient(messageClient);
// Ensure the exception was defined
if (e == null) {
return;
}
// Create the details section
Section detailsSection = createUISection(parent, Msgs.details, e.getMessage(), sectionStyle);
Composite detailsClient = createUISectionContainer(detailsSection, 1);
// Create text widget holding the exception trace
int style = SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.READ_ONLY;
Text text = toolkit.createText(detailsClient, getStackTrace(e), style);
GridData data = new GridData(GridData.FILL_HORIZONTAL);
data.heightHint = 160;
data.widthHint = 200;
text.setLayoutData(data);
// Bind the widgets
toolkit.paintBordersFor(detailsClient);
detailsSection.setClient(detailsClient);
// Note: The veritical scrollbar fails to appear when text widget is
// not entirely shown
}
public Section createUISection(Composite parent, String text, String description, int style) {
Section section = getManagedForm().getToolkit().createSection(parent, style);
section.clientVerticalSpacing = FormLayoutFactory.SECTION_HEADER_VERTICAL_SPACING;
section.setLayout(FormLayoutFactory.createClearGridLayout(false, 1));
section.setText(text);
section.setDescription(description);
GridData data = new GridData(GridData.FILL_HORIZONTAL);
section.setLayoutData(data);
return section;
}
public Composite createUISectionContainer(Composite parent, int columns) {
Composite container = getManagedForm().getToolkit().createComposite(parent);
container.setLayout(FormLayoutFactory.createSectionClientGridLayout(false, columns));
return container;
}
private String getStackTrace(Throwable throwable) {
StringWriter swriter = new StringWriter();
PrintWriter pwriter = new PrintWriter(swriter);
throwable.printStackTrace(pwriter);
pwriter.flush();
pwriter.close();
return swriter.toString();
}
/**
* Used to align the section client / decriptions of two section headers
* horizontally adjacent to each other. The misalignment is caused by one
* section header containing toolbar icons and the other not.
*
* @param masterSection
* @param detailsSection
*/
public void alignSectionHeaders(Section masterSection, Section detailsSection) {
detailsSection.descriptionVerticalSpacing += masterSection.getTextClientHeightDifference();
}
public IBaseModel getModel() {
return ((IDEFormEditor)getEditor()).getModel();
}
public Shell getShell() {
return null;
}
private static class Msgs extends NLS
{
public static String details;
public static String message;
static
{
initializeMessages( IDEFormPage.class.getName(), Msgs.class );
}
}
}