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.jdt.internal.ui.refactoring;
011:
012: import java.lang.reflect.InvocationTargetException;
013: import java.util.Arrays;
014: import java.util.HashSet;
015: import java.util.Iterator;
016: import java.util.LinkedList;
017: import java.util.Set;
018:
019: import org.eclipse.core.runtime.Assert;
020: import org.eclipse.core.runtime.IProgressMonitor;
021: import org.eclipse.core.runtime.OperationCanceledException;
022:
023: import org.eclipse.swt.SWT;
024: import org.eclipse.swt.events.ModifyEvent;
025: import org.eclipse.swt.events.ModifyListener;
026: import org.eclipse.swt.events.SelectionAdapter;
027: import org.eclipse.swt.events.SelectionEvent;
028: import org.eclipse.swt.graphics.Image;
029: import org.eclipse.swt.layout.GridData;
030: import org.eclipse.swt.layout.GridLayout;
031: import org.eclipse.swt.widgets.Button;
032: import org.eclipse.swt.widgets.Composite;
033: import org.eclipse.swt.widgets.Control;
034: import org.eclipse.swt.widgets.Label;
035: import org.eclipse.swt.widgets.Shell;
036: import org.eclipse.swt.widgets.Text;
037:
038: import org.eclipse.jface.dialogs.Dialog;
039: import org.eclipse.jface.operation.IRunnableWithProgress;
040: import org.eclipse.jface.viewers.ArrayContentProvider;
041: import org.eclipse.jface.viewers.DoubleClickEvent;
042: import org.eclipse.jface.viewers.IDoubleClickListener;
043: import org.eclipse.jface.viewers.ILabelProvider;
044: import org.eclipse.jface.viewers.ISelectionChangedListener;
045: import org.eclipse.jface.viewers.IStructuredSelection;
046: import org.eclipse.jface.viewers.ITableLabelProvider;
047: import org.eclipse.jface.viewers.SelectionChangedEvent;
048: import org.eclipse.jface.viewers.StructuredSelection;
049: import org.eclipse.jface.viewers.TableViewer;
050: import org.eclipse.jface.viewers.Viewer;
051: import org.eclipse.jface.viewers.ViewerComparator;
052: import org.eclipse.jface.window.Window;
053:
054: import org.eclipse.ui.PlatformUI;
055: import org.eclipse.ui.dialogs.SelectionDialog;
056:
057: import org.eclipse.ltk.core.refactoring.RefactoringStatus;
058:
059: import org.eclipse.jdt.core.IType;
060: import org.eclipse.jdt.core.JavaModelException;
061:
062: import org.eclipse.jdt.internal.corext.refactoring.structure.ExtractSupertypeProcessor;
063: import org.eclipse.jdt.internal.corext.refactoring.structure.ExtractSupertypeRefactoring;
064:
065: import org.eclipse.jdt.ui.JavaElementComparator;
066: import org.eclipse.jdt.ui.JavaElementLabels;
067:
068: import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
069: import org.eclipse.jdt.internal.ui.dialogs.TextFieldNavigationHandler;
070: import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
071: import org.eclipse.jdt.internal.ui.util.SWTUtil;
072: import org.eclipse.jdt.internal.ui.viewsupport.AppearanceAwareLabelProvider;
073: import org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider;
074:
075: /**
076: * Wizard page for the extract supertype refactoring, which, apart from pull up
077: * facilities, also allows to specify the types where to extract the supertype.
078: *
079: * @since 3.2
080: */
081: public final class ExtractSupertypeMemberPage extends PullUpMemberPage {
082:
083: /** Dialog to select supertypes */
084: private static class SupertypeSelectionDialog extends
085: SelectionDialog {
086:
087: /** The table viewer */
088: private TableViewer fViewer;
089:
090: /**
091: * Creates a new supertype selection dialog.
092: *
093: * @param shell
094: * the parent shell
095: */
096: public SupertypeSelectionDialog(final Shell shell) {
097: super (shell);
098: setHelpAvailable(false);
099: }
100:
101: /**
102: * {@inheritDoc}
103: */
104: public void create() {
105: setShellStyle(getShellStyle() | SWT.RESIZE);
106: super .create();
107: getShell()
108: .setText(
109: RefactoringMessages.ExtractSupertypeMemberPage_choose_type_caption);
110: }
111:
112: /**
113: * {@inheritDoc}
114: */
115: protected Control createDialogArea(final Composite composite) {
116: Assert.isNotNull(composite);
117: setMessage(RefactoringMessages.ExtractSupertypeMemberPage_choose_type_message);
118: final Composite control = (Composite) super
119: .createDialogArea(composite);
120: createMessageArea(control);
121: fViewer = new TableViewer(control, SWT.MULTI | SWT.H_SCROLL
122: | SWT.V_SCROLL | SWT.BORDER);
123: fViewer.setLabelProvider(createLabelProvider());
124: fViewer.setContentProvider(new ArrayContentProvider());
125: fViewer.setComparator(new SupertypeSelectionViewerSorter());
126: fViewer
127: .addSelectionChangedListener(new ISelectionChangedListener() {
128: public void selectionChanged(
129: final SelectionChangedEvent event) {
130: performSelectionChanged(((IStructuredSelection) fViewer
131: .getSelection()).toArray());
132: }
133: });
134: fViewer.addDoubleClickListener(new IDoubleClickListener() {
135: public void doubleClick(final DoubleClickEvent event) {
136: performSelectionChanged(((IStructuredSelection) fViewer
137: .getSelection()).toArray());
138: close();
139: }
140: });
141: final GridData data = new GridData(GridData.FILL_BOTH);
142: data.heightHint = convertHeightInCharsToPixels(15);
143: data.widthHint = convertWidthInCharsToPixels(55);
144: fViewer.getTable().setLayoutData(data);
145: applyDialogFont(control);
146: return control;
147: }
148:
149: protected void performSelectionChanged(Object[] selection) {
150: setSelectionResult(selection);
151: getOkButton().setEnabled(selection.length != 0);
152: }
153:
154: /**
155: * Sets the input of this dialog.
156: *
157: * @param input
158: * the input elements
159: */
160: public void setInput(final Object[] input) {
161: fViewer.setInput(input);
162: if (input.length > 0) {
163: fViewer.setSelection(new StructuredSelection(input[0]));
164: }
165: getOkButton().setEnabled(!fViewer.getSelection().isEmpty());
166: }
167: }
168:
169: /** The label provider */
170: private static class SupertypeSelectionLabelProvider extends
171: AppearanceAwareLabelProvider implements ITableLabelProvider {
172:
173: /**
174: * Creates a new supertype selection label provider.
175: *
176: * @param textFlags
177: * the text flags
178: * @param imageFlags
179: * the image flags
180: */
181: public SupertypeSelectionLabelProvider(final long textFlags,
182: final int imageFlags) {
183: super (textFlags, imageFlags);
184: }
185:
186: /**
187: * {@inheritDoc}
188: */
189: public Image getColumnImage(final Object element,
190: final int index) {
191: return getImage(element);
192: }
193:
194: /**
195: * {@inheritDoc}
196: */
197: public String getColumnText(final Object element,
198: final int index) {
199: return getText(element);
200: }
201: }
202:
203: /** The viewer sorter */
204: private static class SupertypeSelectionViewerSorter extends
205: ViewerComparator {
206:
207: /**
208: * {@inheritDoc}
209: */
210: public int compare(final Viewer viewer, final Object first,
211: final Object second) {
212: final IType predecessor = (IType) first;
213: final IType successor = (IType) second;
214: return getComparator().compare(
215: predecessor.getElementName(),
216: successor.getElementName());
217: }
218: }
219:
220: /**
221: * Creates a label provider for a type list.
222: *
223: * @return a label provider
224: */
225: private static ILabelProvider createLabelProvider() {
226: return new SupertypeSelectionLabelProvider(
227: JavaElementLabels.T_TYPE_PARAMETERS
228: | JavaElementLabels.T_POST_QUALIFIED,
229: JavaElementImageProvider.OVERLAY_ICONS);
230: }
231:
232: /** The supertype name field */
233: private Text fNameField;
234:
235: /** The table viewer */
236: private TableViewer fTableViewer;
237:
238: /** The types to extract */
239: private final Set fTypesToExtract = new HashSet(2);
240:
241: /**
242: * Creates a new extract supertype member page.
243: *
244: * @param name
245: * the page name
246: * @param page
247: * the method page
248: */
249: public ExtractSupertypeMemberPage(final String name,
250: final ExtractSupertypeMethodPage page) {
251: super (name, page);
252: setDescription(RefactoringMessages.ExtractSupertypeMemberPage_page_title);
253: METHOD_LABELS[PULL_UP_ACTION] = RefactoringMessages.ExtractSupertypeMemberPage_extract;
254: METHOD_LABELS[DECLARE_ABSTRACT_ACTION] = RefactoringMessages.ExtractSupertypeMemberPage_declare_abstract;
255: TYPE_LABELS[PULL_UP_ACTION] = RefactoringMessages.ExtractSupertypeMemberPage_extract;
256: }
257:
258: /**
259: * {@inheritDoc}
260: */
261: protected void checkPageCompletionStatus(final boolean display) {
262: final RefactoringStatus status = getProcessor()
263: .checkExtractedCompilationUnit();
264: setMessage(null);
265: if (display)
266: setPageComplete(status);
267: else
268: setPageComplete(!status.hasFatalError());
269: fSuccessorPage.fireSettingsChanged();
270: }
271:
272: /**
273: * Computes the candidate types.
274: *
275: * @throws InterruptedException
276: * if the computation has been interrupted
277: */
278: protected void computeCandidateTypes() throws InterruptedException {
279: if (fCandidateTypes != null && fCandidateTypes.length > 0)
280: return;
281: try {
282: getWizard().getContainer().run(true, true,
283: new IRunnableWithProgress() {
284:
285: public void run(final IProgressMonitor monitor)
286: throws InvocationTargetException {
287: try {
288: fCandidateTypes = getProcessor()
289: .getCandidateTypes(
290: new RefactoringStatus(),
291: monitor);
292: } finally {
293: monitor.done();
294: }
295: }
296: });
297: } catch (InvocationTargetException exception) {
298: ExceptionHandler
299: .handle(
300: exception,
301: getShell(),
302: RefactoringMessages.ExtractSupertypeMemberPage_extract_super type,
303: RefactoringMessages.PullUpInputPage_exception);
304: } catch (InterruptedException exception) {
305: fCandidateTypes = new IType[0];
306: throw new InterruptedException();
307: } catch (OperationCanceledException exception) {
308: fCandidateTypes = new IType[0];
309: }
310: }
311:
312: /**
313: * Creates the button composite.
314: *
315: * @param parent
316: * the parent control
317: */
318: protected void createButtonComposite(final Composite parent) {
319: final Composite buttons = new Composite(parent, SWT.NONE);
320: final GridLayout layout = new GridLayout();
321: layout.marginHeight = 0;
322: layout.marginWidth = 0;
323: buttons.setLayout(layout);
324: buttons.setLayoutData(new GridData(GridData.FILL_VERTICAL));
325:
326: final Button addButton = new Button(buttons, SWT.PUSH);
327: addButton
328: .setText(RefactoringMessages.ExtractSupertypeMemberPage_add_button_label);
329: addButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
330: SWTUtil.setButtonDimensionHint(addButton);
331: addButton.addSelectionListener(new SelectionAdapter() {
332:
333: public void widgetSelected(final SelectionEvent event) {
334: try {
335: computeCandidateTypes();
336: } catch (InterruptedException exception) {
337: return;
338: }
339: final LinkedList list = new LinkedList(Arrays
340: .asList(fCandidateTypes));
341: for (final Iterator outer = list.iterator(); outer
342: .hasNext();) {
343: final IType first = (IType) outer.next();
344: for (final Iterator inner = fTypesToExtract
345: .iterator(); inner.hasNext();) {
346: final IType second = (IType) inner.next();
347: if (second.getFullyQualifiedName().equals(
348: first.getFullyQualifiedName()))
349: outer.remove();
350: }
351: }
352: final SupertypeSelectionDialog dialog = new SupertypeSelectionDialog(
353: getShell());
354: dialog.create();
355: dialog.setInput(list.toArray());
356: final int result = dialog.open();
357: if (result == Window.OK) {
358: final Object[] objects = dialog.getResult();
359: if (objects != null && objects.length > 0) {
360: for (int index = 0; index < objects.length; index++) {
361: fTypesToExtract.add(objects[index]);
362: }
363: fTableViewer
364: .setInput(fTypesToExtract.toArray());
365: handleTypesChanged();
366: }
367: }
368: }
369: });
370:
371: final Button removeButton = new Button(buttons, SWT.PUSH);
372: removeButton
373: .setText(RefactoringMessages.ExtractSupertypeMemberPage_remove_button_label);
374: removeButton.setEnabled(fCandidateTypes.length > 0
375: && !fTableViewer.getSelection().isEmpty());
376: removeButton.setLayoutData(new GridData(
377: GridData.FILL_HORIZONTAL));
378: SWTUtil.setButtonDimensionHint(removeButton);
379: removeButton.addSelectionListener(new SelectionAdapter() {
380:
381: public void widgetSelected(final SelectionEvent event) {
382: final IStructuredSelection selection = (IStructuredSelection) fTableViewer
383: .getSelection();
384: if (!selection.isEmpty()) {
385: final IType declaring = getDeclaringType();
386: for (final Iterator iterator = selection.iterator(); iterator
387: .hasNext();) {
388: final Object element = iterator.next();
389: if (!declaring.equals(element))
390: fTypesToExtract.remove(element);
391: }
392: fTableViewer.setInput(fTypesToExtract.toArray());
393: handleTypesChanged();
394: }
395: }
396: });
397: fTableViewer
398: .addSelectionChangedListener(new ISelectionChangedListener() {
399:
400: public void selectionChanged(
401: final SelectionChangedEvent event) {
402: final IStructuredSelection selection = (IStructuredSelection) fTableViewer
403: .getSelection();
404: if (selection.isEmpty()) {
405: removeButton.setEnabled(false);
406: return;
407: } else {
408: final Object[] elements = selection
409: .toArray();
410: if (elements.length == 1
411: && elements[0]
412: .equals(getDeclaringType())) {
413: removeButton.setEnabled(false);
414: return;
415: }
416: }
417: removeButton.setEnabled(true);
418: }
419: });
420: }
421:
422: /**
423: * {@inheritDoc}
424: */
425: public void createControl(final Composite parent) {
426: final Composite composite = new Composite(parent, SWT.NONE);
427: final GridLayout layout = new GridLayout();
428: layout.numColumns = 2;
429: composite.setLayout(layout);
430: createSuperTypeField(composite);
431: createSpacer(composite);
432: createSuperTypeCheckbox(composite);
433: createInstanceOfCheckbox(composite, layout.marginWidth);
434: createStubCheckbox(composite);
435: createSuperTypeControl(composite);
436: createSpacer(composite);
437: createMemberTableLabel(composite);
438: createMemberTableComposite(composite);
439: createStatusLine(composite);
440:
441: setControl(composite);
442: Dialog.applyDialogFont(composite);
443: initializeEnablement();
444: initializeCheckboxes();
445: PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(),
446: IJavaHelpContextIds.EXTRACT_SUPERTYPE_WIZARD_PAGE);
447: }
448:
449: /**
450: * {@inheritDoc}
451: */
452: protected void createSuperTypeControl(final Composite parent) {
453: try {
454: createSuperTypeList(parent);
455: } catch (JavaModelException exception) {
456: ExceptionHandler
457: .handle(
458: exception,
459: getShell(),
460: RefactoringMessages.ExtractSupertypeMemberPage_extract_super type,
461: RefactoringMessages.PullUpInputPage_exception);
462: }
463: }
464:
465: /**
466: * Creates the super type field.
467: *
468: * @param parent
469: * the parent control
470: */
471: protected void createSuperTypeField(final Composite parent) {
472: final Label label = new Label(parent, SWT.NONE);
473: label
474: .setText(RefactoringMessages.ExtractSupertypeMemberPage_name_label);
475: label.setLayoutData(new GridData());
476:
477: fNameField = new Text(parent, SWT.BORDER);
478: fNameField.addModifyListener(new ModifyListener() {
479:
480: public void modifyText(ModifyEvent e) {
481: handleNameChanged(fNameField.getText());
482: }
483: });
484: fNameField.setLayoutData(new GridData(GridData.FILL,
485: GridData.CENTER, true, false));
486: TextFieldNavigationHandler.install(fNameField);
487: }
488:
489: /**
490: * Creates the super type list.
491: *
492: * @param parent
493: * the parent control
494: * @throws JavaModelException
495: */
496: protected void createSuperTypeList(final Composite parent)
497: throws JavaModelException {
498: createSpacer(parent);
499:
500: final Label label = new Label(parent, SWT.NONE);
501: label
502: .setText(RefactoringMessages.ExtractSupertypeMemberPage_types_list_caption);
503: GridData data = new GridData();
504: data.horizontalSpan = 2;
505: label.setLayoutData(data);
506:
507: final Composite composite = new Composite(parent, SWT.NONE);
508: final GridLayout layout = new GridLayout();
509: layout.numColumns = 2;
510: layout.marginWidth = 0;
511: layout.marginHeight = 0;
512: composite.setLayout(layout);
513: data = new GridData(GridData.FILL_BOTH);
514: data.horizontalSpan = 2;
515: composite.setLayoutData(data);
516:
517: fTableViewer = new TableViewer(composite, SWT.MULTI
518: | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
519: data = new GridData(GridData.FILL_BOTH);
520: data.heightHint = SWTUtil.getTableHeightHint(fTableViewer
521: .getTable(), 3);
522: fTableViewer.getTable().setLayoutData(data);
523: fTableViewer.setLabelProvider(createLabelProvider());
524: fTableViewer.setContentProvider(new ArrayContentProvider());
525: fTableViewer.setComparator(new JavaElementComparator());
526: fTypesToExtract.add(getDeclaringType());
527: fTableViewer.setInput(fTypesToExtract.toArray());
528:
529: createButtonComposite(composite);
530: }
531:
532: /**
533: * {@inheritDoc}
534: */
535: protected String getCreateStubsButtonLabel() {
536: return RefactoringMessages.ExtractSupertypeMemberPage_create_stubs_label;
537: }
538:
539: /**
540: * {@inheritDoc}
541: */
542: protected String getDeclareAbstractActionLabel() {
543: return RefactoringMessages.ExtractSupertypeMemberPage_declare_abstract;
544: }
545:
546: /**
547: * Returns the declaring type.
548: *
549: * @return the declaring type
550: */
551: public IType getDeclaringType() {
552: return getProcessor().getDeclaringType();
553: }
554:
555: /**
556: * {@inheritDoc}
557: */
558: public IType getDestinationType() {
559: return getProcessor()
560: .computeExtractedType(fNameField.getText());
561: }
562:
563: /**
564: * Returns the extract supertype refactoring.
565: * @return the refactoring
566: */
567: public ExtractSupertypeRefactoring getExtractSuperTypeRefactoring() {
568: return (ExtractSupertypeRefactoring) getRefactoring();
569: }
570:
571: /**
572: * {@inheritDoc}
573: */
574: protected String getInstanceofButtonLabel() {
575: return RefactoringMessages.ExtractSupertypeMemberPage_use_super type_label;
576: }
577:
578: /**
579: * {@inheritDoc}
580: */
581: protected String getNoMembersMessage() {
582: return RefactoringMessages.ExtractSupertypeMemberPage_no_members_selected;
583: }
584:
585: /**
586: * Returns the refactoring processor.
587: *
588: * @return the refactoring processor
589: */
590: protected ExtractSupertypeProcessor getProcessor() {
591: return getExtractSuperTypeRefactoring()
592: .getExtractSupertypeProcessor();
593: }
594:
595: /**
596: * {@inheritDoc}
597: */
598: protected String getPullUpActionLabel() {
599: return RefactoringMessages.ExtractSupertypeMemberPage_extract;
600: }
601:
602: /**
603: * {@inheritDoc}
604: */
605: protected String getReplaceButtonLabel() {
606: return RefactoringMessages.ExtractSupertypeMemberPage_use_instanceof _label;
607: }
608:
609: /**
610: * {@inheritDoc}
611: */
612: protected int getTableRowCount() {
613: return 6;
614: }
615:
616: /**
617: * Handles the name changed event.
618: *
619: * @param name
620: * the name
621: */
622: protected void handleNameChanged(final String name) {
623: if (name != null)
624: getProcessor().setTypeName(name);
625: checkPageCompletionStatus(true);
626: }
627:
628: /**
629: * Handles the types changed event.
630: */
631: protected void handleTypesChanged() {
632: getProcessor().setTypesToExtract(
633: (IType[]) fTypesToExtract
634: .toArray(new IType[fTypesToExtract.size()]));
635: }
636:
637: /**
638: * {@inheritDoc}
639: */
640: public void setVisible(final boolean visible) {
641: super.setVisible(visible);
642: if (visible) {
643: fNameField.setFocus();
644: getProcessor().resetChanges();
645: }
646: }
647: }
|