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.wizards.extension;
011:
012: import java.io.ByteArrayInputStream;
013: import java.io.IOException;
014: import java.io.InputStream;
015: import java.io.PrintWriter;
016: import java.io.StringWriter;
017: import java.io.UnsupportedEncodingException;
018:
019: import org.eclipse.core.resources.IContainer;
020: import org.eclipse.core.resources.IFile;
021: import org.eclipse.core.resources.IFolder;
022: import org.eclipse.core.resources.IResource;
023: import org.eclipse.core.resources.IWorkspace;
024: import org.eclipse.core.runtime.CoreException;
025: import org.eclipse.core.runtime.IPath;
026: import org.eclipse.core.runtime.IProgressMonitor;
027: import org.eclipse.core.runtime.Path;
028: import org.eclipse.jface.dialogs.Dialog;
029: import org.eclipse.jface.operation.IRunnableWithProgress;
030: import org.eclipse.jface.viewers.Viewer;
031: import org.eclipse.jface.viewers.ViewerFilter;
032: import org.eclipse.jface.window.Window;
033: import org.eclipse.jface.wizard.WizardPage;
034: import org.eclipse.osgi.util.NLS;
035: import org.eclipse.pde.core.plugin.IPluginModelBase;
036: import org.eclipse.pde.core.plugin.PluginRegistry;
037: import org.eclipse.pde.internal.core.PDECore;
038: import org.eclipse.pde.internal.core.ischema.IDocumentSection;
039: import org.eclipse.pde.internal.core.ischema.ISchemaAttribute;
040: import org.eclipse.pde.internal.core.schema.DocumentSection;
041: import org.eclipse.pde.internal.core.schema.EditableSchema;
042: import org.eclipse.pde.internal.core.schema.SchemaAttribute;
043: import org.eclipse.pde.internal.core.schema.SchemaComplexType;
044: import org.eclipse.pde.internal.core.schema.SchemaElement;
045: import org.eclipse.pde.internal.core.schema.SchemaRootElement;
046: import org.eclipse.pde.internal.core.schema.SchemaSimpleType;
047: import org.eclipse.pde.internal.core.util.CoreUtility;
048: import org.eclipse.pde.internal.core.util.IdUtil;
049: import org.eclipse.pde.internal.ui.IHelpContextIds;
050: import org.eclipse.pde.internal.ui.IPDEUIConstants;
051: import org.eclipse.pde.internal.ui.PDEPlugin;
052: import org.eclipse.pde.internal.ui.PDEUIMessages;
053: import org.eclipse.pde.internal.ui.util.SWTUtil;
054: import org.eclipse.pde.internal.ui.wizards.PluginSelectionDialog;
055: import org.eclipse.swt.SWT;
056: import org.eclipse.swt.events.ModifyEvent;
057: import org.eclipse.swt.events.ModifyListener;
058: import org.eclipse.swt.events.SelectionAdapter;
059: import org.eclipse.swt.events.SelectionEvent;
060: import org.eclipse.swt.layout.GridData;
061: import org.eclipse.swt.layout.GridLayout;
062: import org.eclipse.swt.widgets.Button;
063: import org.eclipse.swt.widgets.Composite;
064: import org.eclipse.swt.widgets.Display;
065: import org.eclipse.swt.widgets.Label;
066: import org.eclipse.swt.widgets.Text;
067: import org.eclipse.ui.IWorkbenchWindow;
068: import org.eclipse.ui.PartInitException;
069: import org.eclipse.ui.PlatformUI;
070: import org.eclipse.ui.actions.WorkspaceModifyOperation;
071: import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
072: import org.eclipse.ui.ide.IDE;
073: import org.eclipse.ui.model.WorkbenchContentProvider;
074: import org.eclipse.ui.model.WorkbenchLabelProvider;
075: import org.eclipse.ui.part.FileEditorInput;
076: import org.eclipse.ui.views.navigator.ResourceComparator;
077:
078: public abstract class BaseExtensionPointMainPage extends WizardPage {
079: public static final String SETTINGS_PLUGIN_ID = "BaseExtensionPoint.settings.pluginId"; //$NON-NLS-1$
080: public static final String SCHEMA_DIR = "schema"; //$NON-NLS-1$
081:
082: protected IContainer fContainer;
083: protected Text fIdText;
084: protected Text fPluginIdText;
085: protected Text fNameText;
086: protected Text fSchemaText;
087: protected Text fSchemaLocationText;
088: protected Button fOpenSchemaButton;
089: protected Button fSharedSchemaButton;
090: protected Button fPluginBrowseButton;
091: protected Button fFindLocationButton;
092:
093: public BaseExtensionPointMainPage(IContainer container) {
094: super ("newExtensionPoint"); //$NON-NLS-1$
095: fContainer = container;
096: }
097:
098: public void createControl(Composite parent) {
099: Composite container = new Composite(parent, SWT.NONE);
100: GridLayout layout = new GridLayout();
101: layout.numColumns = 3;
102: layout.verticalSpacing = 9;
103: layout.makeColumnsEqualWidth = false;
104: container.setLayout(layout);
105: Label label;
106: GridData gd;
107: if (isPluginIdNeeded()) {
108: label = new Label(container, SWT.NONE);
109: label.setText(PDEUIMessages.BaseExtensionPoint_pluginId);
110: fPluginIdText = new Text(container, SWT.SINGLE | SWT.BORDER);
111: gd = new GridData(GridData.FILL_HORIZONTAL);
112: gd.horizontalSpan = 1;
113: gd.widthHint = 275;
114: fPluginIdText.setLayoutData(gd);
115: fPluginIdText.addModifyListener(new ModifyListener() {
116: public void modifyText(ModifyEvent e) {
117: validatePage();
118: }
119: });
120: fPluginBrowseButton = new Button(container, SWT.PUSH);
121: gd = new GridData(GridData.HORIZONTAL_ALIGN_END);
122: gd.horizontalSpan = 1;
123: gd.widthHint = 50;
124: fPluginBrowseButton.setLayoutData(gd);
125: fPluginBrowseButton
126: .setText(PDEUIMessages.BaseExtensionPointMainPage_pluginBrowse);
127: fPluginBrowseButton
128: .setToolTipText(PDEUIMessages.BaseExtensionPointMainPage_pluginId_tooltip);
129: fPluginBrowseButton
130: .addSelectionListener(new SelectionAdapter() {
131: public void widgetSelected(SelectionEvent e) {
132: handlePluginBrowse();
133: }
134: });
135: SWTUtil.setButtonDimensionHint(fPluginBrowseButton);
136: }
137: label = new Label(container, SWT.NONE);
138: label.setText(PDEUIMessages.BaseExtensionPoint_id);
139: fIdText = new Text(container, SWT.SINGLE | SWT.BORDER);
140: gd = new GridData(GridData.FILL_HORIZONTAL);
141: gd.horizontalSpan = 2;
142: fIdText.setLayoutData(gd);
143: fIdText.addModifyListener(new ModifyListener() {
144: public void modifyText(ModifyEvent e) {
145: // setting the text will trigger validation
146: // do not implicitly validate here
147: fSchemaText
148: .setText(getSchemaLocation()
149: + (getSchemaLocation().length() > 0 ? "/" : "") + fIdText.getText() + ".exsd"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
150: }
151: });
152: label = new Label(container, SWT.NONE);
153: label.setText(PDEUIMessages.BaseExtensionPoint_name);
154: fNameText = new Text(container, SWT.SINGLE | SWT.BORDER);
155: gd = new GridData(GridData.FILL_HORIZONTAL);
156: gd.horizontalSpan = 2;
157: fNameText.setLayoutData(gd);
158: fNameText.addModifyListener(new ModifyListener() {
159: public void modifyText(ModifyEvent e) {
160: validatePage();
161: }
162: });
163: if (isPluginIdNeeded() && !isPluginIdFinal()) {
164: label = new Label(container, SWT.NONE);
165: label
166: .setText(PDEUIMessages.BaseExtensionPoint_schemaLocation);
167: fSchemaLocationText = new Text(container, SWT.SINGLE
168: | SWT.BORDER);
169: gd = new GridData(GridData.FILL_HORIZONTAL);
170: gd.widthHint = 150;
171: gd.grabExcessHorizontalSpace = true;
172: fSchemaLocationText.setLayoutData(gd);
173: fSchemaLocationText.addModifyListener(new ModifyListener() {
174: public void modifyText(ModifyEvent e) {
175: validatePage();
176: }
177: });
178: fFindLocationButton = new Button(container, SWT.PUSH);
179: gd = new GridData(GridData.HORIZONTAL_ALIGN_END);
180: gd.widthHint = 50;
181: fFindLocationButton.setLayoutData(gd);
182: fFindLocationButton
183: .setText(PDEUIMessages.BaseExtensionPointMainPage_findBrowse);
184: fFindLocationButton
185: .setToolTipText(PDEUIMessages.BaseExtensionPointMainPage_schemaLocation_tooltip);
186: fFindLocationButton
187: .addSelectionListener(new SelectionAdapter() {
188: public void widgetSelected(SelectionEvent e) {
189: handleSchemaLocation();
190: }
191: });
192: SWTUtil.setButtonDimensionHint(fFindLocationButton);
193: }
194: label = new Label(container, SWT.NONE);
195: label.setText(PDEUIMessages.BaseExtensionPoint_schema);
196: fSchemaText = new Text(container, SWT.SINGLE | SWT.BORDER);
197: gd = new GridData(GridData.FILL_HORIZONTAL);
198: gd.horizontalSpan = 2;
199: fSchemaText.setLayoutData(gd);
200: fSchemaText.addModifyListener(new ModifyListener() {
201: public void modifyText(ModifyEvent e) {
202: validatePage();
203: }
204: });
205: if (isSharedSchemaSwitchNeeded()) {
206: fSharedSchemaButton = new Button(container, SWT.CHECK);
207: fSharedSchemaButton
208: .setText(PDEUIMessages.BaseExtensionPoint_shared);
209: gd = new GridData(GridData.FILL_HORIZONTAL);
210: gd.horizontalSpan = 2;
211: fSharedSchemaButton.setLayoutData(gd);
212: }
213: fOpenSchemaButton = new Button(container, SWT.CHECK);
214: fOpenSchemaButton
215: .setText(PDEUIMessages.BaseExtensionPoint_edit);
216: fOpenSchemaButton.setSelection(true);
217: gd = new GridData(GridData.FILL_HORIZONTAL);
218: gd.horizontalSpan = 2;
219: fOpenSchemaButton.setLayoutData(gd);
220: if (isPluginIdNeeded())
221: fPluginIdText.setFocus();
222: else
223: fIdText.setFocus();
224: setControl(container);
225: initializeValues();
226: validatePage();
227: // do not start with an error message, convert to regular message
228: String error = getErrorMessage();
229: if (error != null) {
230: setMessage(error);
231: setErrorMessage(null);
232: }
233: Dialog.applyDialogFont(container);
234: PlatformUI.getWorkbench().getHelpSystem().setHelp(container,
235: IHelpContextIds.NEW_SCHEMA);
236: }
237:
238: private InputStream createSchemaStream(String pluginId,
239: String pointId, String name, boolean shared) {
240: if (name.length() == 0)
241: name = pointId;
242: EditableSchema schema = new EditableSchema(pluginId, pointId,
243: name, false);
244: schema
245: .setDescription(PDEUIMessages.BaseExtensionPoint_sections_overview);
246: DocumentSection section;
247: section = new DocumentSection(schema, IDocumentSection.SINCE,
248: PDEUIMessages.BaseExtensionPointMainPage_since);
249: section
250: .setDescription(PDEUIMessages.BaseExtensionPoint_sections_since);
251: schema.addDocumentSection(section);
252: SchemaElement element;
253: if (!shared) {
254: element = new SchemaRootElement(schema, "extension"); //$NON-NLS-1$
255: SchemaComplexType complexType = new SchemaComplexType(
256: schema);
257: element.setType(complexType);
258: SchemaAttribute attribute = new SchemaAttribute(element,
259: "point"); //$NON-NLS-1$
260: attribute.setType(new SchemaSimpleType(schema, "string")); //$NON-NLS-1$
261: attribute.setUse(ISchemaAttribute.REQUIRED);
262: complexType.addAttribute(attribute);
263: attribute = new SchemaAttribute(element, "id"); //$NON-NLS-1$
264: attribute.setType(new SchemaSimpleType(schema, "string")); //$NON-NLS-1$
265: complexType.addAttribute(attribute);
266: attribute = new SchemaAttribute(element, "name"); //$NON-NLS-1$
267: attribute.setType(new SchemaSimpleType(schema, "string")); //$NON-NLS-1$
268: attribute.setTranslatableProperty(true);
269: complexType.addAttribute(attribute);
270: schema.addElement(element);
271: }
272: section = new DocumentSection(schema,
273: IDocumentSection.EXAMPLES, "Examples"); //$NON-NLS-1$
274: section
275: .setDescription(PDEUIMessages.BaseExtensionPoint_sections_usage);
276: schema.addDocumentSection(section);
277: section = new DocumentSection(schema,
278: IDocumentSection.API_INFO, "API Information"); //$NON-NLS-1$
279: section
280: .setDescription(PDEUIMessages.BaseExtensionPoint_sections_api);
281: schema.addDocumentSection(section);
282: section = new DocumentSection(schema,
283: IDocumentSection.IMPLEMENTATION,
284: "Supplied Implementation"); //$NON-NLS-1$
285: section
286: .setDescription(PDEUIMessages.BaseExtensionPoint_sections_supplied);
287: schema.addDocumentSection(section);
288: section = new DocumentSection(schema,
289: IDocumentSection.COPYRIGHT, "Copyright"); //$NON-NLS-1$
290: section
291: .setDescription(PDEUIMessages.BaseExtensionPoint_sections_copyright);
292: schema.addDocumentSection(section);
293: StringWriter swriter = new StringWriter();
294: try {
295: PrintWriter writer = new PrintWriter(swriter, true);
296: schema.save(writer);
297: swriter.close();
298: } catch (IOException e) {
299: PDEPlugin.logException(e);
300: }
301: try {
302: return new ByteArrayInputStream(swriter.toString()
303: .getBytes("UTF8")); //$NON-NLS-1$
304: } catch (UnsupportedEncodingException e) {
305: return new ByteArrayInputStream(new byte[0]);
306: }
307: }
308:
309: private IFile generateSchemaFile(String pluginId, String id,
310: String name, boolean shared, String schema,
311: IProgressMonitor monitor) throws CoreException {
312: IFile schemaFile = null;
313:
314: IWorkspace workspace = fContainer.getWorkspace();
315: IPath schemaPath = new Path(schema).removeLastSegments(1);
316: IPath newSchemaPath = fContainer.getProjectRelativePath()
317: .append(schemaPath);
318: monitor.subTask(PDEUIMessages.BaseExtensionPoint_generating);
319: if (newSchemaPath.isEmpty() == false) {
320: IFolder folder = fContainer.getProject().getFolder(
321: newSchemaPath);
322: CoreUtility.createFolder(folder);
323: }
324: InputStream source = createSchemaStream(pluginId, id, name,
325: shared);
326: IPath filePath = fContainer.getFullPath().append(schema);
327: schemaFile = workspace.getRoot().getFile(filePath);
328: if (!schemaFile.exists()) {
329: // create for the first time
330: schemaFile.create(source, true, monitor);
331: } else {
332: schemaFile.setContents(source, true, false, monitor);
333: }
334: IDE.setDefaultEditor(schemaFile,
335: IPDEUIConstants.SCHEMA_EDITOR_ID);
336: return schemaFile;
337: }
338:
339: public IRunnableWithProgress getOperation() {
340: final boolean openFile = fOpenSchemaButton.getSelection();
341: final String id = fIdText.getText();
342: final String name = fNameText.getText();
343: final String schema = fSchemaText.getText();
344: final boolean shared = fSharedSchemaButton != null ? fSharedSchemaButton
345: .getSelection()
346: : false;
347: IRunnableWithProgress operation = new WorkspaceModifyOperation() {
348: public void execute(final IProgressMonitor monitor) {
349: try {
350: Display.getDefault().asyncExec(new Runnable() {
351:
352: public void run() {
353: String schemaName = schema;
354: if (!schema.endsWith(".exsd")) //$NON-NLS-1$
355: schemaName = schema + ".exsd"; //$NON-NLS-1$
356:
357: IFile file = fContainer.getFile(new Path(
358: schema));
359: // do not overwrite if schema already exists
360: if (!file.exists())
361: try {
362: file = generateSchemaFile(
363: getPluginId(), id, name,
364: shared, schemaName, monitor);
365: } catch (CoreException e) {
366: PDEPlugin.logException(e);
367: }
368:
369: if (file != null && openFile) {
370: fSchemaText.setText(file
371: .getProjectRelativePath()
372: .toString());
373: openSchemaFile(file);
374: }
375: }
376:
377: });
378:
379: } finally {
380: monitor.done();
381: }
382: }
383: };
384: return operation;
385: }
386:
387: public String getSchemaLocation() {
388: if (fSchemaText != null) {
389: String schema = fSchemaText.getText();
390: if (schema.length() == 0) {
391: if (fSchemaLocationText != null
392: && SCHEMA_DIR.equals(new Path(
393: fSchemaLocationText.getText())
394: .lastSegment())) {
395: return ""; //$NON-NLS-1$
396: }
397: return SCHEMA_DIR;
398: }
399:
400: int loc = schema.lastIndexOf("/"); //$NON-NLS-1$
401: if (loc != -1)
402: return schema.substring(0, loc);
403: }
404: return ""; //$NON-NLS-1$
405: }
406:
407: public String getPluginId() {
408: if (fPluginIdText != null) {
409: return fPluginIdText.getText();
410: }
411: return ""; //$NON-NLS-1$
412: }
413:
414: protected boolean isPluginIdNeeded() {
415: return false;
416: }
417:
418: protected boolean isPluginIdFinal() {
419: return false;
420: }
421:
422: protected boolean isSharedSchemaSwitchNeeded() {
423: return false;
424: }
425:
426: private void openSchemaFile(final IFile file) {
427: final IWorkbenchWindow ww = PDEPlugin
428: .getActiveWorkbenchWindow();
429: Display d = ww.getShell().getDisplay();
430: d.asyncExec(new Runnable() {
431: public void run() {
432: try {
433: String editorId = IPDEUIConstants.SCHEMA_EDITOR_ID;
434: ww.getActivePage().openEditor(
435: new FileEditorInput(file), editorId);
436: } catch (PartInitException e) {
437: PDEPlugin.logException(e);
438: }
439: }
440: });
441: }
442:
443: private void validatePage() {
444: // clear opening message
445: setMessage(null);
446: String message = validateFieldContents();
447: setErrorMessage(message);
448: setPageComplete(message == null);
449: }
450:
451: protected abstract String validateFieldContents();
452:
453: protected abstract void initializeValues();
454:
455: protected String validateExtensionPointID() {
456:
457: // Verify not zero length
458: String id = fIdText.getText();
459: if (id.length() == 0)
460: return PDEUIMessages.BaseExtensionPointMainPage_missingExtensionPointID;
461:
462: // For 3.2 or greater plug-ins verify that it is a valid composite ID
463: // and that it has a valid namespace
464: // For 3.1 and lower plug-ins verify that it is a valid simple ID
465: String pluginID = getPluginId();
466: IPluginModelBase model = PluginRegistry.findModel(pluginID);
467: // Verify that the plugin was found
468: if (model == null) {
469: return NLS
470: .bind(
471: PDEUIMessages.BaseExtensionPointMainPage_errorMsgPluginNotFound,
472: pluginID);
473: }
474:
475: String schemaVersion = model.getPluginBase().getSchemaVersion();
476: if (schemaVersion == null
477: || Float.parseFloat(schemaVersion) >= 3.2) {
478: if (!IdUtil.isValidCompositeID(id))
479: return PDEUIMessages.BaseExtensionPointMainPage_invalidCompositeID;
480:
481: } else if (!IdUtil.isValidSimpleID(id))
482: return PDEUIMessages.BaseExtensionPointMainPage_invalidSimpleID;
483:
484: return null;
485: }
486:
487: protected String validateExtensionPointName() {
488: // Verify not zero length
489: if (fNameText.getText().length() == 0)
490: return PDEUIMessages.BaseExtensionPointMainPage_missingExtensionPointName;
491:
492: return null;
493: }
494:
495: protected String validateExtensionPointSchema() {
496: // Verify not zero length
497: if (fSchemaText.getText().length() == 0)
498: return PDEUIMessages.BaseExtensionPointMainPage_missingExtensionPointSchema;
499:
500: return null;
501: }
502:
503: private void handlePluginBrowse() {
504: PluginSelectionDialog dialog = new PluginSelectionDialog(
505: getShell(), PluginRegistry.getWorkspaceModels(), false);
506: dialog.create();
507: if (dialog.open() == Window.OK) {
508: IPluginModelBase workspaceModelBase = (IPluginModelBase) dialog
509: .getFirstResult();
510: fPluginIdText.setText(workspaceModelBase.getPluginBase()
511: .getId());
512: }
513: }
514:
515: private void handleSchemaLocation() {
516: ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(
517: getShell(), new WorkbenchLabelProvider(),
518: new WorkbenchContentProvider());
519: dialog
520: .setTitle(PDEUIMessages.BaseExtensionPointMainPage_schemaLocation_title);
521: dialog
522: .setMessage(PDEUIMessages.BaseExtensionPointMainPage_schemaLocation_desc);
523: dialog.setDoubleClickSelects(false);
524: dialog.setAllowMultiple(false);
525: dialog.addFilter(new ViewerFilter() {
526: public boolean select(Viewer viewer, Object parentElement,
527: Object element) {
528: if (element instanceof IFile)
529: return false;
530: return true;
531: }
532: });
533:
534: dialog.setInput(PDEPlugin.getWorkspace().getRoot());
535: dialog.setComparator(new ResourceComparator(
536: ResourceComparator.NAME));
537: dialog.setInitialSelection(fContainer);
538: if (dialog.open() == Window.OK) {
539: Object[] elements = dialog.getResult();
540: if (elements.length > 0) {
541: IResource elem = (IResource) elements[0];
542: String newPath = getWorkspaceRelativePath(elem
543: .getLocation().toString());
544: fSchemaLocationText.setText(newPath + "/"); //$NON-NLS-1$
545: }
546: }
547: }
548:
549: private String getWorkspaceRelativePath(String path) {
550: String workspacePath = PDECore.getWorkspace().getRoot()
551: .getLocation().toString();
552: if (path.startsWith(workspacePath))
553: path = path.replaceFirst(workspacePath, ""); //$NON-NLS-1$
554: return path;
555: }
556:
557: public String getInvalidIdMessage() {
558: // No validation done (other than making sure id is not blank)
559: return null;
560: }
561:
562: }
|