1 /*******************************************************************************
2  * Copyright (c) 2009, 2016 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  *******************************************************************************/
12 
13 package org.eclipse.jdt.internal.ui.callhierarchy;
14 
15 import java.util.Arrays;
16 import java.util.List;
17 
18 import org.eclipse.swt.SWT;
19 import org.eclipse.swt.events.SelectionAdapter;
20 import org.eclipse.swt.events.SelectionEvent;
21 import org.eclipse.swt.graphics.Image;
22 import org.eclipse.swt.layout.GridData;
23 import org.eclipse.swt.layout.GridLayout;
24 import org.eclipse.swt.widgets.Button;
25 import org.eclipse.swt.widgets.Composite;
26 import org.eclipse.swt.widgets.Control;
27 import org.eclipse.swt.widgets.Shell;
28 import org.eclipse.swt.widgets.Text;
29 
30 import org.eclipse.core.runtime.Assert;
31 import org.eclipse.core.runtime.IStatus;
32 
33 import org.eclipse.jface.dialogs.Dialog;
34 import org.eclipse.jface.dialogs.StatusDialog;
35 import org.eclipse.jface.layout.PixelConverter;
36 import org.eclipse.jface.operation.IRunnableContext;
37 import org.eclipse.jface.viewers.LabelProvider;
38 import org.eclipse.jface.viewers.ViewerComparator;
39 import org.eclipse.jface.window.Window;
40 
41 import org.eclipse.ui.PlatformUI;
42 import org.eclipse.ui.dialogs.SelectionDialog;
43 import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
44 
45 import org.eclipse.jdt.core.IType;
46 import org.eclipse.jdt.core.JavaConventions;
47 import org.eclipse.jdt.core.JavaCore;
48 import org.eclipse.jdt.core.JavaModelException;
49 import org.eclipse.jdt.core.search.IJavaSearchScope;
50 import org.eclipse.jdt.core.search.SearchEngine;
51 
52 import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
53 
54 import org.eclipse.jdt.ui.IJavaElementSearchConstants;
55 import org.eclipse.jdt.ui.JavaUI;
56 import org.eclipse.jdt.ui.PreferenceConstants;
57 
58 import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
59 import org.eclipse.jdt.internal.ui.JavaPluginImages;
60 import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
61 import org.eclipse.jdt.internal.ui.dialogs.TextFieldNavigationHandler;
62 import org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock;
63 import org.eclipse.jdt.internal.ui.util.BusyIndicatorRunnableContext;
64 import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
65 import org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider;
66 import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener;
67 import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField;
68 import org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
69 import org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter;
70 import org.eclipse.jdt.internal.ui.wizards.dialogfields.IStringButtonAdapter;
71 import org.eclipse.jdt.internal.ui.wizards.dialogfields.LayoutUtil;
72 import org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField;
73 import org.eclipse.jdt.internal.ui.wizards.dialogfields.StringButtonDialogField;
74 
75 /**
76  * Call hierarchy expand with constructors configuration block.
77  *
78  * @since 3.6
79  */
80 public class ExpandWithConstructorsConfigurationBlock extends OptionsConfigurationBlock {
81 
82 	/**
83 	 * Call hierarchy expand with constructors dialog for types and members.
84 	 */
85 	private static class CallHierarchyTypesOrMembersDialog extends StatusDialog {
86 
87 		/**
88 		 * The change listener class for the dialog field and the string button dialog field.
89 		 *
90 		 */
91 		private class StringButtonAdapter implements IDialogFieldListener, IStringButtonAdapter {
92 			/*
93 			 * @see IDialogFieldListener#dialogFieldChanged(DialogField)
94 			 */
95 			@Override
dialogFieldChanged(DialogField field)96 			public void dialogFieldChanged(DialogField field) {
97 				doValidation();
98 			}
99 
100 			/*
101 			 * @see IStringButtonAdapter#changeControlPressed(DialogField)
102 			 */
103 			@Override
changeControlPressed(DialogField field)104 			public void changeControlPressed(DialogField field) {
105 				doBrowseTypes();
106 			}
107 		}
108 
109 		/**
110 		 * The name dialog field to hold the default expand with constructors list.
111 		 */
112 		private StringButtonDialogField fNameDialogField;
113 
114 		/**
115 		 * The list of previously existing entries.
116 		 */
117 		private List<String> fExistingEntries;
118 
119 		/**
120 		 * Tells whether it is an member or type.
121 		 */
122 		private final boolean fIsEditingMember;
123 
124 		/**
125 		 * Creates a call hierarchy preference dialog for members or types.
126 		 *
127 		 * @param parent the parent shell
128 		 * @param existingEntries the existing list of types and members
129 		 * @param isEditingMember <code>true</code if its a member, <code>false</code> otherwise
130 		 */
CallHierarchyTypesOrMembersDialog(Shell parent, List<String> existingEntries, boolean isEditingMember)131 		public CallHierarchyTypesOrMembersDialog(Shell parent, List<String> existingEntries, boolean isEditingMember) {
132 			super(parent);
133 			fIsEditingMember= isEditingMember;
134 			fExistingEntries= existingEntries;
135 
136 			String label, title;
137 			if (isEditingMember) {
138 				title= CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_member_title;
139 				label= CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_member_labelText;
140 			} else {
141 				title= CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_type_title;
142 				label= CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_type_labelText;
143 			}
144 			setTitle(title);
145 
146 			StringButtonAdapter adapter= new StringButtonAdapter();
147 
148 			fNameDialogField= new StringButtonDialogField(adapter);
149 			fNameDialogField.setLabelText(label);
150 			fNameDialogField.setButtonLabel(CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_browse_button);
151 			fNameDialogField.setDialogFieldListener(adapter);
152 			fNameDialogField.setText(""); //$NON-NLS-1$
153 		}
154 
155 		/*
156 		 * @see org.eclipse.jface.dialogs.Dialog#isResizable()		 *
157 		 */
158 		@Override
isResizable()159 		protected boolean isResizable() {
160 			return true;
161 		}
162 
163 		/**
164 		 * Sets the initial selection in the name dialog field.
165 		 *
166 		 * @param editedEntry the edited entry
167 		 */
setInitialSelection(String editedEntry)168 		public void setInitialSelection(String editedEntry) {
169 			Assert.isNotNull(editedEntry);
170 			if (editedEntry.length() == 0)
171 				fNameDialogField.setText(""); //$NON-NLS-1$
172 			else
173 				fNameDialogField.setText(editedEntry);
174 		}
175 
176 		/**
177 		 * Returns the resulting text from the name dialog field.
178 		 *
179 		 * @return the resulting text from the name dialog field
180 		 */
getResult()181 		public String getResult() {
182 			String val= fNameDialogField.getText();
183 			if (!fIsEditingMember)
184 				val= val + WILDCARD;
185 			return val;
186 		}
187 
188 		/*
189 		 * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
190 		 */
191 		@Override
createDialogArea(Composite parent)192 		protected Control createDialogArea(Composite parent) {
193 			Composite composite= (Composite)super.createDialogArea(parent);
194 			initializeDialogUnits(composite);
195 
196 			GridLayout layout= (GridLayout)composite.getLayout();
197 			layout.numColumns= 2;
198 
199 			fNameDialogField.doFillIntoGrid(composite, 3);
200 
201 			fNameDialogField.getChangeControl(null).setVisible(!fIsEditingMember);
202 
203 			LayoutUtil.setHorizontalSpan(fNameDialogField.getLabelControl(null), 2);
204 
205 			int fieldWidthHint= convertWidthInCharsToPixels(60);
206 			Text text= fNameDialogField.getTextControl(null);
207 			LayoutUtil.setWidthHint(text, fieldWidthHint);
208 			LayoutUtil.setHorizontalGrabbing(text);
209 			LayoutUtil.setHorizontalSpan(text, fIsEditingMember ? 2 : 1);
210 			TextFieldNavigationHandler.install(text);
211 
212 			DialogField.createEmptySpace(composite, 1);
213 
214 			fNameDialogField.postSetFocusOnDialogField(parent.getDisplay());
215 
216 			applyDialogFont(composite);
217 			return composite;
218 		}
219 
220 		/**
221 		 * Creates the type hierarchy for type selection.
222 		 */
doBrowseTypes()223 		private void doBrowseTypes() {
224 			IRunnableContext context= new BusyIndicatorRunnableContext();
225 			IJavaSearchScope scope= SearchEngine.createWorkspaceScope();
226 			int style= IJavaElementSearchConstants.CONSIDER_ALL_TYPES;
227 			try {
228 				SelectionDialog dialog= JavaUI.createTypeDialog(getShell(), context, scope, style, false, fNameDialogField.getText());
229 				dialog.setTitle(CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_ChooseTypeDialog_title);
230 				dialog.setMessage(CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_ChooseTypeDialog_description);
231 				if (dialog.open() == Window.OK) {
232 					IType res= (IType)dialog.getResult()[0];
233 					fNameDialogField.setText(res.getFullyQualifiedName('.'));
234 				}
235 			} catch (JavaModelException e) {
236 				ExceptionHandler.handle(e, getShell(), CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_ChooseTypeDialog_title,
237 						CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_ChooseTypeDialog_error_message);
238 			}
239 		}
240 
241 		/**
242 		 * Validates the entered type or member and updates the status.
243 		 */
doValidation()244 		private void doValidation() {
245 			StatusInfo status= new StatusInfo();
246 			String newText= fNameDialogField.getText();
247 			if (newText.length() == 0) {
248 				status.setError(""); //$NON-NLS-1$
249 			} else {
250 				IStatus val= JavaConventions.validateJavaTypeName(newText, JavaCore.VERSION_1_3, JavaCore.VERSION_1_3, null);
251 				if (val.matches(IStatus.ERROR)) {
252 					if (fIsEditingMember)
253 						status.setError(CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_error_invalidMemberName);
254 					else
255 						status.setError(CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_error_invalidTypeName);
256 				} else {
257 					if (doesExist(newText)) {
258 						status.setError(CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_error_entryExists);
259 					}
260 				}
261 			}
262 			updateStatus(status);
263 		}
264 
265 		/**
266 		 * Checks if the entry already exists.
267 		 *
268 		 * @param name the type or member name
269 		 * @return <code>true</code> if it already exists in the list of types and members,
270 		 *         <code>false</code> otherwise
271 		 */
doesExist(String name)272 		private boolean doesExist(String name) {
273 			return fExistingEntries.contains(name);
274 		}
275 
276 
277 		/*
278 		 * @see org.eclipse.jface.window.Window#configureShell(Shell)
279 		 */
280 		@Override
configureShell(Shell newShell)281 		protected void configureShell(Shell newShell) {
282 			super.configureShell(newShell);
283 			PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell, IJavaHelpContextIds.CALL_HIERARCHY_EXPAND_WITH_CONSTRUCTORS_DIALOG);
284 		}
285 
286 	}
287 
288 	/*
289 	 * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#performOk()
290 	 */
291 	@Override
performOk()292 	public boolean performOk() {
293 		setValue(ANONYMOUS_EXPAND_WITH_CONSTRUCTORS, fIsAnonymous);
294 		return super.performOk();
295 	}
296 
297 	/**
298 	 * The list label provider class.
299 	 */
300 	private static class ListLabelProvider extends LabelProvider {
301 
302 		public final Image MEMBER_ICON;
303 
304 		private final Image CLASS_ICON;
305 
306 		/**
307 		 * Create the member and class icons.
308 		 */
ListLabelProvider()309 		public ListLabelProvider() {
310 			MEMBER_ICON= JavaElementImageProvider.getDecoratedImage(JavaPluginImages.DESC_MISC_PUBLIC, 0, JavaElementImageProvider.SMALL_SIZE);
311 			CLASS_ICON= JavaElementImageProvider.getDecoratedImage(JavaPluginImages.DESC_OBJS_CLASS, 0, JavaElementImageProvider.SMALL_SIZE);
312 		}
313 
314 		/*
315 		 * @see org.eclipse.jface.viewers.LabelProvider#getImage(java.lang.Object)
316 		 */
317 		@Override
getImage(Object element)318 		public Image getImage(Object element) {
319 			return ((String)element).endsWith(WILDCARD) ? CLASS_ICON : MEMBER_ICON;
320 		}
321 
322 		/*
323 		 * @see org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object)
324 		 */
325 		@Override
getText(Object element)326 		public String getText(Object element) {
327 			return BasicElementLabels.getJavaElementName((String)element);
328 		}
329 	}
330 
331 
332 	/**
333 	 * The change listener for <code>ListDialogField</code>.
334 	 */
335 	private class ListAdapter implements IListAdapter<String>, IDialogFieldListener {
336 
337 		/**
338 		 * Checks if field can be edited.
339 		 *
340 		 * @param field the list dialog field
341 		 * @return <code>true</code> if it can be edited, <code>false</code> otherwise
342 		 */
canEdit(ListDialogField<String> field)343 		private boolean canEdit(ListDialogField<String> field) {
344 			List<String> selected= field.getSelectedElements();
345 			return selected.size() == 1;
346 		}
347 
348 		/*
349 		 * @see org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter#customButtonPressed(org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField, int)
350 		 */
351 		@Override
customButtonPressed(ListDialogField<String> field, int index)352 		public void customButtonPressed(ListDialogField<String> field, int index) {
353 			doButtonPressed(index);
354 		}
355 
356 		/*
357 		 * @see org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter#selectionChanged(org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField)
358 		 */
359 		@Override
selectionChanged(ListDialogField<String> field)360 		public void selectionChanged(ListDialogField<String> field) {
361 			fList.enableButton(IDX_EDIT, canEdit(field));
362 			fList.enableButton(IDX_REMOVE, canRemove(field));
363 		}
364 
365 		/**
366 		 * Checks if the field can be removed.
367 		 *
368 		 * @param field the list dialog field
369 		 * @return <code>true</code> if it can be removed, <code>false</code> otherwise
370 		 */
canRemove(ListDialogField<String> field)371 		private boolean canRemove(ListDialogField<String> field) {
372 			List<String> selected= field.getSelectedElements();
373 			return !selected.isEmpty();
374 		}
375 
376 		/* )
377 		 * @see org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener#dialogFieldChanged(org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField)
378 		 */
379 		@Override
dialogFieldChanged(DialogField field)380 		public void dialogFieldChanged(DialogField field) {
381 			doDialogFieldChanged(field);
382 		}
383 
384 		/*
385 		 * @see org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter#doubleClicked(org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField)
386 		 */
387 		@Override
doubleClicked(ListDialogField<String> field)388 		public void doubleClicked(ListDialogField<String> field) {
389 			if (canEdit(field)) {
390 				doButtonPressed(IDX_EDIT);
391 			}
392 		}
393 	}
394 
395 	private static final String WILDCARD= ".*"; //$NON-NLS-1$
396 
397 	private static final int IDX_NEW_TYPE= 0;
398 	private static final int IDX_NEW_MEMBER= 1;
399 	private static final int IDX_EDIT= 2;
400 	private static final int IDX_REMOVE= 3;
401 	private static final int IDX_RESTORE_DEFAULTS= 4;
402 
403 	private ListDialogField<String> fList;
404 
405 	private Button fAnonymousButton;
406 
407 	protected boolean fIsAnonymous;
408 
409 	/**
410 	 * A key that holds the list of methods or types whose methods are by default expanded with constructors in the Call Hierarchy.
411 	 */
412 	private static Key DEFAULT_EXPAND_WITH_CONSTRUCTORS_MEMBERS= getJDTUIKey(PreferenceConstants.PREF_DEFAULT_EXPAND_WITH_CONSTRUCTORS_MEMBERS);
413 
414 	/**
415 	 * A key that controls whether the methods from anonymous types are by default expanded with constructors in the Call Hierarchy.
416 	 */
417 	private static Key ANONYMOUS_EXPAND_WITH_CONSTRUCTORS= getJDTUIKey(PreferenceConstants.PREF_ANONYMOUS_EXPAND_WITH_CONSTRUCTORS);
418 
419 	/**
420 	 * Returns all the key values.
421 	 *
422 	 * @return array of keys
423 	 */
getAllKeys()424 	public static Key[] getAllKeys() {
425 		return new Key[] { DEFAULT_EXPAND_WITH_CONSTRUCTORS_MEMBERS, ANONYMOUS_EXPAND_WITH_CONSTRUCTORS };
426 	}
427 
428 
429 	/**
430 	 * Creates the call hierarchy preferences configuration block.
431 	 *
432 	 * @param context the status
433 	 * @param container the preference container
434 	 */
ExpandWithConstructorsConfigurationBlock(IStatusChangeListener context, IWorkbenchPreferenceContainer container)435 	public ExpandWithConstructorsConfigurationBlock(IStatusChangeListener context, IWorkbenchPreferenceContainer container) {
436 		super(context, null, getAllKeys(), container);
437 	}
438 
439 	/*
440 	 * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#createContents(org.eclipse.swt.widgets.Composite)
441 	 */
442 	@Override
createContents(Composite parent)443 	protected Control createContents(Composite parent) {
444 		Composite control= new Composite(parent, SWT.NONE);
445 		GridLayout layout= new GridLayout();
446 		layout.numColumns= 2;
447 		layout.marginWidth= 10;
448 		layout.marginHeight= 10;
449 		control.setLayout(layout);
450 
451 		createPreferenceList(control);
452 
453 		fAnonymousButton= new Button(control, SWT.CHECK);
454 		fAnonymousButton.setText(CallHierarchyMessages.CallHierarchyTypesOrMembersDialog_anonymousTypes_label);
455 		fIsAnonymous= getBooleanValue(ANONYMOUS_EXPAND_WITH_CONSTRUCTORS);
456 		fAnonymousButton.setSelection(fIsAnonymous);
457 		fAnonymousButton.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
458 		fAnonymousButton.addSelectionListener(new SelectionAdapter() {
459 			@Override
460 			public void widgetSelected(SelectionEvent e) {
461 				fIsAnonymous= fAnonymousButton.getSelection();
462 			}
463 
464 		});
465 
466 		initialize();
467 
468 		Dialog.applyDialogFont(control);
469 
470 		return control;
471 	}
472 
473 	/**
474 	 * Create a list dialog field.
475 	 *
476 	 * @param parent the composite
477 	 */
createPreferenceList(Composite parent)478 	private void createPreferenceList(Composite parent) {
479 		String[] buttonLabels= new String[] {
480 				CallHierarchyMessages.ExpandWithConstructorsConfigurationBlock_newType_button,
481 				CallHierarchyMessages.ExpandWithConstructorsConfigurationBlock_newMember_button,
482 				CallHierarchyMessages.ExpandWithConstructorsConfigurationBlock_edit_button,
483 				CallHierarchyMessages.ExpandWithConstructorsConfigurationBlock_remove_button,
484 				CallHierarchyMessages.ExpandWithConstructorsConfigurationBlock_restoreDefaults_button
485 		};
486 
487 		ListAdapter adapter= new ListAdapter();
488 
489 		fList= new ListDialogField<>(adapter, buttonLabels, new ListLabelProvider());
490 		fList.setDialogFieldListener(adapter);
491 		fList.setLabelText(CallHierarchyMessages.ExpandWithConstructorsConfigurationBlock_description);
492 		fList.setRemoveButtonIndex(IDX_REMOVE);
493 		fList.enableButton(IDX_EDIT, false);
494 		fList.setViewerComparator(new ViewerComparator());
495 
496 		PixelConverter pixelConverter= new PixelConverter(parent);
497 
498 		fList.doFillIntoGrid(parent, 3);
499 		LayoutUtil.setHorizontalSpan(fList.getLabelControl(null), 2);
500 		LayoutUtil.setWidthHint(fList.getLabelControl(null), pixelConverter.convertWidthInCharsToPixels(60));
501 		LayoutUtil.setHorizontalGrabbing(fList.getListControl(null));
502 
503 		Control listControl= fList.getListControl(null);
504 		GridData gd= (GridData)listControl.getLayoutData();
505 		gd.verticalAlignment= GridData.FILL;
506 		gd.grabExcessVerticalSpace= true;
507 		gd.heightHint= pixelConverter.convertHeightInCharsToPixels(10);
508 	}
509 
510 	/**
511 	 * Initialize the elements of the list dialog field.
512 	 */
initialize()513 	public void initialize() {
514 		fList.setElements(Arrays.asList(getDefaultExpandWithConstructorsMembers()));
515 	}
516 
517 	/*
518 	 * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#performDefaults()
519 	 */
520 	@Override
performDefaults()521 	public void performDefaults() {
522 		String str= PreferenceConstants.getPreferenceStore().getDefaultString(PreferenceConstants.PREF_DEFAULT_EXPAND_WITH_CONSTRUCTORS_MEMBERS);
523 		fList.setElements(Arrays.asList(deserializeMembers(str)));
524 		fIsAnonymous= PreferenceConstants.getPreferenceStore().getDefaultBoolean(PreferenceConstants.PREF_ANONYMOUS_EXPAND_WITH_CONSTRUCTORS);
525 		fAnonymousButton.setSelection(fIsAnonymous);
526 		super.performDefaults();
527 	}
528 
529 	/*
530 	 * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#getFullBuildDialogStrings(boolean)
531 	 */
532 	@Override
getFullBuildDialogStrings(boolean workspaceSettings)533 	protected String[] getFullBuildDialogStrings(boolean workspaceSettings) {
534 		return null;
535 	}
536 
537 	/*
538 	 * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#validateSettings(org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock.Key, java.lang.String, java.lang.String)
539 	 */
540 	@Override
validateSettings(Key changedKey, String oldValue, String newValue)541 	protected void validateSettings(Key changedKey, String oldValue, String newValue) {
542 
543 	}
544 
545 	/**
546 	 * Perform the 'New' and 'Edit' button operations by opening the respective call hierarchy
547 	 * preferences dialog, and 'Restore Defaults' button by restoring to default values for the list dialog.
548 	 *
549 	 * @param index the index of the button
550 	 */
doButtonPressed(int index)551 	private void doButtonPressed(int index) {
552 		switch (index) {
553 		case IDX_NEW_TYPE:
554 		case IDX_NEW_MEMBER:
555 			{
556 				// add new
557 				List<String> existing= fList.getElements();
558 				CallHierarchyTypesOrMembersDialog dialog= new CallHierarchyTypesOrMembersDialog(getShell(), existing, index == IDX_NEW_MEMBER);
559 				if (dialog.open() == Window.OK) {
560 					fList.addElement(dialog.getResult());
561 				}	break;
562 			}
563 		case IDX_EDIT:
564 			{
565 				// edit
566 				List<String> selected= fList.getSelectedElements();
567 				if (selected.isEmpty())
568 					return;
569 				String editedEntry= selected.get(0);
570 				List<String> existing= fList.getElements();
571 				existing.remove(editedEntry);
572 				boolean isType= editedEntry.endsWith(WILDCARD);
573 				CallHierarchyTypesOrMembersDialog dialog= new CallHierarchyTypesOrMembersDialog(getShell(), existing, !isType);
574 				if (isType)
575 					dialog.setInitialSelection(editedEntry.substring(0, editedEntry.length() - 2));
576 				else
577 					dialog.setInitialSelection(editedEntry);
578 				if (dialog.open() == Window.OK) {
579 					fList.replaceElement(editedEntry, dialog.getResult());
580 				}	break;
581 			}
582 		case IDX_RESTORE_DEFAULTS:
583 			performDefaults();
584 			break;
585 		default:
586 			break;
587 		}
588 	}
589 
590 	/**
591 	 * Update the key on dialog field change.
592 	 *
593 	 * @param field the dialog field
594 	 */
doDialogFieldChanged(DialogField field)595 	protected final void doDialogFieldChanged(DialogField field) {
596 		// set values in working copy
597 		if (field == fList) {
598 			setValue(DEFAULT_EXPAND_WITH_CONSTRUCTORS_MEMBERS, serializeMembers(fList.getElements()));
599 		}
600 	}
601 
602 	/**
603 	 * Returns the array of strings containing the types or methods for default expand with constructors.
604 	 *
605 	 * @return the array of strings containing the types or methods for default expand with constructors
606 	 */
getDefaultExpandWithConstructorsMembers()607 	private String[] getDefaultExpandWithConstructorsMembers() {
608 		String str= getValue(DEFAULT_EXPAND_WITH_CONSTRUCTORS_MEMBERS);
609 		if (str != null && str.length() > 0) {
610 			return deserializeMembers(str);
611 		}
612 		return new String[0];
613 	}
614 
615 	/**
616 	 * Return the array of types and/or methods after splitting the stored preference string.
617 	 *
618 	 * @param str the input string
619 	 * @return the array of types and/or methods
620 	 */
deserializeMembers(String str)621 	private static String[] deserializeMembers(String str) {
622 		return str.split(";"); //$NON-NLS-1$
623 	}
624 
625 	/**
626 	 * Creates a single output string from the list of strings using a delimiter.
627 	 *
628 	 * @param list the input list of types and/or methods
629 	 * @return the single output string from the list of strings using a delimiter
630 	 */
serializeMembers(List<String> list)631 	public static String serializeMembers(List<String> list) {
632 		return String.join(";", list.toArray(new String[list.size()])); //$NON-NLS-1$
633 	}
634 
635 }
636