001: /*******************************************************************************
002: * Copyright (c) 2003, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.pde.internal.ui.editor;
011:
012: import java.io.PrintWriter;
013: import java.io.StringWriter;
014:
015: import org.eclipse.core.runtime.IAdaptable;
016: import org.eclipse.jface.action.Action;
017: import org.eclipse.jface.action.IAction;
018: import org.eclipse.jface.action.IMenuManager;
019: import org.eclipse.jface.action.IToolBarManager;
020: import org.eclipse.jface.dialogs.Dialog;
021: import org.eclipse.jface.resource.JFaceResources;
022: import org.eclipse.jface.viewers.ISelection;
023: import org.eclipse.pde.core.IBaseModel;
024: import org.eclipse.pde.internal.ui.PDEPluginImages;
025: import org.eclipse.pde.internal.ui.PDEUIMessages;
026: import org.eclipse.swt.SWT;
027: import org.eclipse.swt.custom.BusyIndicator;
028: import org.eclipse.swt.custom.CCombo;
029: import org.eclipse.swt.custom.CTabFolder;
030: import org.eclipse.swt.dnd.Clipboard;
031: import org.eclipse.swt.events.FocusEvent;
032: import org.eclipse.swt.events.FocusListener;
033: import org.eclipse.swt.layout.GridData;
034: import org.eclipse.swt.layout.GridLayout;
035: import org.eclipse.swt.widgets.Button;
036: import org.eclipse.swt.widgets.Combo;
037: import org.eclipse.swt.widgets.Composite;
038: import org.eclipse.swt.widgets.Control;
039: import org.eclipse.swt.widgets.Display;
040: import org.eclipse.swt.widgets.Link;
041: import org.eclipse.swt.widgets.List;
042: import org.eclipse.swt.widgets.Menu;
043: import org.eclipse.swt.widgets.Spinner;
044: import org.eclipse.swt.widgets.TabFolder;
045: import org.eclipse.swt.widgets.Table;
046: import org.eclipse.swt.widgets.Text;
047: import org.eclipse.swt.widgets.Tree;
048: import org.eclipse.ui.PlatformUI;
049: import org.eclipse.ui.actions.ActionFactory;
050: import org.eclipse.ui.dialogs.FilteredTree;
051: import org.eclipse.ui.forms.AbstractFormPart;
052: import org.eclipse.ui.forms.IFormPart;
053: import org.eclipse.ui.forms.IManagedForm;
054: import org.eclipse.ui.forms.editor.FormEditor;
055: import org.eclipse.ui.forms.editor.FormPage;
056: import org.eclipse.ui.forms.widgets.ExpandableComposite;
057: import org.eclipse.ui.forms.widgets.FormToolkit;
058: import org.eclipse.ui.forms.widgets.Hyperlink;
059: import org.eclipse.ui.forms.widgets.ScrolledForm;
060: import org.eclipse.ui.forms.widgets.Section;
061:
062: public abstract class PDEFormPage extends FormPage {
063:
064: private boolean fNewStyleHeader = true;
065: private Control fLastFocusControl;
066:
067: private boolean fStale;
068:
069: public PDEFormPage(FormEditor editor, String id, String title) {
070: super (editor, id, title);
071: fLastFocusControl = null;
072: fStale = false;
073: }
074:
075: public PDEFormPage(FormEditor editor, String id, String title,
076: boolean newStyleHeader) {
077: this (editor, id, title);
078: fNewStyleHeader = newStyleHeader;
079: }
080:
081: /**
082: *
083: */
084: protected void markStale() {
085: fStale = true;
086: }
087:
088: /**
089: * @return
090: */
091: protected boolean isStale() {
092: return fStale;
093: }
094:
095: /**
096: *
097: */
098: protected void refresh() {
099: fStale = false;
100: }
101:
102: /* (non-Javadoc)
103: * @see org.eclipse.ui.forms.editor.FormPage#setActive(boolean)
104: */
105: public void setActive(boolean active) {
106: super .setActive(active);
107: if (active && isStale()) {
108: refresh();
109: }
110: }
111:
112: public void dispose() {
113: Control c = getPartControl();
114: if (c != null && !c.isDisposed()) {
115: Menu menu = c.getMenu();
116: if (menu != null)
117: resetMenu(menu, c);
118: }
119: super .dispose();
120: }
121:
122: private void resetMenu(Menu menu, Control c) {
123: if (c instanceof Composite) {
124: Composite comp = (Composite) c;
125: Control[] children = comp.getChildren();
126: for (int i = 0; i < children.length; i++) {
127: resetMenu(menu, children[i]);
128: }
129: }
130: Menu cmenu = c.getMenu();
131: if (cmenu != null && cmenu.equals(menu)) {
132: c.setMenu(null);
133: }
134: }
135:
136: protected void createFormContent(IManagedForm managedForm) {
137: final ScrolledForm form = managedForm.getForm();
138: FormToolkit toolkit = managedForm.getToolkit();
139: //FormColors colors = toolkit.getColors();
140: //form.getForm().setSeparatorColor(colors.getColor(FormColors.TB_BORDER));
141: if (fNewStyleHeader) {
142: //createNewStyleHeader(form, colors);
143: toolkit.decorateFormHeading(form.getForm());
144: }
145:
146: IToolBarManager manager = form.getToolBarManager();
147:
148: getPDEEditor().contributeToToolbar(manager);
149:
150: final String href = getHelpResource();
151: if (href != null) {
152: Action helpAction = new Action("help") { //$NON-NLS-1$
153: public void run() {
154: BusyIndicator.showWhile(form.getDisplay(),
155: new Runnable() {
156: public void run() {
157: PlatformUI.getWorkbench()
158: .getHelpSystem()
159: .displayHelpResource(href);
160: }
161: });
162: }
163: };
164: helpAction.setToolTipText(PDEUIMessages.PDEFormPage_help);
165: helpAction.setImageDescriptor(PDEPluginImages.DESC_HELP);
166: manager.add(helpAction);
167: }
168: //check to see if our form parts are contributing actions
169: IFormPart[] parts = managedForm.getParts();
170: for (int i = 0; i < parts.length; i++) {
171: if (parts[i] instanceof IAdaptable) {
172: IAdaptable adapter = (IAdaptable) parts[i];
173: IAction[] actions = (IAction[]) adapter
174: .getAdapter(IAction[].class);
175: if (actions != null) {
176: for (int j = 0; j < actions.length; j++) {
177: form.getToolBarManager().add(actions[j]);
178: }
179: }
180: }
181: }
182: form.updateToolBar();
183: }
184:
185: public PDEFormEditor getPDEEditor() {
186: return (PDEFormEditor) getEditor();
187: }
188:
189: protected String getHelpResource() {
190: return null;
191: }
192:
193: public IBaseModel getModel() {
194: return getPDEEditor().getAggregateModel();
195: }
196:
197: public void contextMenuAboutToShow(IMenuManager menu) {
198: }
199:
200: protected Control getFocusControl() {
201: IManagedForm form = getManagedForm();
202: if (form == null)
203: return null;
204: Control control = form.getForm();
205: if (control == null || control.isDisposed())
206: return null;
207: Display display = control.getDisplay();
208: Control focusControl = display.getFocusControl();
209: if (focusControl == null || focusControl.isDisposed())
210: return null;
211: return focusControl;
212: }
213:
214: public boolean performGlobalAction(String actionId) {
215: Control focusControl = getFocusControl();
216: if (focusControl == null)
217: return false;
218:
219: if (canPerformDirectly(actionId, focusControl))
220: return true;
221: AbstractFormPart focusPart = getFocusSection();
222: if (focusPart != null) {
223: if (focusPart instanceof PDESection)
224: return ((PDESection) focusPart)
225: .doGlobalAction(actionId);
226: if (focusPart instanceof PDEDetails)
227: return ((PDEDetails) focusPart)
228: .doGlobalAction(actionId);
229: }
230: return false;
231: }
232:
233: public boolean canPaste(Clipboard clipboard) {
234: AbstractFormPart focusPart = getFocusSection();
235: if (focusPart != null) {
236: if (focusPart instanceof PDESection) {
237: return ((PDESection) focusPart).canPaste(clipboard);
238: }
239: if (focusPart instanceof PDEDetails) {
240: return ((PDEDetails) focusPart).canPaste(clipboard);
241: }
242: }
243: return false;
244: }
245:
246: /**
247: * @param selection
248: * @return
249: */
250: public boolean canCopy(ISelection selection) {
251: AbstractFormPart focusPart = getFocusSection();
252: if (focusPart != null) {
253: if (focusPart instanceof PDESection) {
254: return ((PDESection) focusPart).canCopy(selection);
255: }
256: if (focusPart instanceof PDEDetails) {
257: return ((PDEDetails) focusPart).canCopy(selection);
258: }
259: }
260: return false;
261: }
262:
263: /**
264: * @param selection
265: * @return
266: */
267: public boolean canCut(ISelection selection) {
268: AbstractFormPart focusPart = getFocusSection();
269: if (focusPart != null) {
270: if (focusPart instanceof PDESection) {
271: return ((PDESection) focusPart).canCut(selection);
272: }
273: if (focusPart instanceof PDEDetails) {
274: return ((PDEDetails) focusPart).canCut(selection);
275: }
276: }
277: return false;
278: }
279:
280: private AbstractFormPart getFocusSection() {
281: Control focusControl = getFocusControl();
282: if (focusControl == null)
283: return null;
284: Composite parent = focusControl.getParent();
285: AbstractFormPart targetPart = null;
286: while (parent != null) {
287: Object data = parent.getData("part"); //$NON-NLS-1$
288: if (data != null && data instanceof AbstractFormPart) {
289: targetPart = (AbstractFormPart) data;
290: break;
291: }
292: parent = parent.getParent();
293: }
294: return targetPart;
295: }
296:
297: protected boolean canPerformDirectly(String id, Control control) {
298: if (control instanceof Text) {
299: Text text = (Text) control;
300: if (id.equals(ActionFactory.CUT.getId())) {
301: text.cut();
302: return true;
303: }
304: if (id.equals(ActionFactory.COPY.getId())) {
305: text.copy();
306: return true;
307: }
308: if (id.equals(ActionFactory.PASTE.getId())) {
309: text.paste();
310: return true;
311: }
312: if (id.equals(ActionFactory.SELECT_ALL.getId())) {
313: text.selectAll();
314: return true;
315: }
316: if (id.equals(ActionFactory.DELETE.getId())) {
317: int count = text.getSelectionCount();
318: if (count == 0) {
319: int caretPos = text.getCaretPosition();
320: text.setSelection(caretPos, caretPos + 1);
321: }
322: text.insert(""); //$NON-NLS-1$
323: return true;
324: }
325: }
326: return false;
327: }
328:
329: public void cancelEdit() {
330: IFormPart[] parts = getManagedForm().getParts();
331: for (int i = 0; i < parts.length; i++) {
332: IFormPart part = parts[i];
333: if (part instanceof IContextPart)
334: ((IContextPart) part).cancelEdit();
335: }
336: }
337:
338: /* (non-Javadoc)
339: * @see org.eclipse.ui.forms.editor.FormPage#createPartControl(org.eclipse.swt.widgets.Composite)
340: */
341: public void createPartControl(Composite parent) {
342: super .createPartControl(parent);
343: // Dynamically add focus listeners to all the forms children in order
344: // to track the last focus control
345: IManagedForm managedForm = getManagedForm();
346: if (managedForm != null) {
347: addLastFocusListeners(managedForm.getForm());
348: }
349: }
350:
351: /**
352: * Programatically and recursively add focus listeners to the specified
353: * composite and its children that track the last control to have focus
354: * before a page change or the editor lost focus
355: *
356: * @param composite
357: */
358: public void addLastFocusListeners(Composite composite) {
359: Control[] controls = composite.getChildren();
360: for (int i = 0; i < controls.length; i++) {
361: Control control = controls[i];
362: // Add a focus listener if the control is any one of the below types
363: // Note that the controls listed below represent all the controls
364: // currently in use by all form pages in PDE. In the future,
365: // more controls will have to be added.
366: // Could not add super class categories of controls because it
367: // would include things like tool bars that we don't want to track
368: // focus for.
369: if ((control instanceof Text)
370: || (control instanceof Button)
371: || (control instanceof Combo)
372: || (control instanceof CCombo)
373: || (control instanceof Tree)
374: || (control instanceof Table)
375: || (control instanceof Spinner)
376: || (control instanceof Link)
377: || (control instanceof List)
378: || (control instanceof TabFolder)
379: || (control instanceof CTabFolder)
380: || (control instanceof Hyperlink)
381: || (control instanceof FilteredTree)) {
382: addLastFocusListener(control);
383: }
384: if (control instanceof Composite) {
385: // Recursively add focus listeners to this composites children
386: addLastFocusListeners((Composite) control);
387: }
388: }
389: }
390:
391: /**
392: * Add a focus listener to the specified control that tracks the last
393: * control to have focus on this page.
394: * When focus is gained by this control, it registers itself as the last
395: * control to have focus. The last control to have focus is stored in order
396: * to be restored after a page change or editor loses focus.
397: *
398: * @param control
399: */
400: private void addLastFocusListener(final Control control) {
401: control.addFocusListener(new FocusListener() {
402: public void focusGained(FocusEvent e) {
403: // NO-OP
404: }
405:
406: public void focusLost(FocusEvent e) {
407: fLastFocusControl = control;
408: }
409: });
410: }
411:
412: /**
413: * Set the focus on the last control to have focus before a page change
414: * or the editor lost focus.
415: */
416: public void updateFormSelection() {
417: if ((fLastFocusControl != null)
418: && (fLastFocusControl.isDisposed() == false)) {
419: // Set focus on the control
420: fLastFocusControl.setFocus();
421: // If the control is a Text widget, select its contents
422: if (fLastFocusControl instanceof Text) {
423: Text text = (Text) fLastFocusControl;
424: text.setSelection(0, text.getText().length());
425: }
426: } else {
427: // No focus control set
428: // Fallback on managed form selection mechanism by setting the
429: // focus on this page itself.
430: // The managed form will set focus on the first managed part.
431: // Most likely this will turn out to be a section.
432: // In order for this to work properly, we must override the
433: // sections setFocus() method and set focus on a child control
434: // (preferrably first) that can practically take focus.
435: setFocus();
436: }
437: }
438:
439: /**
440: * @return
441: */
442: public Control getLastFocusControl() {
443: return fLastFocusControl;
444: }
445:
446: /**
447: * @param control
448: */
449: public void setLastFocusControl(Control control) {
450: fLastFocusControl = control;
451: }
452:
453: /**
454: * @param managedForm
455: * @param errorTitle
456: * @param errorMessage
457: */
458: protected void createFormErrorContent(IManagedForm managedForm,
459: String errorTitle, String errorMessage) {
460: createFormErrorContent(managedForm, errorTitle, errorMessage,
461: null);
462: }
463:
464: /**
465: * @param managedForm
466: * @param errorTitle
467: * @param errorMessage
468: * @param e
469: */
470: protected void createFormErrorContent(IManagedForm managedForm,
471: String errorTitle, String errorMessage, Exception e) {
472:
473: ScrolledForm form = managedForm.getForm();
474: FormToolkit toolkit = managedForm.getToolkit();
475: //FormColors colors = toolkit.getColors();
476: //form.getForm().setSeparatorColor(colors.getColor(FormColors.TB_BORDER));
477: if (fNewStyleHeader) {
478: //createNewStyleHeader(form, colors);
479: toolkit.decorateFormHeading(form.getForm());
480: }
481:
482: Composite parent = form.getBody();
483: GridLayout layout = new GridLayout();
484: GridData data2 = new GridData(GridData.FILL_BOTH);
485: layout.marginWidth = 7;
486: layout.marginHeight = 7;
487: parent.setLayout(layout);
488: parent.setLayoutData(data2);
489: // Set the title and image of the form
490: form.setText(errorTitle);
491: form.setImage(JFaceResources
492: .getImage(Dialog.DLG_IMG_MESSAGE_ERROR));
493:
494: int sectionStyle = Section.DESCRIPTION
495: | ExpandableComposite.TITLE_BAR;
496: // Create the message section
497: Section messageSection = createUISection(parent,
498: PDEUIMessages.PDEFormPage_titleMessage, errorMessage,
499: sectionStyle);
500: Composite messageClient = createUISectionContainer(
501: messageSection, 1);
502: // Bind the widgets
503: toolkit.paintBordersFor(messageClient);
504: messageSection.setClient(messageClient);
505: // Ensure the exception was defined
506: if (e == null) {
507: return;
508: }
509: // Create the details section
510: Section detailsSection = createUISection(parent,
511: PDEUIMessages.PDEFormPage_titleDetails, e.getMessage(),
512: sectionStyle);
513: Composite detailsClient = createUISectionContainer(
514: detailsSection, 1);
515: // Create text widget holding the exception trace
516: int style = SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL
517: | SWT.READ_ONLY;
518: Text text = toolkit.createText(detailsClient, getStackTrace(e),
519: style);
520: GridData data = new GridData(GridData.FILL_HORIZONTAL);
521: data.heightHint = 160;
522: data.widthHint = 200;
523: text.setLayoutData(data);
524: // Bind the widgets
525: toolkit.paintBordersFor(detailsClient);
526: detailsSection.setClient(detailsClient);
527: // Note: The veritical scrollbar fails to appear when text widget is
528: // not entirely shown
529: }
530:
531: /**
532: * @param parent
533: * @param text
534: * @param description
535: * @param style
536: * @return
537: */
538: public Section createUISection(Composite parent, String text,
539: String description, int style) {
540: Section section = getManagedForm().getToolkit().createSection(
541: parent, style);
542: section.clientVerticalSpacing = FormLayoutFactory.SECTION_HEADER_VERTICAL_SPACING;
543: section.setLayout(FormLayoutFactory.createClearGridLayout(
544: false, 1));
545: section.setText(text);
546: section.setDescription(description);
547: GridData data = new GridData(GridData.FILL_HORIZONTAL);
548: section.setLayoutData(data);
549: return section;
550: }
551:
552: /**
553: * @param parent
554: * @param columns
555: * @return
556: */
557: public Composite createUISectionContainer(Composite parent,
558: int columns) {
559: Composite container = getManagedForm().getToolkit()
560: .createComposite(parent);
561: container.setLayout(FormLayoutFactory
562: .createSectionClientGridLayout(false, columns));
563: return container;
564: }
565:
566: /**
567: * @param throwable
568: * @return
569: */
570: public String getStackTrace(Throwable throwable) {
571: StringWriter swriter = new StringWriter();
572: PrintWriter pwriter = new PrintWriter(swriter);
573: throwable.printStackTrace(pwriter);
574: pwriter.flush();
575: pwriter.close();
576: return swriter.toString();
577: }
578:
579: /**
580: * Used to align the section client / decriptions of two section headers
581: * horizontally adjacent to each other. The misalignment is caused by one
582: * section header containing toolbar icons and the other not.
583: *
584: * @param masterSection
585: * @param detailsSection
586: */
587: public void alignSectionHeaders(Section masterSection,
588: Section detailsSection) {
589: detailsSection.descriptionVerticalSpacing += masterSection
590: .getTextClientHeightDifference();
591: }
592:
593: /**
594: * @param form
595: * @param colors
596: */
597: /*
598: private void createNewStyleHeader(final ScrolledForm form, FormColors colors) {
599: colors.initializeSectionToolBarColors();
600: Color gbg = colors.getColor(IFormColors.TB_BG);
601: Color bg = colors.getBackground();
602: form.getForm().setTextBackground(new Color[]{bg, gbg}, new int [] {100}, true);
603: form.getForm().setSeparatorVisible(true);
604: }
605: */
606: }
|