001: /*******************************************************************************
002: * Copyright (c) 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.plugin;
011:
012: import org.eclipse.core.runtime.CoreException;
013: import org.eclipse.jface.text.IInformationControl;
014: import org.eclipse.jface.viewers.ISelection;
015: import org.eclipse.jface.viewers.IStructuredSelection;
016: import org.eclipse.osgi.util.NLS;
017: import org.eclipse.pde.core.IModelChangedEvent;
018: import org.eclipse.pde.core.plugin.IPluginElement;
019: import org.eclipse.pde.core.plugin.IPluginModelBase;
020: import org.eclipse.pde.internal.core.ischema.ISchemaElement;
021: import org.eclipse.pde.internal.ui.PDEPlugin;
022: import org.eclipse.pde.internal.ui.PDEUIMessages;
023: import org.eclipse.pde.internal.ui.editor.FormEntryAdapter;
024: import org.eclipse.pde.internal.ui.editor.FormLayoutFactory;
025: import org.eclipse.pde.internal.ui.editor.PDEFormPage;
026: import org.eclipse.pde.internal.ui.editor.PDESection;
027: import org.eclipse.pde.internal.ui.editor.text.IControlHoverContentProvider;
028: import org.eclipse.pde.internal.ui.editor.text.PDETextHover;
029: import org.eclipse.pde.internal.ui.editor.text.TranslationHyperlink;
030: import org.eclipse.pde.internal.ui.parts.FormEntry;
031: import org.eclipse.swt.SWT;
032: import org.eclipse.swt.layout.GridData;
033: import org.eclipse.swt.widgets.Composite;
034: import org.eclipse.swt.widgets.Control;
035: import org.eclipse.swt.widgets.Display;
036: import org.eclipse.swt.widgets.Label;
037: import org.eclipse.swt.widgets.Text;
038: import org.eclipse.ui.forms.IFormPart;
039: import org.eclipse.ui.forms.events.HyperlinkAdapter;
040: import org.eclipse.ui.forms.events.HyperlinkEvent;
041: import org.eclipse.ui.forms.widgets.ExpandableComposite;
042: import org.eclipse.ui.forms.widgets.FormToolkit;
043: import org.eclipse.ui.forms.widgets.Hyperlink;
044: import org.eclipse.ui.forms.widgets.Section;
045:
046: /**
047: * ExtensionElementBodyTextDetails
048: *
049: */
050: public class ExtensionElementBodyTextDetails extends
051: AbstractPluginElementDetails implements
052: IControlHoverContentProvider {
053:
054: private IPluginElement fPluginElement;
055:
056: private ISchemaElement fSchemaElement;
057:
058: private FormEntry fTextBody;
059:
060: private Section fSectionElementDetails;
061:
062: private FormToolkit fToolkit;
063:
064: private Hyperlink fHyperlinkBody;
065:
066: private IInformationControl fInfoControlHover;
067:
068: /**
069: *
070: */
071: public ExtensionElementBodyTextDetails(PDESection masterSection) {
072: super (masterSection);
073: fPluginElement = null;
074: fSchemaElement = null;
075: fTextBody = null;
076: fSectionElementDetails = null;
077: }
078:
079: /* (non-Javadoc)
080: * @see org.eclipse.ui.forms.IDetailsPage#createContents(org.eclipse.swt.widgets.Composite)
081: */
082: public void createContents(Composite parent) {
083: // Get the toolkit
084: createUIToolkit();
085: // Configure the parents layout
086: configureParentLayout(parent);
087: // Create the UI
088: createUI(parent);
089: // Create the listeners
090: createListeners();
091: }
092:
093: /**
094: *
095: */
096: private void createListeners() {
097: // Create the listeners for the body text field
098: createListenersTextBody();
099: // Create the listeners for the body text hyperlink
100: createListenersHyperlinkBody();
101: // Create the model listeners
102: createListenersModel();
103: }
104:
105: /**
106: *
107: */
108: private void createListenersHyperlinkBody() {
109: // Listen to hyperlink clicks
110: fHyperlinkBody.addHyperlinkListener(new HyperlinkAdapter() {
111: public void linkActivated(HyperlinkEvent e) {
112: handleHyperlinkBodyLinkActivated();
113: }
114: });
115: // Listen to mouse hovers
116: PDETextHover.addHoverListenerToControl(fInfoControlHover,
117: fHyperlinkBody, this );
118: }
119:
120: /**
121: *
122: */
123: private void handleHyperlinkBodyLinkActivated() {
124: boolean opened = false;
125: // Open the reference if this is not a reference model
126: if (isReferenceModel() == false) {
127: opened = openReference();
128: }
129: // If the reference was not opened, notify the user with a beep
130: if (opened == false) {
131: Display.getCurrent().beep();
132: }
133: }
134:
135: /**
136: *
137: */
138: private boolean openReference() {
139: // Ensure a plugin element was specified
140: if (fPluginElement == null) {
141: return false;
142: }
143: // Create the link
144: TranslationHyperlink link = new TranslationHyperlink(null,
145: fTextBody.getValue(), fPluginElement.getModel());
146: // Open the link
147: link.open();
148:
149: return link.getOpened();
150: }
151:
152: /**
153: *
154: */
155: private void createListenersModel() {
156: IPluginModelBase model = (IPluginModelBase) getPage()
157: .getModel();
158: model.addModelChangedListener(this );
159: }
160:
161: /**
162: *
163: */
164: private void createListenersTextBody() {
165: // Listen for text input
166: fTextBody.setFormEntryListener(new FormEntryAdapter(this ) {
167: public void textValueChanged(FormEntry entry) {
168: handleTextBodyValueChanged();
169: }
170: });
171: // Listen to mouse hovers
172: PDETextHover.addHoverListenerToControl(fInfoControlHover,
173: fTextBody.getText(), this );
174: }
175:
176: /**
177: *
178: */
179: private void handleTextBodyValueChanged() {
180: // Plugin element data not defined, nothing to update
181: if (fPluginElement == null) {
182: return;
183: }
184: // Update the body text field with the new value from plugin element
185: // data
186: try {
187: fPluginElement.setText(fTextBody.getValue());
188: } catch (CoreException e) {
189: PDEPlugin.logException(e);
190: }
191: }
192:
193: /**
194: * @param parent
195: */
196: private void configureParentLayout(Composite parent) {
197: parent.setLayout(FormLayoutFactory.createDetailsGridLayout(
198: false, 1));
199: }
200:
201: /**
202: *
203: */
204: private void createUIToolkit() {
205: fToolkit = getManagedForm().getToolkit();
206: }
207:
208: /**
209: * @param parent
210: */
211: private void createUI(Composite parent) {
212: // Create the element details section
213: createUISectionElementDetails(parent);
214: // Create the client container for the section
215: Composite client = createUISectionContainer(fSectionElementDetails);
216: // Create the info hover control for the body text field and hyperlink
217: createUIInfoHoverControl(client);
218: // Create the body text label
219: createUIHyperlinkBody(client);
220: // Create the body text field
221: createUITextBody(client);
222: // Associate the client with the section
223: fToolkit.paintBordersFor(client);
224: fSectionElementDetails.setClient(client);
225: // Needed for keyboard paste operation to work
226: markDetailsPart(fSectionElementDetails);
227: }
228:
229: /**
230: * @param client
231: */
232: private void createUIInfoHoverControl(Composite client) {
233: // Shared between the body text field and body text hyperlink / label
234: fInfoControlHover = PDETextHover.getInformationControlCreator()
235: .createInformationControl(client.getShell());
236: fInfoControlHover.setSizeConstraints(300, 600);
237: }
238:
239: /**
240: * @param client
241: */
242: private void createUIHyperlinkBody(Composite client) {
243: fHyperlinkBody = fToolkit
244: .createHyperlink(
245: client,
246: PDEUIMessages.ExtensionElementBodyTextDetails_labelBodyText,
247: SWT.NULL);
248: }
249:
250: /**
251: * @return
252: */
253: private boolean isReferenceModel() {
254: // If the model has no underlying resource, then it is a reference
255: // model
256: if ((fPluginElement == null)
257: || (fPluginElement.getModel().getUnderlyingResource() == null)) {
258: return true;
259: }
260: return false;
261: }
262:
263: /**
264: * @param section
265: * @return
266: */
267: private Composite createUISectionContainer(Section section) {
268: Composite client = fToolkit.createComposite(section);
269: client.setLayout(FormLayoutFactory
270: .createSectionClientGridLayout(false, 1));
271: return client;
272: }
273:
274: /**
275: * @param parent
276: */
277: private void createUISectionElementDetails(Composite parent) {
278: int section_style = Section.DESCRIPTION
279: | ExpandableComposite.TITLE_BAR;
280: fSectionElementDetails = fToolkit.createSection(parent,
281: section_style);
282: fSectionElementDetails.clientVerticalSpacing = FormLayoutFactory.SECTION_HEADER_VERTICAL_SPACING;
283: fSectionElementDetails
284: .setText(PDEUIMessages.ExtensionElementDetails_title);
285: fSectionElementDetails
286: .setDescription(PDEUIMessages.ExtensionElementBodyTextDetails_sectionDescElementGeneral);
287: fSectionElementDetails.setLayout(FormLayoutFactory
288: .createClearGridLayout(false, 1));
289: int layout_style = GridData.FILL_HORIZONTAL;
290: GridData data = new GridData(layout_style);
291: fSectionElementDetails.setLayoutData(data);
292:
293: // Align the master and details section headers (misalignment caused
294: // by section toolbar icons)
295: getPage().alignSectionHeaders(getMasterSection().getSection(),
296: fSectionElementDetails);
297: }
298:
299: /**
300: * @param parent
301: */
302: private void createUITextBody(Composite parent) {
303: int widget_style = SWT.MULTI | SWT.WRAP | SWT.V_SCROLL;
304: fTextBody = new FormEntry(parent, fToolkit, null, widget_style);
305: int layout_text_style = GridData.FILL_HORIZONTAL;
306: GridData data = new GridData(layout_text_style);
307: data.heightHint = 90;
308: fTextBody.getText().setLayoutData(data);
309: }
310:
311: /* (non-Javadoc)
312: * @see org.eclipse.ui.forms.IPartSelectionListener#selectionChanged(org.eclipse.ui.forms.IFormPart, org.eclipse.jface.viewers.ISelection)
313: */
314: public void selectionChanged(IFormPart part, ISelection selection) {
315: // Get the structured selection
316: IStructuredSelection structured_selection = (IStructuredSelection) selection;
317: // The selection from the master tree viewer is our plugin element data
318: if (structured_selection.size() == 1) {
319: fPluginElement = (IPluginElement) structured_selection
320: .getFirstElement();
321: } else {
322: fPluginElement = null;
323: }
324: // Update the UI given the new plugin element data
325: updateUI();
326: }
327:
328: /**
329: *
330: */
331: private void updateUI() {
332: // Update the section description
333: updateUISectionElementDetails();
334: // Update the body text field
335: updateUITextBody();
336: }
337:
338: /**
339: *
340: */
341: private void updateUISectionElementDetails() {
342: // Set the general or specifc section description depending if whether
343: // the plugin element data is defined
344: if (fPluginElement == null) {
345: fSectionElementDetails
346: .setDescription(PDEUIMessages.ExtensionElementBodyTextDetails_sectionDescElementGeneral);
347: } else {
348: fSectionElementDetails
349: .setDescription(NLS
350: .bind(
351: PDEUIMessages.ExtensionElementBodyTextDetails_sectionDescElementSpecific,
352: fPluginElement.getName()));
353: }
354: // Re-layout the section to properly wrap the new section description
355: fSectionElementDetails.layout();
356: }
357:
358: /**
359: *
360: */
361: private void updateUITextBody() {
362: // Set the new body text value from the new plugin element data if
363: // defined
364: if (fPluginElement == null) {
365: fTextBody.setEditable(false);
366: fTextBody.setValue(null, true);
367: } else {
368: fTextBody.setEditable(isEditable());
369: fTextBody.setValue(fPluginElement.getText(), true);
370: }
371: }
372:
373: /* (non-Javadoc)
374: * @see org.eclipse.pde.internal.ui.editor.IContextPart#fireSaveNeeded()
375: */
376: public void fireSaveNeeded() {
377: markDirty();
378: getPage().getPDEEditor().fireSaveNeeded(getContextId(), false);
379: }
380:
381: /* (non-Javadoc)
382: * @see org.eclipse.pde.internal.ui.editor.IContextPart#getContextId()
383: */
384: public String getContextId() {
385: return PluginInputContext.CONTEXT_ID;
386: }
387:
388: /* (non-Javadoc)
389: * @see org.eclipse.pde.internal.ui.editor.IContextPart#getPage()
390: */
391: public PDEFormPage getPage() {
392: return (PDEFormPage) getManagedForm().getContainer();
393: }
394:
395: /* (non-Javadoc)
396: * @see org.eclipse.pde.internal.ui.editor.IContextPart#isEditable()
397: */
398: public boolean isEditable() {
399: return getPage().getPDEEditor().getAggregateModel()
400: .isEditable();
401: }
402:
403: /* (non-Javadoc)
404: * @see org.eclipse.pde.core.IModelChangedListener#modelChanged(org.eclipse.pde.core.IModelChangedEvent)
405: */
406: public void modelChanged(IModelChangedEvent event) {
407: // Refresh the UI if the plugin element data changed
408: if (event.getChangeType() == IModelChangedEvent.CHANGE) {
409: Object object = event.getChangedObjects()[0];
410: if (object.equals(fPluginElement)) {
411: refresh();
412: }
413: }
414: }
415:
416: /* (non-Javadoc)
417: * @see org.eclipse.ui.forms.AbstractFormPart#refresh()
418: */
419: public void refresh() {
420: updateUI();
421: super .refresh();
422: }
423:
424: /* (non-Javadoc)
425: * @see org.eclipse.pde.internal.ui.editor.PDEDetails#cancelEdit()
426: */
427: public void cancelEdit() {
428: fTextBody.cancelEdit();
429: super .cancelEdit();
430: }
431:
432: /* (non-Javadoc)
433: * @see org.eclipse.ui.forms.AbstractFormPart#commit(boolean)
434: */
435: public void commit(boolean onSave) {
436: fTextBody.commit();
437: super .commit(onSave);
438: }
439:
440: /* (non-Javadoc)
441: * @see org.eclipse.ui.forms.AbstractFormPart#dispose()
442: */
443: public void dispose() {
444: IPluginModelBase model = (IPluginModelBase) getPage()
445: .getModel();
446: // Remove the model listener
447: if (model != null) {
448: model.removeModelChangedListener(this );
449: }
450: super .dispose();
451: }
452:
453: /* (non-Javadoc)
454: * @see org.eclipse.ui.forms.AbstractFormPart#setFocus()
455: */
456: public void setFocus() {
457: fTextBody.getText().setFocus();
458: }
459:
460: /* (non-Javadoc)
461: * @see org.eclipse.pde.internal.ui.editor.text.TextHoverDescriptionProvider#getDescription(org.eclipse.swt.widgets.Control)
462: */
463: public String getHoverContent(Control control) {
464: // Retrieve either the hyperlink, label or text description as the
465: // hover content
466: if ((control instanceof Hyperlink)
467: || (control instanceof Label)) {
468: return getHyperlinkDescription();
469: } else if (control instanceof Text) {
470: return getTextDescription((Text) control);
471: }
472:
473: return null;
474: }
475:
476: /**
477: * @return
478: */
479: private String getHyperlinkDescription() {
480: // Ensure there is an associated schema
481: if (fSchemaElement == null) {
482: return null;
483: }
484: // Return the associated element description
485: return fSchemaElement.getDescription();
486: }
487:
488: /**
489: * @param text
490: * @return
491: */
492: private String getTextDescription(Text text) {
493: // Ensure there is an associated schema
494: if (fSchemaElement == null) {
495: return null;
496: }
497: String bodyText = text.getText();
498: String translatedBodyText = null;
499: // If the text represents a translated string key, retrieve its
500: // associated value
501: if ((bodyText.startsWith("%")) && //$NON-NLS-1$
502: fSchemaElement.hasTranslatableContent()) {
503: translatedBodyText = fPluginElement
504: .getResourceString(bodyText);
505: // If the value does not equal the key, a value was found
506: if (bodyText.equals(translatedBodyText) == false) {
507: return translatedBodyText;
508: }
509: }
510:
511: return null;
512: }
513:
514: /**
515: * @param schemaElement
516: */
517: public void setSchemaElement(ISchemaElement schemaElement) {
518: fSchemaElement = schemaElement;
519: }
520:
521: }
|