001: /*******************************************************************************
002: * Copyright (c) 2006, 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.cheatsheet;
011:
012: import java.util.ArrayList;
013:
014: import org.eclipse.core.resources.IProject;
015: import org.eclipse.jface.dialogs.Dialog;
016: import org.eclipse.jface.window.Window;
017: import org.eclipse.jface.wizard.WizardPage;
018: import org.eclipse.pde.core.IModel;
019: import org.eclipse.pde.core.plugin.IPluginAttribute;
020: import org.eclipse.pde.core.plugin.IPluginElement;
021: import org.eclipse.pde.core.plugin.IPluginExtension;
022: import org.eclipse.pde.core.plugin.IPluginModelBase;
023: import org.eclipse.pde.core.plugin.IPluginObject;
024: import org.eclipse.pde.core.plugin.ISharedExtensionsModel;
025: import org.eclipse.pde.core.plugin.PluginRegistry;
026: import org.eclipse.pde.internal.core.ibundle.IBundlePluginModelBase;
027: import org.eclipse.pde.internal.core.icheatsheet.comp.ICompCSConstants;
028: import org.eclipse.pde.internal.core.util.PDETextHelper;
029: import org.eclipse.pde.internal.ui.IHelpContextIds;
030: import org.eclipse.pde.internal.ui.PDEPlugin;
031: import org.eclipse.pde.internal.ui.PDEUIMessages;
032: import org.eclipse.pde.internal.ui.util.SWTUtil;
033: import org.eclipse.swt.SWT;
034: import org.eclipse.swt.events.ModifyEvent;
035: import org.eclipse.swt.events.ModifyListener;
036: import org.eclipse.swt.events.SelectionAdapter;
037: import org.eclipse.swt.events.SelectionEvent;
038: import org.eclipse.swt.layout.GridData;
039: import org.eclipse.swt.layout.GridLayout;
040: import org.eclipse.swt.widgets.Button;
041: import org.eclipse.swt.widgets.Combo;
042: import org.eclipse.swt.widgets.Composite;
043: import org.eclipse.swt.widgets.Group;
044: import org.eclipse.swt.widgets.Label;
045: import org.eclipse.swt.widgets.Text;
046: import org.eclipse.ui.PlatformUI;
047:
048: /**
049: * RegisterCSWizardPage
050: *
051: */
052: public abstract class RegisterCSWizardPage extends WizardPage implements
053: IRegisterCSData {
054:
055: public final static String F_PAGE_NAME = "register-cs"; //$NON-NLS-1$
056:
057: public final static String F_CS_ELEMENT_CATEGORY = "category"; //$NON-NLS-1$
058:
059: public final static String F_CS_ELEMENT_CHEATSHEET = "cheatsheet"; //$NON-NLS-1$
060:
061: public final static String F_CS_ELEMENT_DESCRIPTION = "description"; //$NON-NLS-1$
062:
063: private final static String F_LOCALE_VARIABLE = "$nl$/"; //$NON-NLS-1$
064:
065: private Combo fCategoryCombo;
066:
067: private Button fCategoryButton;
068:
069: private Text fDescriptionText;
070:
071: protected IModel fCheatSheetModel;
072:
073: private ISharedExtensionsModel fExtensionsModel;
074:
075: private IProject fPluginProject;
076:
077: private String fDataCategoryName;
078:
079: private String fDataDescription;
080:
081: private String fDataCheatSheetID;
082:
083: private CSCategoryTrackerUtil fCategoryTrackerUtil;
084:
085: /**
086: * @param pageName
087: */
088: public RegisterCSWizardPage(IModel model) {
089: super (F_PAGE_NAME);
090:
091: fCheatSheetModel = model;
092: initialize();
093: }
094:
095: /**
096: *
097: */
098: private void initialize() {
099:
100: setTitle(PDEUIMessages.CheatSheetFileWizardPage_1);
101: setDescription(PDEUIMessages.RegisterCSWizardPage_wizardPageDescription);
102:
103: fCategoryCombo = null;
104: fCategoryButton = null;
105: fDescriptionText = null;
106:
107: fCategoryTrackerUtil = new CSCategoryTrackerUtil();
108:
109: fDataCategoryName = null;
110: fDataDescription = null;
111:
112: // Get the project the cheat sheet is stored in
113: fPluginProject = fCheatSheetModel.getUnderlyingResource()
114: .getProject();
115:
116: fDataCheatSheetID = generateCheatSheetID();
117:
118: initializePluginModel();
119: }
120:
121: /**
122: *
123: */
124: private void initializePluginModel() {
125: IPluginModelBase base = PluginRegistry
126: .findModel(getPluginProject());
127: // should never happen
128: if (base == null)
129: return;
130: if (base instanceof IBundlePluginModelBase)
131: fExtensionsModel = ((IBundlePluginModelBase) base)
132: .getExtensionsModel();
133: else
134: fExtensionsModel = base;
135: }
136:
137: /* (non-Javadoc)
138: * @see org.eclipse.pde.internal.ui.wizards.cheatsheet.IRegisterCSData#getDataDescription()
139: */
140: public String getDataDescription() {
141: return fDataDescription;
142: }
143:
144: /* (non-Javadoc)
145: * @see org.eclipse.pde.internal.ui.wizards.cheatsheet.IRegisterCSData#getDataCategoryName()
146: */
147: public String getDataCategoryName() {
148: return fDataCategoryName;
149: }
150:
151: /* (non-Javadoc)
152: * @see org.eclipse.pde.internal.ui.wizards.cheatsheet.IRegisterCSData#getDataCategoryType()
153: */
154: public int getDataCategoryType() {
155: String categoryID = getDataCategoryID();
156: if (categoryID == null) {
157: return CSCategoryTrackerUtil.F_TYPE_NO_CATEGORY;
158: }
159: return fCategoryTrackerUtil.getCategoryType(categoryID);
160: }
161:
162: /* (non-Javadoc)
163: * @see org.eclipse.pde.internal.ui.wizards.cheatsheet.IRegisterCSData#getDataCategoryID()
164: */
165: public String getDataCategoryID() {
166: if (fDataCategoryName != null) {
167: return fCategoryTrackerUtil
168: .getCategoryID(fDataCategoryName);
169: }
170: return null;
171: }
172:
173: /* (non-Javadoc)
174: * @see org.eclipse.pde.internal.ui.wizards.cheatsheet.IRegisterCSData#getDataContentFile()
175: */
176: public String getDataContentFile() {
177: // Retrieve the project relative path to the cheat sheet
178: String portablePath = fCheatSheetModel.getUnderlyingResource()
179: .getProjectRelativePath().toPortableString();
180: // Prepend the locale specific variable
181: return F_LOCALE_VARIABLE + portablePath;
182: }
183:
184: /* (non-Javadoc)
185: * @see org.eclipse.pde.internal.ui.wizards.cheatsheet.IRegisterCSData#getDataCheatSheetID()
186: */
187: public String getDataCheatSheetID() {
188: return fDataCheatSheetID;
189: }
190:
191: /* (non-Javadoc)
192: * @see org.eclipse.pde.internal.ui.wizards.cheatsheet.IRegisterCSData#getPluginProject()
193: */
194: public IProject getPluginProject() {
195: return fPluginProject;
196: }
197:
198: /**
199: * @return
200: */
201: public abstract String getDataCheatSheetName();
202:
203: /**
204: * @return
205: */
206: public abstract boolean isCompositeCheatSheet();
207:
208: /* (non-Javadoc)
209: * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
210: */
211: public void createControl(Composite parent) {
212:
213: createUI(parent);
214: createUIListeners();
215:
216: updateUI();
217: validateUI();
218:
219: }
220:
221: /**
222: * @param parent
223: */
224: private void createUI(Composite parent) {
225: // Create the container
226: Composite container = createUIContainer(parent);
227: // Create the label
228: createUILabel(container);
229: // Create the group
230: Group group = createUIGroup(container);
231: // Create the category field
232: createUICategoryField(group);
233: // Create the description field
234: createUIDescriptionField(group);
235: // Set the control for the reciever
236: // Must be done otherwise a null assertion error is generated
237: setControl(container);
238: // Apply the dialog font to all controls using the default font
239: Dialog.applyDialogFont(container);
240:
241: // Provide functionality for the help button
242: PlatformUI.getWorkbench().getHelpSystem().setHelp(container,
243: IHelpContextIds.REGISTER_CS);
244: }
245:
246: /**
247: * @param container
248: */
249: private void createUILabel(Composite container) {
250: Label label = new Label(container, SWT.WRAP);
251: label
252: .setText(PDEUIMessages.RegisterCSWizardPage_labelInstructionText);
253: GridData data = new GridData(GridData.FILL_HORIZONTAL);
254: data.widthHint = 300;
255: label.setLayoutData(data);
256: }
257:
258: /**
259: * @param container
260: * @return
261: */
262: private Group createUIGroup(Composite container) {
263: Group group = new Group(container, SWT.NONE);
264: GridLayout layout = new GridLayout(3, false);
265: layout.marginWidth = 6;
266: layout.marginHeight = 6;
267: group.setLayout(layout);
268: GridData data = new GridData(GridData.FILL_HORIZONTAL);
269: data.horizontalSpan = 3;
270: data.verticalIndent = 10;
271: group.setLayoutData(data);
272: group
273: .setText(PDEUIMessages.RegisterCSWizardPage_groupRegistration);
274: return group;
275: }
276:
277: /**
278: * @param parent
279: * @return
280: */
281: private Composite createUIContainer(Composite parent) {
282: Composite container = new Composite(parent, SWT.NONE);
283: GridLayout layout = new GridLayout();
284: layout.numColumns = 3;
285: container.setLayout(layout);
286: return container;
287: }
288:
289: /**
290: * @param parent
291: */
292: private void createUICategoryField(Composite parent) {
293: // Create the label
294: createUICategoryLabel(parent);
295: // Create the combo
296: createUICategoryCombo(parent);
297: // Create the button
298: createUICategoryButton(parent);
299: }
300:
301: /**
302: * @param parent
303: */
304: private void createUICategoryLabel(Composite parent) {
305: Label label = new Label(parent, SWT.NONE);
306: label.setText(PDEUIMessages.RegisterCSWizardPage_labelCategory);
307: }
308:
309: /**
310: * @param parent
311: */
312: private void createUICategoryCombo(Composite parent) {
313: int style = SWT.READ_ONLY | SWT.BORDER;
314: fCategoryCombo = new Combo(parent, style);
315: GridData data = new GridData(GridData.FILL_HORIZONTAL);
316: fCategoryCombo.setLayoutData(data);
317: fCategoryCombo.add(PDEUIMessages.SimpleCSCommandDetails_6);
318: fCategoryCombo.setText(PDEUIMessages.SimpleCSCommandDetails_6);
319: }
320:
321: /**
322: * @param parent
323: */
324: private void createUICategoryButton(Composite parent) {
325: fCategoryButton = new Button(parent, SWT.PUSH);
326: GridData data = new GridData(GridData.HORIZONTAL_ALIGN_END);
327: data.widthHint = 50;
328: fCategoryButton.setLayoutData(data);
329: fCategoryButton
330: .setText(PDEUIMessages.RegisterCSWizardPage_buttonNew);
331: fCategoryButton
332: .setToolTipText(PDEUIMessages.RegisterCSWizardPage_toolTipNewCategory);
333: SWTUtil.setButtonDimensionHint(fCategoryButton);
334: }
335:
336: /**
337: * @param parent
338: */
339: private void createUIDescriptionField(Composite parent) {
340: // Create the label
341: createUIDescriptionLabel(parent);
342: // Create the text widget
343: createUIDescriptionText(parent);
344: }
345:
346: /**
347: * @param parent
348: */
349: private void createUIDescriptionLabel(Composite parent) {
350: Label label = new Label(parent, SWT.NONE);
351: label
352: .setText(PDEUIMessages.RegisterCSWizardPage_labelDescription);
353: int style = GridData.VERTICAL_ALIGN_BEGINNING
354: | GridData.HORIZONTAL_ALIGN_END;
355: GridData data = new GridData(style);
356: label.setLayoutData(data);
357: }
358:
359: /**
360: * @param parent
361: */
362: private void createUIDescriptionText(Composite parent) {
363: int style = SWT.MULTI | SWT.WRAP | SWT.V_SCROLL | SWT.BORDER;
364: fDescriptionText = new Text(parent, style);
365: GridData data = new GridData(GridData.FILL_HORIZONTAL);
366: data.heightHint = 60;
367: data.horizontalSpan = 2;
368: fDescriptionText.setLayoutData(data);
369: }
370:
371: /**
372: *
373: */
374: private void createUIListeners() {
375: // Create listeners for the category button
376: createUIListenersCategoryButton();
377: // Create listeners for the category combo box
378: createUIListenersCategoryCombo();
379: // Create listeners for the description text
380: createUIListenersDescriptionText();
381: }
382:
383: /**
384: *
385: */
386: private void createUIListenersCategoryButton() {
387: fCategoryButton.addSelectionListener(new SelectionAdapter() {
388: public void widgetSelected(SelectionEvent e) {
389: handleWidgetSelectedCategoryButton();
390: }
391: });
392: }
393:
394: /**
395: *
396: */
397: private void createUIListenersCategoryCombo() {
398: fCategoryCombo.addModifyListener(new ModifyListener() {
399: public void modifyText(ModifyEvent e) {
400: fDataCategoryName = fCategoryCombo.getText();
401: }
402: });
403: }
404:
405: /**
406: *
407: */
408: private void createUIListenersDescriptionText() {
409: fDescriptionText.addModifyListener(new ModifyListener() {
410: public void modifyText(ModifyEvent e) {
411: fDataDescription = fDescriptionText.getText();
412: }
413: });
414: }
415:
416: /**
417: *
418: */
419: private void handleWidgetSelectedCategoryButton() {
420: // Create a dialog allowing the user to input the category name
421: NewCategoryNameDialog dialog = new NewCategoryNameDialog(
422: PDEPlugin.getActiveWorkbenchShell());
423: dialog.create();
424: dialog
425: .getShell()
426: .setText(
427: PDEUIMessages.RegisterCSWizardPage_dialogTitleNewCategory);
428:
429: if (dialog.open() == Window.OK) {
430: String newCategoryName = dialog.getNameText();
431:
432: if (PDETextHelper.isDefinedAfterTrim(newCategoryName)) {
433: String trimmedText = newCategoryName.trim();
434: fCategoryCombo.add(trimmedText);
435: fCategoryCombo.setText(trimmedText);
436: fCategoryCombo.setFocus();
437: String id = generateCategoryID(trimmedText);
438: fCategoryTrackerUtil.associate(id, trimmedText,
439: CSCategoryTrackerUtil.F_TYPE_NEW_CATEGORY);
440: }
441: }
442:
443: }
444:
445: /**
446: *
447: */
448: private void updateUI() {
449:
450: if (fExtensionsModel != null) {
451: // Find all cheat sheet extensions within the host plug-in
452: IPluginExtension[] extensions = RegisterCSOperation
453: .findCheatSheetExtensions(fExtensionsModel);
454: // Process all category elements
455: processCategoryElements(extensions);
456: // Process all cheat sheet elements
457: processCheatSheetElements(extensions);
458: }
459: }
460:
461: /**
462: * @param extensions
463: */
464: private void processCategoryElements(IPluginExtension[] extensions) {
465: // Linear search: Process all cheat sheet extensions found
466: for (int i = 0; i < extensions.length; i++) {
467: if (extensions[i].getChildCount() == 0) {
468: // Extension has no children, skip to the next extension
469: continue;
470: }
471: IPluginExtension extension = extensions[i];
472: IPluginObject[] pluginObjects = extension.getChildren();
473: // Process all children
474: for (int j = 0; j < pluginObjects.length; j++) {
475: if (pluginObjects[j] instanceof IPluginElement) {
476: IPluginElement element = (IPluginElement) pluginObjects[j];
477: if (element.getName().equals(F_CS_ELEMENT_CATEGORY)) {
478: // Category element
479: // Update the category combo
480: updateUICategoryComboElement(element);
481: }
482: }
483: }
484: }
485: }
486:
487: /**
488: * @param extensions
489: */
490: private void processCheatSheetElements(IPluginExtension[] extensions) {
491: // Query cheat sheet extensions for information required to update
492: // the description text and category combo widgets
493: // Linear search: Process all cheat sheet extensions found
494: for (int i = 0; i < extensions.length; i++) {
495: if (extensions[i].getChildCount() == 0) {
496: // Extension has no children, skip to the next extension
497: continue;
498: }
499: IPluginExtension extension = extensions[i];
500: IPluginObject[] pluginObjects = extension.getChildren();
501: // Process all children
502: for (int j = 0; j < pluginObjects.length; j++) {
503: if (pluginObjects[j] instanceof IPluginElement) {
504: IPluginElement element = (IPluginElement) pluginObjects[j];
505: if (element.getName().equals(
506: F_CS_ELEMENT_CHEATSHEET)) {
507: // Cheat sheet element
508: processCheatSheetElement(element,
509: fDataCheatSheetID);
510: }
511:
512: }
513: }
514: }
515: }
516:
517: /**
518: * Process category elements
519: * @param parentElement
520: */
521: private void updateUICategoryComboElement(
522: IPluginElement parentElement) {
523: // Get the id attribute
524: IPluginAttribute idAttribute = parentElement
525: .getAttribute(ICompCSConstants.ATTRIBUTE_ID);
526: // Get the name attribute
527: IPluginAttribute nameAttribute = parentElement
528: .getAttribute(ICompCSConstants.ATTRIBUTE_NAME);
529: // Add the category to the combo box only if
530: // (1) the category name is defined
531: // (2) the category has not already been added to the combo box
532: if ((nameAttribute != null)
533: && PDETextHelper.isDefined(nameAttribute.getValue())
534: && (idAttribute != null)
535: && PDETextHelper.isDefined(idAttribute.getValue())
536: && (fCategoryTrackerUtil
537: .containsCategoryName(nameAttribute.getValue()) == false)) {
538: // TODO: MP: LOW: CompCS: Reference translated value
539: fCategoryCombo.add(nameAttribute.getValue());
540: // Assocate the category ID with the category name
541: fCategoryTrackerUtil.associate(idAttribute.getValue(),
542: nameAttribute.getValue(),
543: CSCategoryTrackerUtil.F_TYPE_OLD_CATEGORY);
544: }
545: }
546:
547: /**
548: * Process cheatsheet elements with a category attribute
549: * @param parentElement
550: */
551: private void updateUICategoryComboAttribute(IPluginElement element) {
552: // Get the category attribute
553: IPluginAttribute categoryAttribute = element
554: .getAttribute(F_CS_ELEMENT_CATEGORY);
555: // Process the category attribute
556: if ((categoryAttribute != null)
557: && PDETextHelper
558: .isDefined(categoryAttribute.getValue())) {
559: String id = categoryAttribute.getValue();
560: // Check to see if the category ID has been defined
561: if (fCategoryTrackerUtil.containsCategoryID(id)) {
562: // Update the category combo selection
563: String name = fCategoryTrackerUtil.getCategoryName(id);
564: fCategoryCombo.setText(name);
565: } else {
566: // Add the category ID to the combo box (no assoicated name)
567: // This can only happen if the category is defined outside of
568: // the plug-in the cheat sheet is stored in
569: fCategoryCombo.add(id);
570: fCategoryCombo.setText(id);
571: fCategoryTrackerUtil.associate(id, id,
572: CSCategoryTrackerUtil.F_TYPE_OLD_CATEGORY);
573: }
574: }
575: }
576:
577: /**
578: * @param extensions
579: */
580: private void processCheatSheetElement(IPluginElement parentElement,
581: String generatedID) {
582: // Get the id attribute
583: IPluginAttribute idAttribute = parentElement
584: .getAttribute(ICompCSConstants.ATTRIBUTE_ID);
585:
586: // Check for the generated ID for this cheat sheet
587: // If a cheat sheet exists with the generated ID already, read its
588: // description and populate the description text accordingly
589: if ((idAttribute != null)
590: && PDETextHelper.isDefined(idAttribute.getValue())
591: && generatedID.equals(idAttribute.getValue())) {
592: // Matching cheat sheet extension found
593: // Process children if any
594: if (parentElement.getChildCount() > 0) {
595: // Update the description text widget
596: updateUIDescriptionText(parentElement);
597: }
598: updateUICategoryComboAttribute(parentElement);
599: }
600: }
601:
602: /**
603: * @param parentElement
604: */
605: private void updateUIDescriptionText(IPluginElement parentElement) {
606: IPluginObject pluginObject = parentElement.getChildren()[0];
607: if (pluginObject instanceof IPluginElement) {
608: IPluginElement element = (IPluginElement) pluginObject;
609: if (element.getName().equals(F_CS_ELEMENT_DESCRIPTION)
610: && PDETextHelper.isDefinedAfterTrim(element
611: .getText())) {
612: // Triggers listener to update data description on load
613: fDescriptionText.setText(element.getText().trim());
614: }
615: }
616: }
617:
618: /**
619: *
620: */
621: private void validateUI() {
622: setPageComplete(true);
623: }
624:
625: /**
626: * @param model
627: * @param extensionPointID
628: * @return
629: */
630: public IPluginExtension[] findExtensions(
631: ISharedExtensionsModel model, String extensionPointID) {
632: IPluginExtension[] extensions = model.getExtensions()
633: .getExtensions();
634:
635: ArrayList csExtensions = new ArrayList();
636: for (int i = 0; i < extensions.length; i++) {
637: String point = extensions[i].getPoint();
638: if (extensionPointID.equals(point)) {
639: csExtensions.add(extensions[i]);
640: }
641: }
642: return (IPluginExtension[]) csExtensions
643: .toArray(new IPluginExtension[csExtensions.size()]);
644: }
645:
646: /**
647: * @return
648: */
649: private String generateCheatSheetID() {
650: // Generate the hash code using the full path
651: long uniqueID = hash(fCheatSheetModel.getUnderlyingResource()
652: .getFullPath().toPortableString());
653: // Qualify with the project name
654: // Append the hash code to make the name unique and allow cheat sheets
655: // with the same name (but different directories) be registered
656: // individually
657: String result = fPluginProject.getName() + '.'
658: + F_CS_ELEMENT_CHEATSHEET + uniqueID;
659: return result;
660: }
661:
662: /**
663: * @return
664: */
665: private String generateCategoryID(String name) {
666: // Generate the hash code using the category name
667: long uniqueID = hash(name);
668: // Qualify with the project name
669: // Append the hash code to make the name unique
670: String result = fPluginProject.getName() + '.'
671: + F_CS_ELEMENT_CATEGORY + uniqueID;
672: return result;
673: }
674:
675: /**
676: * @param string
677: * @return
678: */
679: private long hash(String string) {
680: int b = 378551;
681: int a = 63689;
682: long hash = 0;
683:
684: for (int i = 0; i < string.length(); i++) {
685: hash = hash * a + string.charAt(i);
686: a = a * b;
687: }
688: return (hash & 0x7FFFFFFF);
689: }
690:
691: }
|