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.jdt.internal.ui.wizards;
011:
012: import java.net.URI;
013: import java.util.ArrayList;
014: import java.util.HashSet;
015: import java.util.List;
016: import java.util.Set;
017:
018: import org.eclipse.core.filesystem.EFS;
019: import org.eclipse.core.filesystem.IFileStore;
020:
021: import org.eclipse.core.runtime.CoreException;
022: import org.eclipse.core.runtime.IPath;
023: import org.eclipse.core.runtime.IProgressMonitor;
024: import org.eclipse.core.runtime.IStatus;
025: import org.eclipse.core.runtime.NullProgressMonitor;
026: import org.eclipse.core.runtime.Path;
027: import org.eclipse.core.runtime.SubProgressMonitor;
028:
029: import org.eclipse.core.resources.IFolder;
030: import org.eclipse.core.resources.IProject;
031: import org.eclipse.core.resources.IResource;
032: import org.eclipse.core.resources.IWorkspaceRoot;
033: import org.eclipse.core.resources.ResourcesPlugin;
034:
035: import org.eclipse.swt.SWT;
036: import org.eclipse.swt.layout.GridLayout;
037: import org.eclipse.swt.widgets.Composite;
038:
039: import org.eclipse.jface.dialogs.Dialog;
040: import org.eclipse.jface.viewers.ILabelProvider;
041: import org.eclipse.jface.viewers.IStructuredSelection;
042: import org.eclipse.jface.viewers.ITreeContentProvider;
043: import org.eclipse.jface.viewers.ViewerFilter;
044: import org.eclipse.jface.window.Window;
045:
046: import org.eclipse.ui.PlatformUI;
047: import org.eclipse.ui.dialogs.ElementListSelectionDialog;
048: import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
049: import org.eclipse.ui.dialogs.ISelectionStatusValidator;
050: import org.eclipse.ui.model.WorkbenchContentProvider;
051: import org.eclipse.ui.model.WorkbenchLabelProvider;
052:
053: import org.eclipse.ui.views.navigator.ResourceComparator;
054:
055: import org.eclipse.jdt.core.IClasspathEntry;
056: import org.eclipse.jdt.core.IJavaElement;
057: import org.eclipse.jdt.core.IJavaModelStatus;
058: import org.eclipse.jdt.core.IJavaProject;
059: import org.eclipse.jdt.core.IPackageFragmentRoot;
060: import org.eclipse.jdt.core.JavaConventions;
061: import org.eclipse.jdt.core.JavaCore;
062: import org.eclipse.jdt.core.JavaModelException;
063:
064: import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
065: import org.eclipse.jdt.internal.corext.util.Messages;
066:
067: import org.eclipse.jdt.ui.JavaElementLabelProvider;
068: import org.eclipse.jdt.ui.PreferenceConstants;
069: import org.eclipse.jdt.ui.wizards.NewElementWizardPage;
070:
071: import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
072: import org.eclipse.jdt.internal.ui.JavaPlugin;
073: import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
074: import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
075: import org.eclipse.jdt.internal.ui.util.CoreUtility;
076: import org.eclipse.jdt.internal.ui.wizards.buildpaths.BuildPathsBlock;
077: import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField;
078: import org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
079: import org.eclipse.jdt.internal.ui.wizards.dialogfields.IStringButtonAdapter;
080: import org.eclipse.jdt.internal.ui.wizards.dialogfields.LayoutUtil;
081: import org.eclipse.jdt.internal.ui.wizards.dialogfields.SelectionButtonDialogField;
082: import org.eclipse.jdt.internal.ui.wizards.dialogfields.StringButtonDialogField;
083:
084: public class NewSourceFolderWizardPage extends NewElementWizardPage {
085:
086: private static final String PAGE_NAME = "NewSourceFolderWizardPage"; //$NON-NLS-1$
087:
088: private StringButtonDialogField fProjectField;
089: private StatusInfo fProjectStatus;
090:
091: private StringButtonDialogField fRootDialogField;
092: private StatusInfo fRootStatus;
093:
094: private SelectionButtonDialogField fExcludeInOthersFields;
095:
096: private IWorkspaceRoot fWorkspaceRoot;
097:
098: private IJavaProject fCurrJProject;
099: private IClasspathEntry[] fEntries;
100: private IPath fOutputLocation;
101:
102: private IClasspathEntry[] fNewEntries;
103: private IPath fNewOutputLocation;
104:
105: private boolean fIsProjectAsSourceFolder;
106:
107: private IPackageFragmentRoot fCreatedRoot;
108:
109: public NewSourceFolderWizardPage() {
110: super (PAGE_NAME);
111:
112: setTitle(NewWizardMessages.NewSourceFolderWizardPage_title);
113: setDescription(NewWizardMessages.NewSourceFolderWizardPage_description);
114:
115: fWorkspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
116:
117: RootFieldAdapter adapter = new RootFieldAdapter();
118:
119: fProjectField = new StringButtonDialogField(adapter);
120: fProjectField.setDialogFieldListener(adapter);
121: fProjectField
122: .setLabelText(NewWizardMessages.NewSourceFolderWizardPage_project_label);
123: fProjectField
124: .setButtonLabel(NewWizardMessages.NewSourceFolderWizardPage_project_button);
125:
126: fRootDialogField = new StringButtonDialogField(adapter);
127: fRootDialogField.setDialogFieldListener(adapter);
128: fRootDialogField
129: .setLabelText(NewWizardMessages.NewSourceFolderWizardPage_root_label);
130: fRootDialogField
131: .setButtonLabel(NewWizardMessages.NewSourceFolderWizardPage_root_button);
132:
133: fExcludeInOthersFields = new SelectionButtonDialogField(
134: SWT.CHECK);
135: fExcludeInOthersFields.setDialogFieldListener(adapter);
136: fExcludeInOthersFields
137: .setLabelText(NewWizardMessages.NewSourceFolderWizardPage_exclude_label);
138:
139: fExcludeInOthersFields
140: .setEnabled(JavaCore.ENABLED
141: .equals(JavaCore
142: .getOption(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS)));
143:
144: fRootStatus = new StatusInfo();
145: fProjectStatus = new StatusInfo();
146: }
147:
148: // -------- Initialization ---------
149:
150: public void init(IStructuredSelection selection) {
151: String projPath = getProjectPath(selection);
152: if (projPath != null) {
153: fProjectField.setText(projPath);
154: }
155: fRootDialogField.setText(""); //$NON-NLS-1$
156: }
157:
158: private String getProjectPath(IStructuredSelection selection) {
159: Object selectedElement = null;
160: if (selection == null || selection.isEmpty()) {
161: selectedElement = EditorUtility.getActiveEditorJavaInput();
162: } else if (selection.size() == 1) {
163: selectedElement = selection.getFirstElement();
164: }
165:
166: if (selectedElement instanceof IResource) {
167: IProject proj = ((IResource) selectedElement).getProject();
168: if (proj != null) {
169: return proj.getFullPath().makeRelative().toString();
170: }
171: } else if (selectedElement instanceof IJavaElement) {
172: IJavaProject jproject = ((IJavaElement) selectedElement)
173: .getJavaProject();
174: if (jproject != null) {
175: return jproject.getProject().getFullPath()
176: .makeRelative().toString();
177: }
178: }
179:
180: return null;
181: }
182:
183: // -------- UI Creation ---------
184:
185: /*
186: * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
187: */
188: public void createControl(Composite parent) {
189: initializeDialogUnits(parent);
190:
191: Composite composite = new Composite(parent, SWT.NONE);
192:
193: GridLayout layout = new GridLayout();
194: layout.numColumns = 3;
195: composite.setLayout(layout);
196:
197: fProjectField.doFillIntoGrid(composite, 3);
198: fRootDialogField.doFillIntoGrid(composite, 3);
199: fExcludeInOthersFields.doFillIntoGrid(composite, 3);
200:
201: int maxFieldWidth = convertWidthInCharsToPixels(40);
202: LayoutUtil.setWidthHint(fProjectField.getTextControl(null),
203: maxFieldWidth);
204: LayoutUtil.setHorizontalGrabbing(fProjectField
205: .getTextControl(null));
206: LayoutUtil.setWidthHint(fRootDialogField.getTextControl(null),
207: maxFieldWidth);
208:
209: setControl(composite);
210: Dialog.applyDialogFont(composite);
211: PlatformUI.getWorkbench().getHelpSystem().setHelp(composite,
212: IJavaHelpContextIds.NEW_PACKAGEROOT_WIZARD_PAGE);
213: }
214:
215: /*
216: * @see org.eclipse.jface.dialogs.IDialogPage#setVisible(boolean)
217: */
218: public void setVisible(boolean visible) {
219: super .setVisible(visible);
220: if (visible) {
221: fRootDialogField.setFocus();
222: }
223: }
224:
225: // -------- ContainerFieldAdapter --------
226:
227: private class RootFieldAdapter implements IStringButtonAdapter,
228: IDialogFieldListener {
229:
230: // -------- IStringButtonAdapter
231: public void changeControlPressed(DialogField field) {
232: packRootChangeControlPressed(field);
233: }
234:
235: // -------- IDialogFieldListener
236: public void dialogFieldChanged(DialogField field) {
237: packRootDialogFieldChanged(field);
238: }
239: }
240:
241: protected void packRootChangeControlPressed(DialogField field) {
242: if (field == fRootDialogField) {
243: IPath initialPath = new Path(fRootDialogField.getText());
244: String title = NewWizardMessages.NewSourceFolderWizardPage_ChooseExistingRootDialog_title;
245: String message = NewWizardMessages.NewSourceFolderWizardPage_ChooseExistingRootDialog_description;
246: IFolder folder = chooseFolder(title, message, initialPath);
247: if (folder != null) {
248: IPath path = folder.getFullPath()
249: .removeFirstSegments(1);
250: fRootDialogField.setText(path.toString());
251: }
252: } else if (field == fProjectField) {
253: IJavaProject jproject = chooseProject();
254: if (jproject != null) {
255: IPath path = jproject.getProject().getFullPath()
256: .makeRelative();
257: fProjectField.setText(path.toString());
258: }
259: }
260: }
261:
262: protected void packRootDialogFieldChanged(DialogField field) {
263: if (field == fRootDialogField) {
264: updateRootStatus();
265: } else if (field == fProjectField) {
266: updateProjectStatus();
267: updateRootStatus();
268: } else if (field == fExcludeInOthersFields) {
269: updateRootStatus();
270: }
271: updateStatus(new IStatus[] { fProjectStatus, fRootStatus });
272: }
273:
274: private void updateProjectStatus() {
275: fCurrJProject = null;
276: fIsProjectAsSourceFolder = false;
277:
278: String str = fProjectField.getText();
279: if (str.length() == 0) {
280: fProjectStatus
281: .setError(NewWizardMessages.NewSourceFolderWizardPage_error_EnterProjectName);
282: return;
283: }
284: IPath path = new Path(str);
285: if (path.segmentCount() != 1) {
286: fProjectStatus
287: .setError(NewWizardMessages.NewSourceFolderWizardPage_error_InvalidProjectPath);
288: return;
289: }
290: IProject project = fWorkspaceRoot.getProject(path.toString());
291: if (!project.exists()) {
292: fProjectStatus
293: .setError(NewWizardMessages.NewSourceFolderWizardPage_error_ProjectNotExists);
294: return;
295: }
296: if (!project.isOpen()) {
297: fProjectStatus
298: .setError(NewWizardMessages.NewSourceFolderWizardPage_error_ProjectNotOpen);
299: return;
300: }
301: try {
302: if (project.hasNature(JavaCore.NATURE_ID)) {
303: fCurrJProject = JavaCore.create(project);
304: fEntries = fCurrJProject.getRawClasspath();
305: fOutputLocation = fCurrJProject.getOutputLocation();
306: fProjectStatus.setOK();
307: return;
308: }
309: } catch (CoreException e) {
310: JavaPlugin.log(e);
311: fCurrJProject = null;
312: }
313: fProjectStatus
314: .setError(NewWizardMessages.NewSourceFolderWizardPage_error_NotAJavaProject);
315: }
316:
317: private void updateRootStatus() {
318: fRootDialogField.enableButton(fCurrJProject != null);
319: fIsProjectAsSourceFolder = false;
320: if (fCurrJProject == null) {
321: return;
322: }
323: fRootStatus.setOK();
324:
325: IPath projPath = fCurrJProject.getProject().getFullPath();
326: String str = fRootDialogField.getText();
327: if (str.length() == 0) {
328: fRootStatus
329: .setError(Messages
330: .format(
331: NewWizardMessages.NewSourceFolderWizardPage_error_EnterRootName,
332: fCurrJProject.getProject()
333: .getFullPath().toString()));
334: } else {
335: IPath path = projPath.append(str);
336: IStatus validate = fWorkspaceRoot.getWorkspace()
337: .validatePath(path.toString(), IResource.FOLDER);
338: if (validate.matches(IStatus.ERROR)) {
339: fRootStatus
340: .setError(Messages
341: .format(
342: NewWizardMessages.NewSourceFolderWizardPage_error_InvalidRootName,
343: validate.getMessage()));
344: } else {
345: IResource res = fWorkspaceRoot.findMember(path);
346: if (res != null) {
347: if (res.getType() != IResource.FOLDER) {
348: fRootStatus
349: .setError(NewWizardMessages.NewSourceFolderWizardPage_error_NotAFolder);
350: return;
351: }
352: } else {
353: URI projLocation = fCurrJProject.getProject()
354: .getLocationURI();
355: if (projLocation != null) {
356: try {
357: IFileStore store = EFS.getStore(
358: projLocation).getChild(str);
359: if (store.fetchInfo().exists()) {
360: fRootStatus
361: .setError(NewWizardMessages.NewSourceFolderWizardPage_error_AlreadyExistingDifferentCase);
362: return;
363: }
364: } catch (CoreException e) {
365: // we couldn't create the file store. Ignore the exception
366: // since we can't check if the file exist. Pretend that it
367: // doesn't.
368: }
369: }
370: }
371: ArrayList newEntries = new ArrayList(
372: fEntries.length + 1);
373: int projectEntryIndex = -1;
374:
375: for (int i = 0; i < fEntries.length; i++) {
376: IClasspathEntry curr = fEntries[i];
377: if (curr.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
378: if (path.equals(curr.getPath())) {
379: fRootStatus
380: .setError(NewWizardMessages.NewSourceFolderWizardPage_error_AlreadyExisting);
381: return;
382: }
383: if (projPath.equals(curr.getPath())) {
384: projectEntryIndex = i;
385: }
386: }
387: newEntries.add(curr);
388: }
389:
390: IClasspathEntry newEntry = JavaCore
391: .newSourceEntry(path);
392:
393: Set modified = new HashSet();
394: if (fExcludeInOthersFields.isSelected()) {
395: addExclusionPatterns(newEntry, newEntries, modified);
396: IClasspathEntry entry = JavaCore
397: .newSourceEntry(path);
398: insertAtEndOfCategory(entry, newEntries);
399: } else {
400: if (projectEntryIndex != -1) {
401: fIsProjectAsSourceFolder = true;
402: newEntries.set(projectEntryIndex, newEntry);
403: } else {
404: IClasspathEntry entry = JavaCore
405: .newSourceEntry(path);
406: insertAtEndOfCategory(entry, newEntries);
407: }
408: }
409:
410: fNewEntries = (IClasspathEntry[]) newEntries
411: .toArray(new IClasspathEntry[newEntries.size()]);
412: fNewOutputLocation = fOutputLocation;
413:
414: IJavaModelStatus status = JavaConventions
415: .validateClasspath(fCurrJProject, fNewEntries,
416: fNewOutputLocation);
417: if (!status.isOK()) {
418: if (fOutputLocation.equals(projPath)) {
419: fNewOutputLocation = projPath
420: .append(PreferenceConstants
421: .getPreferenceStore()
422: .getString(
423: PreferenceConstants.SRCBIN_BINNAME));
424: IStatus status2 = JavaConventions
425: .validateClasspath(fCurrJProject,
426: fNewEntries, fNewOutputLocation);
427: if (status2.isOK()) {
428: if (fIsProjectAsSourceFolder) {
429: fRootStatus
430: .setInfo(Messages
431: .format(
432: NewWizardMessages.NewSourceFolderWizardPage_warning_ReplaceSFandOL,
433: fNewOutputLocation
434: .makeRelative()
435: .toString()));
436: } else {
437: fRootStatus
438: .setInfo(Messages
439: .format(
440: NewWizardMessages.NewSourceFolderWizardPage_warning_ReplaceOL,
441: fNewOutputLocation
442: .makeRelative()
443: .toString()));
444: }
445: return;
446: }
447: }
448: fRootStatus.setError(status.getMessage());
449: return;
450: } else if (fIsProjectAsSourceFolder) {
451: fRootStatus
452: .setInfo(NewWizardMessages.NewSourceFolderWizardPage_warning_ReplaceSF);
453: return;
454: }
455: if (!modified.isEmpty()) {
456: fRootStatus
457: .setInfo(Messages
458: .format(
459: NewWizardMessages.NewSourceFolderWizardPage_warning_AddedExclusions,
460: String.valueOf(modified
461: .size())));
462: return;
463: }
464: }
465: }
466: }
467:
468: private void insertAtEndOfCategory(IClasspathEntry entry,
469: List entries) {
470: int length = entries.size();
471: IClasspathEntry[] elements = (IClasspathEntry[]) entries
472: .toArray(new IClasspathEntry[length]);
473: int i = 0;
474: while (i < length
475: && elements[i].getEntryKind() != entry.getEntryKind()) {
476: i++;
477: }
478: if (i < length) {
479: i++;
480: while (i < length
481: && elements[i].getEntryKind() == entry
482: .getEntryKind()) {
483: i++;
484: }
485: entries.add(i, entry);
486: return;
487: }
488:
489: switch (entry.getEntryKind()) {
490: case IClasspathEntry.CPE_SOURCE:
491: entries.add(0, entry);
492: break;
493: case IClasspathEntry.CPE_CONTAINER:
494: case IClasspathEntry.CPE_LIBRARY:
495: case IClasspathEntry.CPE_PROJECT:
496: case IClasspathEntry.CPE_VARIABLE:
497: default:
498: entries.add(entry);
499: break;
500: }
501: }
502:
503: private void addExclusionPatterns(IClasspathEntry newEntry,
504: List existing, Set modifiedEntries) {
505: IPath entryPath = newEntry.getPath();
506: for (int i = 0; i < existing.size(); i++) {
507: IClasspathEntry curr = (IClasspathEntry) existing.get(i);
508: IPath currPath = curr.getPath();
509: if (curr.getEntryKind() == IClasspathEntry.CPE_SOURCE
510: && currPath.isPrefixOf(entryPath)) {
511: IPath[] exclusionFilters = curr.getExclusionPatterns();
512: if (!JavaModelUtil.isExcludedPath(entryPath,
513: exclusionFilters)) {
514: IPath pathToExclude = entryPath
515: .removeFirstSegments(
516: currPath.segmentCount())
517: .addTrailingSeparator();
518: IPath[] newExclusionFilters = new IPath[exclusionFilters.length + 1];
519: System.arraycopy(exclusionFilters, 0,
520: newExclusionFilters, 0,
521: exclusionFilters.length);
522: newExclusionFilters[exclusionFilters.length] = pathToExclude;
523:
524: IClasspathEntry updated = JavaCore.newSourceEntry(
525: currPath, newExclusionFilters, curr
526: .getOutputLocation());
527: existing.set(i, updated);
528: modifiedEntries.add(updated);
529: }
530: }
531: }
532: }
533:
534: // ---- creation ----------------
535:
536: public IPackageFragmentRoot getNewPackageFragmentRoot() {
537: return fCreatedRoot;
538: }
539:
540: public IResource getCorrespondingResource() {
541: return fCurrJProject.getProject().getFolder(
542: fRootDialogField.getText());
543: }
544:
545: public void createPackageFragmentRoot(IProgressMonitor monitor)
546: throws CoreException, InterruptedException {
547: if (monitor == null) {
548: monitor = new NullProgressMonitor();
549: }
550: monitor.beginTask(
551: NewWizardMessages.NewSourceFolderWizardPage_operation,
552: 3);
553: try {
554: IPath projPath = fCurrJProject.getProject().getFullPath();
555: if (fOutputLocation.equals(projPath)
556: && !fNewOutputLocation.equals(projPath)) {
557: if (BuildPathsBlock.hasClassfiles(fCurrJProject
558: .getProject())) {
559: if (BuildPathsBlock.getRemoveOldBinariesQuery(
560: getShell()).doQuery(false, projPath)) {
561: BuildPathsBlock
562: .removeOldClassfiles(fCurrJProject
563: .getProject());
564: }
565: }
566: }
567:
568: String relPath = fRootDialogField.getText();
569:
570: IFolder folder = fCurrJProject.getProject().getFolder(
571: relPath);
572: if (!folder.exists()) {
573: CoreUtility.createFolder(folder, true, true,
574: new SubProgressMonitor(monitor, 1));
575: }
576: if (monitor.isCanceled()) {
577: throw new InterruptedException();
578: }
579:
580: fCurrJProject.setRawClasspath(fNewEntries,
581: fNewOutputLocation, new SubProgressMonitor(monitor,
582: 2));
583:
584: fCreatedRoot = fCurrJProject.getPackageFragmentRoot(folder);
585: } finally {
586: monitor.done();
587: }
588: }
589:
590: // ------------- choose dialogs
591:
592: private IFolder chooseFolder(String title, String message,
593: IPath initialPath) {
594: Class[] acceptedClasses = new Class[] { IFolder.class };
595: ISelectionStatusValidator validator = new TypedElementSelectionValidator(
596: acceptedClasses, false);
597: ViewerFilter filter = new TypedViewerFilter(acceptedClasses,
598: null);
599:
600: ILabelProvider lp = new WorkbenchLabelProvider();
601: ITreeContentProvider cp = new WorkbenchContentProvider();
602:
603: IProject currProject = fCurrJProject.getProject();
604:
605: ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(
606: getShell(), lp, cp);
607: dialog.setValidator(validator);
608: dialog.setTitle(title);
609: dialog.setMessage(message);
610: dialog.addFilter(filter);
611: dialog.setInput(currProject);
612: dialog.setComparator(new ResourceComparator(
613: ResourceComparator.NAME));
614: IResource res = currProject.findMember(initialPath);
615: if (res != null) {
616: dialog.setInitialSelection(res);
617: }
618:
619: if (dialog.open() == Window.OK) {
620: return (IFolder) dialog.getFirstResult();
621: }
622: return null;
623: }
624:
625: private IJavaProject chooseProject() {
626: IJavaProject[] projects;
627: try {
628: projects = JavaCore.create(fWorkspaceRoot)
629: .getJavaProjects();
630: } catch (JavaModelException e) {
631: JavaPlugin.log(e);
632: projects = new IJavaProject[0];
633: }
634:
635: ILabelProvider labelProvider = new JavaElementLabelProvider(
636: JavaElementLabelProvider.SHOW_DEFAULT);
637: ElementListSelectionDialog dialog = new ElementListSelectionDialog(
638: getShell(), labelProvider);
639: dialog
640: .setTitle(NewWizardMessages.NewSourceFolderWizardPage_ChooseProjectDialog_title);
641: dialog
642: .setMessage(NewWizardMessages.NewSourceFolderWizardPage_ChooseProjectDialog_description);
643: dialog.setElements(projects);
644: dialog.setInitialSelections(new Object[] { fCurrJProject });
645: dialog.setHelpAvailable(false);
646: if (dialog.open() == Window.OK) {
647: return (IJavaProject) dialog.getFirstResult();
648: }
649: return null;
650: }
651:
652: }
|