001: /*******************************************************************************
002: * Copyright (c) 2000, 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.schema;
011:
012: import org.eclipse.jface.text.DocumentEvent;
013: import org.eclipse.jface.text.IDocument;
014: import org.eclipse.jface.text.IDocumentListener;
015: import org.eclipse.jface.viewers.ISelection;
016: import org.eclipse.jface.viewers.IStructuredSelection;
017: import org.eclipse.pde.core.IModelChangedEvent;
018: import org.eclipse.pde.internal.core.ischema.ISchemaCompositor;
019: import org.eclipse.pde.internal.core.ischema.ISchemaObject;
020: import org.eclipse.pde.internal.core.schema.SchemaObject;
021: import org.eclipse.pde.internal.ui.PDEUIMessages;
022: import org.eclipse.pde.internal.ui.editor.FormLayoutFactory;
023: import org.eclipse.pde.internal.ui.editor.PDEDetails;
024: import org.eclipse.pde.internal.ui.editor.PDEFormPage;
025: import org.eclipse.pde.internal.ui.parts.ComboPart;
026: import org.eclipse.pde.internal.ui.parts.PDESourceViewer;
027: import org.eclipse.swt.SWT;
028: import org.eclipse.swt.dnd.Clipboard;
029: import org.eclipse.swt.events.ModifyEvent;
030: import org.eclipse.swt.events.ModifyListener;
031: import org.eclipse.swt.events.SelectionAdapter;
032: import org.eclipse.swt.events.SelectionEvent;
033: import org.eclipse.swt.graphics.GC;
034: import org.eclipse.swt.layout.GridData;
035: import org.eclipse.swt.layout.GridLayout;
036: import org.eclipse.swt.widgets.Button;
037: import org.eclipse.swt.widgets.Composite;
038: import org.eclipse.swt.widgets.Label;
039: import org.eclipse.swt.widgets.Spinner;
040: import org.eclipse.ui.forms.IFormColors;
041: import org.eclipse.ui.forms.IFormPart;
042: import org.eclipse.ui.forms.widgets.ExpandableComposite;
043: import org.eclipse.ui.forms.widgets.FormToolkit;
044: import org.eclipse.ui.forms.widgets.Section;
045:
046: public abstract class AbstractSchemaDetails extends PDEDetails {
047:
048: protected static final String[] BOOLS = new String[] {
049: Boolean.toString(true), Boolean.toString(false) };
050:
051: protected int minLabelWeight;
052:
053: private Section fSection;
054: private SchemaDtdDetailsSection fDtdSection = null;
055: private ElementSection fElementSection;
056: private boolean fShowDTD;
057: private boolean fShowDescription;
058: private Spinner fMinOccurSpinner;
059: private Spinner fMaxOccurSpinner;
060: private Button fUnboundSelect;
061: private Label fMinLabel;
062: private Label fMaxLabel;
063: private PDESourceViewer fDescriptionViewer = null;
064: private boolean fBlockListeners = false;
065: private ISchemaObject fSchemaObject;
066:
067: public AbstractSchemaDetails(ElementSection section,
068: boolean showDTD, boolean showDescription) {
069: fElementSection = section;
070: fShowDTD = showDTD;
071: fShowDescription = showDescription;
072: }
073:
074: public void modelChanged(IModelChangedEvent event) {
075: if ((event.getChangeType() == IModelChangedEvent.REMOVE)
076: || (fShowDTD == false) || (fDtdSection == null)) {
077: return;
078: }
079: Object[] objects = event.getChangedObjects();
080: for (int i = 0; i < objects.length; i++) {
081: if (objects[i] instanceof ISchemaCompositor)
082: fDtdSection.updateDTDLabel(objects[i]);
083: }
084: }
085:
086: public final void createContents(Composite parent) {
087: // This is a hacked fix to ensure that the label columns on every details
088: // page have the same width. SchemaDetails_translatable plus 11 pixels
089: // represents the longest label on any field on any details page. This
090: // occurs on SchemaStringAttributeDetails and 11 is the size of the
091: // horizontal indent that contributes to the label's width.
092: GC gc = new GC(parent);
093: minLabelWeight = gc
094: .textExtent(PDEUIMessages.SchemaDetails_translatable).x + 11;
095: gc.dispose();
096: gc = null;
097:
098: parent.setLayout(FormLayoutFactory.createDetailsGridLayout(
099: false, 1));
100: FormToolkit toolkit = getManagedForm().getToolkit();
101: fSection = toolkit.createSection(parent, Section.DESCRIPTION
102: | ExpandableComposite.TITLE_BAR);
103: fSection.clientVerticalSpacing = FormLayoutFactory.SECTION_HEADER_VERTICAL_SPACING;
104: fSection.setLayout(FormLayoutFactory.createClearGridLayout(
105: false, 1));
106:
107: GridData gd;
108: if (fShowDescription)
109: gd = new GridData(GridData.FILL_BOTH);
110: else
111: gd = new GridData(GridData.FILL_HORIZONTAL);
112: fSection.setLayoutData(gd);
113:
114: // Align the master and details section headers (misalignment caused
115: // by section toolbar icons)
116: getPage().alignSectionHeaders(fElementSection.getSection(),
117: fSection);
118:
119: Composite client = toolkit.createComposite(fSection);
120: client.setLayout(FormLayoutFactory
121: .createSectionClientGridLayout(false, 3));
122:
123: createDetails(client);
124:
125: if (fShowDescription)
126: createDescription(client, toolkit);
127:
128: // If the DTD Approximation section was requested, instantiate it and create it's contents
129: // on the same parent Composite
130: if (fShowDTD) {
131: fDtdSection = new SchemaDtdDetailsSection();
132: fDtdSection.initialize(getManagedForm());
133: fDtdSection.createContents(parent);
134: }
135:
136: toolkit.paintBordersFor(client);
137: fSection.setClient(client);
138: markDetailsPart(fSection);
139:
140: if (fShowDescription)
141: fDescriptionViewer.createUIListeners();
142: hookListeners();
143: }
144:
145: private void createDescription(Composite container,
146: FormToolkit toolkit) {
147:
148: Label label = toolkit.createLabel(container,
149: PDEUIMessages.AbstractSchemaDetails_descriptionLabel);
150: GridData gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
151: gd.horizontalSpan = 3;
152: label.setLayoutData(gd);
153: label.setForeground(toolkit.getColors().getColor(
154: IFormColors.TITLE));
155:
156: fDescriptionViewer = new PDESourceViewer(getPage());
157: gd = new GridData(GridData.FILL_BOTH);
158: gd.heightHint = 75;
159: gd.widthHint = 60;
160: gd.horizontalSpan = 3;
161: gd.horizontalIndent = 1;
162: /*
163: * Needed to align vertically with form entry field and allow space
164: * for a possible field decoration
165: * commented out for now since fields are already grossly misaligned (see bug 196879)
166: * commenting out temporarily makes the alignment better on Element details and Attribute details
167: * but worse on RootElement details
168: */
169: //gd.horizontalIndent = FormLayoutFactory.CONTROL_HORIZONTAL_INDENT;
170: fDescriptionViewer.createUI(container, gd);
171: fDescriptionViewer.getDocument().addDocumentListener(
172: new IDocumentListener() {
173: public void documentChanged(DocumentEvent event) {
174: if (blockListeners())
175: return;
176: if (fSchemaObject != null) {
177: // Get the text from the event
178: IDocument document = event.getDocument();
179: if (document == null) {
180: return;
181: }
182: // Get the text from the event
183: String text = document.get().trim();
184: updateObjectDescription(text);
185: }
186: }
187:
188: public void documentAboutToBeChanged(
189: DocumentEvent event) {
190: }
191: });
192: }
193:
194: public abstract void createDetails(Composite parent);
195:
196: public abstract void updateFields(ISchemaObject obj);
197:
198: public abstract void hookListeners();
199:
200: public boolean isEditableElement() {
201: return fElementSection.isEditable();
202: }
203:
204: protected void setDecription(String desc) {
205: fSection.setDescription(desc);
206: }
207:
208: protected void setText(String title) {
209: fSection.setText(title);
210: }
211:
212: public String getContextId() {
213: return SchemaInputContext.CONTEXT_ID;
214: }
215:
216: public PDEFormPage getPage() {
217: return (PDEFormPage) getManagedForm().getContainer();
218: }
219:
220: public boolean isEditable() {
221: return getPage().getPDEEditor().getAggregateModel()
222: .isEditable();
223: }
224:
225: public void fireSaveNeeded() {
226: markDirty();
227: getPage().getPDEEditor().fireSaveNeeded(getContextId(), false);
228: }
229:
230: public boolean canPaste(Clipboard clipboard) {
231: if (fShowDescription
232: && fDescriptionViewer != null
233: && fDescriptionViewer.getViewer().getTextWidget()
234: .isFocusControl())
235: return fDescriptionViewer.canPaste();
236: return super .canPaste(clipboard);
237: }
238:
239: public boolean doGlobalAction(String actionId) {
240: if (fShowDescription
241: && fDescriptionViewer != null
242: && fDescriptionViewer.getViewer().getTextWidget()
243: .isFocusControl())
244: return fDescriptionViewer.doGlobalAction(actionId);
245: return super .doGlobalAction(actionId);
246: }
247:
248: public void selectionChanged(IFormPart part, ISelection selection) {
249: if (!(part instanceof ElementSection))
250: return;
251: Object obj = ((IStructuredSelection) selection)
252: .getFirstElement();
253: if (obj instanceof ISchemaObject) {
254: setBlockListeners(true);
255: ISchemaObject sObj = (ISchemaObject) obj;
256: fSchemaObject = sObj;
257: if (fShowDTD && fDtdSection != null)
258: fDtdSection.updateDTDLabel(obj);
259: if (fShowDescription && fDescriptionViewer != null)
260: updateDescriptionViewer(sObj);
261: updateFields(sObj);
262: setBlockListeners(false);
263: }
264: }
265:
266: public void updateDescriptionViewer(ISchemaObject obj) {
267: if (obj != null) {
268: String text = obj.getDescription();
269: fDescriptionViewer.getDocument().set(
270: text == null ? "" : text); //$NON-NLS-1$
271: fDescriptionViewer.getViewer().setEditable(
272: obj.getSchema().isEditable());
273: }
274: }
275:
276: private void updateObjectDescription(String text) {
277: if (fSchemaObject instanceof SchemaObject) {
278: ((SchemaObject) fSchemaObject).setDescription(text);
279: }
280: }
281:
282: protected void fireSelectionChange() {
283: fElementSection.fireSelection(fElementSection.getTreeViewer()
284: .getSelection());
285: }
286:
287: protected void fireMasterSelection(ISelection selection) {
288: fElementSection.fireSelection(selection);
289: }
290:
291: protected ComboPart createComboPart(Composite parent,
292: FormToolkit toolkit, String[] items, int colspan, int style) {
293: ComboPart cp = new ComboPart();
294: cp.createControl(parent, toolkit, SWT.READ_ONLY);
295: GridData gd = new GridData(style);
296: gd.horizontalSpan = colspan;
297: gd.horizontalIndent = FormLayoutFactory.CONTROL_HORIZONTAL_INDENT;
298: cp.getControl().setLayoutData(gd);
299: cp.setItems(items);
300: cp.getControl().setEnabled(isEditable());
301: return cp;
302: }
303:
304: protected ComboPart createComboPart(Composite parent,
305: FormToolkit toolkit, String[] items, int colspan) {
306: return createComboPart(parent, toolkit, items, colspan,
307: GridData.FILL_HORIZONTAL);
308: }
309:
310: protected Button[] createTrueFalseButtons(Composite parent,
311: FormToolkit toolkit, int colSpan) {
312: Composite comp = toolkit.createComposite(parent, SWT.NONE);
313: GridLayout gl = new GridLayout(2, false);
314: gl.marginHeight = gl.marginWidth = 0;
315: comp.setLayout(gl);
316: GridData gd = new GridData(GridData.FILL_HORIZONTAL);
317: gd.horizontalSpan = colSpan;
318: gd.horizontalIndent = FormLayoutFactory.CONTROL_HORIZONTAL_INDENT;
319: comp.setLayoutData(gd);
320: Button tButton = toolkit
321: .createButton(comp, BOOLS[0], SWT.RADIO);
322: Button fButton = toolkit
323: .createButton(comp, BOOLS[1], SWT.RADIO);
324: gd = new GridData();
325: gd.horizontalIndent = 20;
326: fButton.setLayoutData(gd);
327: return new Button[] { tButton, fButton };
328: }
329:
330: protected Composite createMinOccurComp(Composite parent,
331: FormToolkit toolkit) {
332: fMinLabel = toolkit.createLabel(parent,
333: PDEUIMessages.AbstractSchemaDetails_minOccurLabel);
334: fMinLabel.setForeground(toolkit.getColors().getColor(
335: IFormColors.TITLE));
336: Composite comp = toolkit.createComposite(parent);
337: GridData gd = new GridData(GridData.FILL_HORIZONTAL);
338: gd.horizontalSpan = 2;
339: GridLayout layout = new GridLayout();
340: layout.marginHeight = layout.marginWidth = 0;
341: comp.setLayout(layout);
342: comp.setLayoutData(gd);
343: fMinOccurSpinner = new Spinner(comp, SWT.BORDER);
344: fMinOccurSpinner.setMinimum(0);
345: fMinOccurSpinner.setMaximum(999);
346: return comp;
347: }
348:
349: protected Composite createMaxOccurComp(Composite parent,
350: FormToolkit toolkit) {
351: fMaxLabel = toolkit.createLabel(parent,
352: PDEUIMessages.AbstractSchemaDetails_maxOccurLabel);
353: fMaxLabel.setForeground(toolkit.getColors().getColor(
354: IFormColors.TITLE));
355: Composite comp = toolkit.createComposite(parent);
356: GridData gd = new GridData(GridData.FILL_HORIZONTAL);
357: gd.horizontalSpan = 2;
358: GridLayout layout = new GridLayout(3, false);
359: layout.marginHeight = layout.marginWidth = 0;
360: comp.setLayout(layout);
361: comp.setLayoutData(gd);
362:
363: fMaxOccurSpinner = new Spinner(comp, SWT.BORDER);
364: fMaxOccurSpinner.setMinimum(1);
365: fMaxOccurSpinner.setMaximum(999);
366: fMaxOccurSpinner.setIncrement(1);
367:
368: fUnboundSelect = toolkit.createButton(comp,
369: PDEUIMessages.AbstractSchemaDetails_unboundedButton,
370: SWT.CHECK);
371: gd = new GridData();
372: gd.horizontalIndent = 10;
373: fUnboundSelect.setLayoutData(gd);
374: fUnboundSelect.addSelectionListener(new SelectionAdapter() {
375: public void widgetSelected(SelectionEvent e) {
376: if (blockListeners())
377: return;
378: fMaxOccurSpinner.setEnabled(!fUnboundSelect
379: .getSelection()
380: && isEditableElement());
381: }
382: });
383:
384: return comp;
385: }
386:
387: protected int getMinOccur() {
388: if (fMinOccurSpinner != null)
389: return fMinOccurSpinner.getSelection();
390: return 0;
391: }
392:
393: protected int getMaxOccur() {
394: if (fMaxOccurSpinner != null) {
395: if (fMaxOccurSpinner.isEnabled())
396: return fMaxOccurSpinner.getSelection();
397: return Integer.MAX_VALUE;
398: }
399: return 1;
400: }
401:
402: protected void updateMinOccur(int min) {
403: if (fMinOccurSpinner != null)
404: fMinOccurSpinner.setSelection(min);
405: }
406:
407: protected void updateMaxOccur(int max) {
408: if (fMaxOccurSpinner == null)
409: return;
410: boolean isMax = max == Integer.MAX_VALUE;
411: fUnboundSelect.setSelection(isMax);
412: fMaxOccurSpinner.setEnabled(!isMax);
413: if (!isMax)
414: fMaxOccurSpinner.setSelection(max);
415: }
416:
417: protected void hookMinOccur(SelectionAdapter adapter) {
418: fMinOccurSpinner.addSelectionListener(adapter);
419: fMinOccurSpinner.addModifyListener(new ModifyListener() {
420: public void modifyText(ModifyEvent e) {
421: if (blockListeners())
422: return;
423: int minOccur = fMinOccurSpinner.getSelection();
424: if (minOccur > getMaxOccur())
425: fMinOccurSpinner.setSelection(minOccur - 1);
426: }
427: });
428: }
429:
430: protected void hookMaxOccur(SelectionAdapter adapter) {
431: fUnboundSelect.addSelectionListener(adapter);
432: fMaxOccurSpinner.addSelectionListener(adapter);
433: fMaxOccurSpinner.addModifyListener(new ModifyListener() {
434: public void modifyText(ModifyEvent e) {
435: if (blockListeners())
436: return;
437: int maxValue = fMaxOccurSpinner.getSelection();
438: if (maxValue < getMinOccur())
439: fMaxOccurSpinner.setSelection(maxValue + 1);
440: }
441: });
442: }
443:
444: protected void enableMinMax(boolean enable) {
445: fMinOccurSpinner.setEnabled(enable);
446: fMaxOccurSpinner.setEnabled(!fUnboundSelect.getSelection()
447: && enable);
448: fUnboundSelect.setEnabled(enable);
449: fMinLabel.setEnabled(enable);
450: fMaxLabel.setEnabled(enable);
451: }
452:
453: protected boolean blockListeners() {
454: return fBlockListeners;
455: }
456:
457: protected void setBlockListeners(boolean blockListeners) {
458: fBlockListeners = blockListeners;
459: }
460:
461: public void dispose() {
462: // Set the context menu to null to prevent the editor context menu
463: // from being disposed along with the source viewer
464: if (fDescriptionViewer != null) {
465: fDescriptionViewer.unsetMenu();
466: fDescriptionViewer = null;
467: }
468: super.dispose();
469: }
470: }
|