Added
Link Here
|
1 |
/******************************************************************************* |
2 |
* Copyright (c) 2004, 2010 IBM Corporation and others. |
3 |
* All rights reserved. This program and the accompanying materials |
4 |
* are made available under the terms of the Eclipse Public License v1.0 |
5 |
* which accompanies this distribution, and is available at |
6 |
* http://www.eclipse.org/legal/epl-v10.html |
7 |
* |
8 |
* Contributors: |
9 |
* IBM Corporation - initial API and implementation |
10 |
* Red Hat, Inc - extensive changes to allow importing of Archive Files |
11 |
* Philippe Ombredanne (pombredanne@nexb.com) |
12 |
* - Bug 101180 [Import/Export] Import Existing Project into Workspace default widget is back button , should be text field |
13 |
* Martin Oberhuber (martin.oberhuber@windriver.com) |
14 |
* - Bug 187318[Wizards] "Import Existing Project" loops forever with cyclic symbolic links |
15 |
* Remy Chi Jian Suen (remy.suen@gmail.com) |
16 |
* - Bug 210568 [Import/Export] [Import/Export] - Refresh button does not update list of projects |
17 |
* Francis Lynch (Wind River) - adapted from standard project import wizard |
18 |
*******************************************************************************/ |
19 |
package org.eclipse.ui.internal.wizards.refreshsnapshot; |
20 |
|
21 |
import java.io.*; |
22 |
import java.lang.reflect.InvocationTargetException; |
23 |
import java.net.URI; |
24 |
import java.util.ArrayList; |
25 |
import java.util.Collection; |
26 |
import java.util.HashSet; |
27 |
import java.util.Iterator; |
28 |
import java.util.List; |
29 |
import java.util.Set; |
30 |
|
31 |
import org.eclipse.core.resources.IProject; |
32 |
import org.eclipse.core.resources.IProjectDescription; |
33 |
import org.eclipse.core.resources.IResource; |
34 |
import org.eclipse.core.resources.IWorkspace; |
35 |
import org.eclipse.core.resources.ResourcesPlugin; |
36 |
import org.eclipse.core.runtime.CoreException; |
37 |
import org.eclipse.core.runtime.IPath; |
38 |
import org.eclipse.core.runtime.IProgressMonitor; |
39 |
import org.eclipse.core.runtime.IStatus; |
40 |
import org.eclipse.core.runtime.OperationCanceledException; |
41 |
import org.eclipse.core.runtime.Path; |
42 |
import org.eclipse.core.runtime.Platform; |
43 |
import org.eclipse.core.runtime.Status; |
44 |
import org.eclipse.core.runtime.SubProgressMonitor; |
45 |
import org.eclipse.jface.dialogs.Dialog; |
46 |
import org.eclipse.jface.dialogs.ErrorDialog; |
47 |
import org.eclipse.jface.dialogs.IDialogConstants; |
48 |
import org.eclipse.jface.dialogs.IDialogSettings; |
49 |
import org.eclipse.jface.dialogs.MessageDialog; |
50 |
import org.eclipse.jface.operation.IRunnableWithProgress; |
51 |
import org.eclipse.jface.viewers.CheckStateChangedEvent; |
52 |
import org.eclipse.jface.viewers.CheckboxTreeViewer; |
53 |
import org.eclipse.jface.viewers.ICheckStateListener; |
54 |
import org.eclipse.jface.viewers.ITreeContentProvider; |
55 |
import org.eclipse.jface.viewers.LabelProvider; |
56 |
import org.eclipse.jface.viewers.Viewer; |
57 |
import org.eclipse.jface.viewers.ViewerComparator; |
58 |
import org.eclipse.jface.wizard.WizardPage; |
59 |
import org.eclipse.osgi.util.NLS; |
60 |
import org.eclipse.swt.SWT; |
61 |
import org.eclipse.swt.events.FocusAdapter; |
62 |
import org.eclipse.swt.events.SelectionAdapter; |
63 |
import org.eclipse.swt.events.SelectionEvent; |
64 |
import org.eclipse.swt.events.TraverseEvent; |
65 |
import org.eclipse.swt.events.TraverseListener; |
66 |
import org.eclipse.swt.layout.GridData; |
67 |
import org.eclipse.swt.layout.GridLayout; |
68 |
import org.eclipse.swt.widgets.Button; |
69 |
import org.eclipse.swt.widgets.Composite; |
70 |
import org.eclipse.swt.widgets.DirectoryDialog; |
71 |
import org.eclipse.swt.widgets.Label; |
72 |
import org.eclipse.swt.widgets.Text; |
73 |
import org.eclipse.ui.actions.WorkspaceModifyOperation; |
74 |
import org.eclipse.ui.dialogs.IOverwriteQuery; |
75 |
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; |
76 |
import org.eclipse.ui.internal.ide.StatusUtil; |
77 |
import org.eclipse.ui.statushandlers.StatusManager; |
78 |
|
79 |
/** |
80 |
* The ProjectRefreshSnapshotImportWizardPage is the page that allows the user to import |
81 |
* projects from a particular location with refresh snapshots. |
82 |
*/ |
83 |
public class ProjectRefreshSnapshotImportWizardPage extends WizardPage implements |
84 |
IOverwriteQuery { |
85 |
|
86 |
/** |
87 |
* The name of the folder containing metadata information for the workspace. |
88 |
*/ |
89 |
public static final String METADATA_FOLDER = ".metadata"; //$NON-NLS-1$ |
90 |
|
91 |
/** |
92 |
* Class declared public only for test suite. |
93 |
* |
94 |
*/ |
95 |
public class ProjectRecord { |
96 |
File projectSystemFile; |
97 |
|
98 |
String projectName; |
99 |
|
100 |
Object parent; |
101 |
|
102 |
int level; |
103 |
|
104 |
IProjectDescription description; |
105 |
|
106 |
/** |
107 |
* Create a record for a project based on the info in the file. |
108 |
* |
109 |
* @param file |
110 |
*/ |
111 |
ProjectRecord(File file) { |
112 |
projectSystemFile = file; |
113 |
setProjectName(); |
114 |
} |
115 |
|
116 |
/** |
117 |
* Set the name of the project based on the projectFile. |
118 |
*/ |
119 |
private void setProjectName() { |
120 |
try { |
121 |
|
122 |
// If we don't have the project name try again |
123 |
if (projectName == null) { |
124 |
IPath path = new Path(projectSystemFile.getPath()); |
125 |
// if the file is in the default location, use the directory |
126 |
// name as the project name |
127 |
if (isDefaultLocation(path)) { |
128 |
projectName = path.segment(path.segmentCount() - 2); |
129 |
description = IDEWorkbenchPlugin.getPluginWorkspace() |
130 |
.newProjectDescription(projectName); |
131 |
} else { |
132 |
description = IDEWorkbenchPlugin.getPluginWorkspace() |
133 |
.loadProjectDescription(path); |
134 |
projectName = description.getName(); |
135 |
} |
136 |
|
137 |
} |
138 |
} catch (CoreException e) { |
139 |
// no good couldn't get the name |
140 |
} |
141 |
} |
142 |
|
143 |
/** |
144 |
* Returns whether the given project description file path is in the |
145 |
* default location for a project |
146 |
* |
147 |
* @param path |
148 |
* The path to examine |
149 |
* @return Whether the given path is the default location for a project |
150 |
*/ |
151 |
private boolean isDefaultLocation(IPath path) { |
152 |
// The project description file must at least be within the project, |
153 |
// which is within the workspace location |
154 |
if (path.segmentCount() < 2) |
155 |
return false; |
156 |
return path.removeLastSegments(2).toFile().equals( |
157 |
Platform.getLocation().toFile()); |
158 |
} |
159 |
|
160 |
/** |
161 |
* Get the name of the project |
162 |
* |
163 |
* @return String |
164 |
*/ |
165 |
public String getProjectName() { |
166 |
return projectName; |
167 |
} |
168 |
|
169 |
/** |
170 |
* Gets the label to be used when rendering this project record in the |
171 |
* UI. |
172 |
* |
173 |
* @return String the label |
174 |
* @since 3.4 |
175 |
*/ |
176 |
public String getProjectLabel() { |
177 |
if (description == null) |
178 |
return projectName; |
179 |
|
180 |
String path = projectSystemFile.getParent(); |
181 |
|
182 |
return NLS |
183 |
.bind( |
184 |
Messages.ProjectRefreshSnapshotImportWizardPage_projectLabel, |
185 |
projectName, path); |
186 |
} |
187 |
} |
188 |
|
189 |
// dialog store id constants |
190 |
private final static String STORE_RECURSE_SUBFOLDERS = "WizardProjectRefreshSnapshotImportPage.STORE__RECURSE_SUBFOLDERS_ID"; //$NON-NLS-1$ |
191 |
|
192 |
private Text directoryPathField; |
193 |
|
194 |
private Text directorySnapshotPathField; |
195 |
|
196 |
private CheckboxTreeViewer projectsList; |
197 |
|
198 |
private Button recurseIntoSubFoldersCheckbox; |
199 |
|
200 |
private boolean recurseIntoSubFolders = false; |
201 |
|
202 |
private ProjectRecord[] selectedProjects = new ProjectRecord[0]; |
203 |
|
204 |
// Keep track of the directory that we browsed to last time |
205 |
// the wizard was invoked. |
206 |
private static String previouslyBrowsedDirectory = ""; //$NON-NLS-1$ |
207 |
|
208 |
private static String previouslyBrowsedSnapshotDirectory = ""; //$NON-NLS-1$ |
209 |
|
210 |
private Button browseDirectoriesButton; |
211 |
|
212 |
private Button browseSnapshotDirectoryButton; |
213 |
|
214 |
private IProject[] wsProjects; |
215 |
|
216 |
// The last selected path to minimize searches |
217 |
private String lastPath; |
218 |
|
219 |
// The last time that the file or folder at the selected path was modified |
220 |
// to minimize searches |
221 |
private long lastModified; |
222 |
|
223 |
/** |
224 |
* Creates a new project creation wizard page. |
225 |
* |
226 |
*/ |
227 |
public ProjectRefreshSnapshotImportWizardPage() { |
228 |
this("refreshSnapshotImportPage"); //$NON-NLS-1$ |
229 |
} |
230 |
|
231 |
/** |
232 |
* Create a new instance of the receiver. |
233 |
* |
234 |
* @param pageName |
235 |
*/ |
236 |
public ProjectRefreshSnapshotImportWizardPage(String pageName) { |
237 |
super(pageName); |
238 |
setPageComplete(false); |
239 |
setTitle(Messages.ProjectRefreshSnapshotImportWizardPage_title); |
240 |
setDescription(Messages.ProjectRefreshSnapshotImportWizardPage_description); |
241 |
} |
242 |
|
243 |
/* |
244 |
* (non-Javadoc) |
245 |
* |
246 |
* @see |
247 |
* org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets |
248 |
* .Composite) |
249 |
*/ |
250 |
public void createControl(Composite parent) { |
251 |
|
252 |
initializeDialogUnits(parent); |
253 |
|
254 |
Composite workArea = new Composite(parent, SWT.NONE); |
255 |
setControl(workArea); |
256 |
|
257 |
workArea.setLayout(new GridLayout()); |
258 |
workArea.setLayoutData(new GridData(GridData.FILL_BOTH |
259 |
| GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL)); |
260 |
|
261 |
createProjectsRoot(workArea); |
262 |
createProjectsList(workArea); |
263 |
createOptionsArea(workArea); |
264 |
createSnapshotArea(workArea); |
265 |
restoreWidgetValues(); |
266 |
Dialog.applyDialogFont(workArea); |
267 |
|
268 |
} |
269 |
|
270 |
private void checkForComplete() { |
271 |
if (projectsList.getCheckedElements().length > 0) { |
272 |
String path = directorySnapshotPathField.getText().trim(); |
273 |
if (path.length() > 0) { |
274 |
File dirpath = new File(path); |
275 |
if (dirpath.exists()) { |
276 |
setPageComplete(true); |
277 |
return; |
278 |
} |
279 |
} |
280 |
} |
281 |
|
282 |
setPageComplete(false); |
283 |
} |
284 |
|
285 |
/** |
286 |
* Create the checkbox list for the found projects. |
287 |
* |
288 |
* @param workArea |
289 |
*/ |
290 |
private void createProjectsList(Composite workArea) { |
291 |
|
292 |
Label title = new Label(workArea, SWT.NONE); |
293 |
title.setText(Messages.ProjectRefreshSnapshotImportWizardPage_selectProject); |
294 |
|
295 |
Composite listComposite = new Composite(workArea, SWT.NONE); |
296 |
GridLayout layout = new GridLayout(); |
297 |
layout.numColumns = 2; |
298 |
layout.marginWidth = 0; |
299 |
layout.makeColumnsEqualWidth = false; |
300 |
listComposite.setLayout(layout); |
301 |
|
302 |
listComposite.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL |
303 |
| GridData.GRAB_VERTICAL | GridData.FILL_BOTH)); |
304 |
|
305 |
projectsList = new CheckboxTreeViewer(listComposite, SWT.BORDER); |
306 |
GridData listData = new GridData(GridData.GRAB_HORIZONTAL |
307 |
| GridData.GRAB_VERTICAL | GridData.FILL_BOTH); |
308 |
listData.heightHint = 100; |
309 |
projectsList.getControl().setLayoutData(listData); |
310 |
|
311 |
projectsList.setContentProvider(new ITreeContentProvider() { |
312 |
|
313 |
/* |
314 |
* (non-Javadoc) |
315 |
* |
316 |
* @see |
317 |
* org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java |
318 |
* .lang.Object) |
319 |
*/ |
320 |
public Object[] getChildren(Object parentElement) { |
321 |
return null; |
322 |
} |
323 |
|
324 |
/* |
325 |
* (non-Javadoc) |
326 |
* |
327 |
* @see |
328 |
* org.eclipse.jface.viewers.IStructuredContentProvider#getElements |
329 |
* (java.lang.Object) |
330 |
*/ |
331 |
public Object[] getElements(Object inputElement) { |
332 |
return getValidProjects(); |
333 |
} |
334 |
|
335 |
/* |
336 |
* (non-Javadoc) |
337 |
* |
338 |
* @see |
339 |
* org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java |
340 |
* .lang.Object) |
341 |
*/ |
342 |
public boolean hasChildren(Object element) { |
343 |
return false; |
344 |
} |
345 |
|
346 |
/* |
347 |
* (non-Javadoc) |
348 |
* |
349 |
* @see |
350 |
* org.eclipse.jface.viewers.ITreeContentProvider#getParent(java |
351 |
* .lang.Object) |
352 |
*/ |
353 |
public Object getParent(Object element) { |
354 |
return null; |
355 |
} |
356 |
|
357 |
/* |
358 |
* (non-Javadoc) |
359 |
* |
360 |
* @see org.eclipse.jface.viewers.IContentProvider#dispose() |
361 |
*/ |
362 |
public void dispose() { |
363 |
|
364 |
} |
365 |
|
366 |
/* |
367 |
* (non-Javadoc) |
368 |
* |
369 |
* @see |
370 |
* org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse |
371 |
* .jface.viewers.Viewer, java.lang.Object, java.lang.Object) |
372 |
*/ |
373 |
public void inputChanged(Viewer viewer, Object oldInput, |
374 |
Object newInput) { |
375 |
} |
376 |
|
377 |
}); |
378 |
|
379 |
projectsList.setLabelProvider(new LabelProvider() { |
380 |
/* |
381 |
* (non-Javadoc) |
382 |
* |
383 |
* @see |
384 |
* org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object) |
385 |
*/ |
386 |
public String getText(Object element) { |
387 |
return ((ProjectRecord) element).getProjectLabel(); |
388 |
} |
389 |
}); |
390 |
|
391 |
projectsList.addCheckStateListener(new ICheckStateListener() { |
392 |
/* |
393 |
* (non-Javadoc) |
394 |
* |
395 |
* @see |
396 |
* org.eclipse.jface.viewers.ICheckStateListener#checkStateChanged |
397 |
* (org.eclipse.jface.viewers.CheckStateChangedEvent) |
398 |
*/ |
399 |
public void checkStateChanged(CheckStateChangedEvent event) { |
400 |
checkForComplete(); |
401 |
} |
402 |
}); |
403 |
|
404 |
projectsList.setInput(this); |
405 |
projectsList.setComparator(new ViewerComparator()); |
406 |
} |
407 |
|
408 |
/** |
409 |
* Create the area to specify the snapshot directory. |
410 |
* |
411 |
* @param workArea |
412 |
*/ |
413 |
private void createSnapshotArea(Composite workArea) { |
414 |
|
415 |
// project specification group |
416 |
Composite projectGroup = new Composite(workArea, SWT.NONE); |
417 |
GridLayout layout = new GridLayout(); |
418 |
layout.numColumns = 3; |
419 |
layout.makeColumnsEqualWidth = false; |
420 |
layout.marginWidth = 0; |
421 |
projectGroup.setLayout(layout); |
422 |
projectGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
423 |
|
424 |
Label title = new Label(projectGroup, SWT.NONE); |
425 |
title.setText(Messages.ProjectRefreshSnapshotImportWizardPage_selectSnapshot); |
426 |
|
427 |
// refresh snapshot directory location entry field |
428 |
this.directorySnapshotPathField = new Text(projectGroup, SWT.BORDER); |
429 |
|
430 |
this.directorySnapshotPathField.setLayoutData(new GridData( |
431 |
GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL)); |
432 |
|
433 |
// browse button |
434 |
browseSnapshotDirectoryButton = new Button(projectGroup, SWT.PUSH); |
435 |
browseSnapshotDirectoryButton |
436 |
.setText(Messages.ProjectRefreshSnapshotImportWizardPage_snapshotBrowse); |
437 |
setButtonLayoutData(browseSnapshotDirectoryButton); |
438 |
|
439 |
browseSnapshotDirectoryButton |
440 |
.addSelectionListener(new SelectionAdapter() { |
441 |
/* |
442 |
* (non-Javadoc) |
443 |
* |
444 |
* @see org.eclipse.swt.events.SelectionAdapter#widgetS |
445 |
* elected(org.eclipse.swt.events.SelectionEvent) |
446 |
*/ |
447 |
public void widgetSelected(SelectionEvent e) { |
448 |
handleLocationSnapshotDirectoryButtonPressed(); |
449 |
} |
450 |
}); |
451 |
|
452 |
directorySnapshotPathField |
453 |
.addTraverseListener(new TraverseListener() { |
454 |
|
455 |
/* |
456 |
* (non-Javadoc) |
457 |
* |
458 |
* @see |
459 |
* org.eclipse.swt.events.TraverseListener#keyTraversed( |
460 |
* org.eclipse.swt.events.TraverseEvent) |
461 |
*/ |
462 |
public void keyTraversed(TraverseEvent e) { |
463 |
if (e.detail == SWT.TRAVERSE_RETURN) { |
464 |
e.doit = false; |
465 |
updateProjectsList(directoryPathField.getText().trim()); |
466 |
checkForComplete(); |
467 |
} |
468 |
} |
469 |
|
470 |
}); |
471 |
|
472 |
directorySnapshotPathField.addFocusListener(new FocusAdapter() { |
473 |
|
474 |
/* |
475 |
* (non-Javadoc) |
476 |
* |
477 |
* @see |
478 |
* org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt |
479 |
* .events.FocusEvent) |
480 |
*/ |
481 |
public void focusLost(org.eclipse.swt.events.FocusEvent e) { |
482 |
updateProjectsList(directoryPathField.getText().trim()); |
483 |
checkForComplete(); |
484 |
} |
485 |
|
486 |
}); |
487 |
|
488 |
} |
489 |
|
490 |
/** |
491 |
* Create the area with the extra options. |
492 |
* |
493 |
* @param workArea |
494 |
*/ |
495 |
private void createOptionsArea(Composite workArea) { |
496 |
Composite optionsGroup = new Composite(workArea, SWT.NONE); |
497 |
optionsGroup.setLayout(new GridLayout()); |
498 |
optionsGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
499 |
|
500 |
recurseIntoSubFoldersCheckbox = new Button(optionsGroup, SWT.CHECK); |
501 |
recurseIntoSubFoldersCheckbox.setText( |
502 |
Messages.ProjectRefreshSnapshotImportWizardPage_recurse); |
503 |
recurseIntoSubFoldersCheckbox.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
504 |
recurseIntoSubFoldersCheckbox.addSelectionListener(new SelectionAdapter() { |
505 |
public void widgetSelected(SelectionEvent e) { |
506 |
recurseIntoSubFolders = recurseIntoSubFoldersCheckbox.getSelection(); |
507 |
lastPath = null; // force update |
508 |
updateProjectsList(directoryPathField.getText().trim()); |
509 |
} |
510 |
}); |
511 |
} |
512 |
/** |
513 |
* Create the area where you select the root directory for the projects. |
514 |
* |
515 |
* @param workArea |
516 |
* Composite |
517 |
*/ |
518 |
private void createProjectsRoot(Composite workArea) { |
519 |
|
520 |
// project specification group |
521 |
Composite projectGroup = new Composite(workArea, SWT.NONE); |
522 |
GridLayout layout = new GridLayout(); |
523 |
layout.numColumns = 3; |
524 |
layout.makeColumnsEqualWidth = false; |
525 |
layout.marginWidth = 0; |
526 |
projectGroup.setLayout(layout); |
527 |
projectGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
528 |
|
529 |
Label dirTitle = new Label(projectGroup, SWT.NONE); |
530 |
dirTitle.setText(Messages.ProjectRefreshSnapshotImportWizardPage_sourceDirectory); |
531 |
|
532 |
// project location entry field |
533 |
this.directoryPathField = new Text(projectGroup, SWT.BORDER); |
534 |
|
535 |
this.directoryPathField.setLayoutData(new GridData( |
536 |
GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL)); |
537 |
|
538 |
// browse button |
539 |
browseDirectoriesButton = new Button(projectGroup, SWT.PUSH); |
540 |
browseDirectoriesButton |
541 |
.setText(Messages.ProjectRefreshSnapshotImportWizardPage_sourceBrowse); |
542 |
setButtonLayoutData(browseDirectoriesButton); |
543 |
|
544 |
browseDirectoriesButton.addSelectionListener(new SelectionAdapter() { |
545 |
/* |
546 |
* (non-Javadoc) |
547 |
* |
548 |
* @see org.eclipse.swt.events.SelectionAdapter#widgetS |
549 |
* elected(org.eclipse.swt.events.SelectionEvent) |
550 |
*/ |
551 |
public void widgetSelected(SelectionEvent e) { |
552 |
handleLocationDirectoryButtonPressed(); |
553 |
} |
554 |
|
555 |
}); |
556 |
|
557 |
directoryPathField.addTraverseListener(new TraverseListener() { |
558 |
|
559 |
/* |
560 |
* (non-Javadoc) |
561 |
* |
562 |
* @see |
563 |
* org.eclipse.swt.events.TraverseListener#keyTraversed(org.eclipse |
564 |
* .swt.events.TraverseEvent) |
565 |
*/ |
566 |
public void keyTraversed(TraverseEvent e) { |
567 |
if (e.detail == SWT.TRAVERSE_RETURN) { |
568 |
e.doit = false; |
569 |
updateProjectsList(directoryPathField.getText().trim()); |
570 |
} |
571 |
} |
572 |
|
573 |
}); |
574 |
|
575 |
directoryPathField.addFocusListener(new FocusAdapter() { |
576 |
|
577 |
/* |
578 |
* (non-Javadoc) |
579 |
* |
580 |
* @see |
581 |
* org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt |
582 |
* .events.FocusEvent) |
583 |
*/ |
584 |
public void focusLost(org.eclipse.swt.events.FocusEvent e) { |
585 |
updateProjectsList(directoryPathField.getText().trim()); |
586 |
} |
587 |
|
588 |
}); |
589 |
} |
590 |
|
591 |
/* |
592 |
* (non-Javadoc) Method declared on IDialogPage. Set the focus on path |
593 |
* fields when page becomes visible. |
594 |
*/ |
595 |
public void setVisible(boolean visible) { |
596 |
super.setVisible(visible); |
597 |
if (visible) { |
598 |
this.directoryPathField.setFocus(); |
599 |
} |
600 |
} |
601 |
|
602 |
/** |
603 |
* Update the list of projects based on path. Method declared public only |
604 |
* for test suite. |
605 |
* |
606 |
* @param path |
607 |
*/ |
608 |
public void updateProjectsList(final String path) { |
609 |
// on an empty path empty selectedProjects |
610 |
if (path == null || path.length() == 0) { |
611 |
setMessage(Messages.ProjectRefreshSnapshotImportWizardPage_selectProjects); |
612 |
selectedProjects = new ProjectRecord[0]; |
613 |
projectsList.refresh(true); |
614 |
projectsList.setCheckedElements(selectedProjects); |
615 |
checkForComplete(); |
616 |
lastPath = path; |
617 |
return; |
618 |
} |
619 |
|
620 |
final File directory = new File(path); |
621 |
long modified = directory.lastModified(); |
622 |
if (path.equals(lastPath) && lastModified == modified) { |
623 |
// since the file/folder was not modified and the path did not |
624 |
// change, no refreshing is required |
625 |
return; |
626 |
} |
627 |
|
628 |
lastPath = path; |
629 |
lastModified = modified; |
630 |
|
631 |
try { |
632 |
getContainer().run(true, true, new IRunnableWithProgress() { |
633 |
|
634 |
/* |
635 |
* (non-Javadoc) |
636 |
* |
637 |
* @see |
638 |
* org.eclipse.jface.operation.IRunnableWithProgress#run(org |
639 |
* .eclipse.core.runtime.IProgressMonitor) |
640 |
*/ |
641 |
public void run(IProgressMonitor monitor) { |
642 |
|
643 |
boolean dirSelected = true; |
644 |
|
645 |
monitor.beginTask( |
646 |
Messages.ProjectRefreshSnapshotImportWizardPage_searching, |
647 |
100); |
648 |
selectedProjects = new ProjectRecord[0]; |
649 |
Collection files = new ArrayList(); |
650 |
monitor.worked(10); |
651 |
|
652 |
File dirpath = new File(path); |
653 |
if (dirpath.exists()) { |
654 |
dirSelected = true; |
655 |
} |
656 |
|
657 |
if (dirSelected && directory.isDirectory()) { |
658 |
|
659 |
if (!collectProjectFilesFromDirectory(files, directory, |
660 |
null, monitor)) { |
661 |
return; |
662 |
} |
663 |
Iterator filesIterator = files.iterator(); |
664 |
selectedProjects = new ProjectRecord[files.size()]; |
665 |
int index = 0; |
666 |
monitor.worked(50); |
667 |
monitor.subTask(Messages.ProjectRefreshSnapshotImportWizardPage_processing); |
668 |
while (filesIterator.hasNext()) { |
669 |
File file = (File) filesIterator.next(); |
670 |
selectedProjects[index] = new ProjectRecord(file); |
671 |
index++; |
672 |
} |
673 |
} else { |
674 |
monitor.worked(60); |
675 |
} |
676 |
monitor.done(); |
677 |
} |
678 |
|
679 |
}); |
680 |
} catch (InvocationTargetException e) { |
681 |
IDEWorkbenchPlugin.log(e.getMessage(), e); |
682 |
} catch (InterruptedException e) { |
683 |
// Nothing to do if the user interrupts. |
684 |
} |
685 |
|
686 |
projectsList.refresh(true); |
687 |
projectsList.setCheckedElements(getValidProjects()); |
688 |
if (getValidProjects().length < selectedProjects.length) { |
689 |
setMessage( |
690 |
Messages.ProjectRefreshSnapshotImportWizardPage_hiddenProjects, |
691 |
WARNING); |
692 |
} else { |
693 |
setMessage(Messages.ProjectRefreshSnapshotImportWizardPage_description); |
694 |
} |
695 |
checkForComplete(); |
696 |
} |
697 |
|
698 |
/** |
699 |
* Display an error dialog with the specified message. |
700 |
* |
701 |
* @param message |
702 |
* the error message |
703 |
*/ |
704 |
protected void displayErrorDialog(String message) { |
705 |
MessageDialog.openError(getContainer().getShell(), |
706 |
getErrorDialogTitle(), message); |
707 |
} |
708 |
|
709 |
/** |
710 |
* Get the title for an error dialog. Subclasses should override. |
711 |
*/ |
712 |
protected String getErrorDialogTitle() { |
713 |
return Messages.ProjectRefreshSnapshotImportWizardPage_internalError; |
714 |
} |
715 |
|
716 |
/** |
717 |
* Get the title for an error dialog. Subclasses should override. |
718 |
*/ |
719 |
protected String getInformationDialogTitle() { |
720 |
return Messages.ProjectRefreshSnapshotImportWizardPage_snapshotError; |
721 |
} |
722 |
|
723 |
/** |
724 |
* Collect the list of .project files that are under directory into files. |
725 |
* To avoid potential performance degradation on slow file systems, by default |
726 |
* only the files in this directory are collected; no recursion into |
727 |
* sub-directories is performed unless the user checks the "recurse into |
728 |
* subfolders" flag. |
729 |
* |
730 |
* @param files |
731 |
* @param directory |
732 |
* @param monitor |
733 |
* The monitor to report to |
734 |
* @return boolean <code>true</code> if the operation was completed. |
735 |
*/ |
736 |
private boolean collectProjectFilesFromDirectory(Collection files, |
737 |
File directory, Set directoriesVisited, IProgressMonitor monitor) { |
738 |
|
739 |
if (monitor.isCanceled()) { |
740 |
return false; |
741 |
} |
742 |
monitor.subTask(NLS.bind( |
743 |
Messages.ProjectRefreshSnapshotImportWizardPage_checking, |
744 |
directory.getPath())); |
745 |
File[] contents = directory.listFiles(); |
746 |
if (contents == null) |
747 |
return false; |
748 |
|
749 |
// Initialize recursion guard for recursive symbolic links |
750 |
if (directoriesVisited == null) { |
751 |
directoriesVisited = new HashSet(); |
752 |
try { |
753 |
directoriesVisited.add(directory.getCanonicalPath()); |
754 |
} catch (IOException exception) { |
755 |
StatusManager.getManager().handle( |
756 |
StatusUtil.newStatus(IStatus.ERROR, exception |
757 |
.getLocalizedMessage(), exception)); |
758 |
} |
759 |
} |
760 |
|
761 |
// first look for project description files |
762 |
final String dotProject = IProjectDescription.DESCRIPTION_FILE_NAME; |
763 |
for (int i = 0; i < contents.length; i++) { |
764 |
File file = contents[i]; |
765 |
if (file.isFile() && file.getName().equals(dotProject)) { |
766 |
files.add(file); |
767 |
// don't search sub-directories since we can't have nested |
768 |
// projects |
769 |
return true; |
770 |
} |
771 |
} |
772 |
if (!recurseIntoSubFolders) |
773 |
return true; |
774 |
// no project description found, so recurse into sub-directories |
775 |
for (int i = 0; i < contents.length; i++) { |
776 |
if (contents[i].isDirectory()) { |
777 |
if (!contents[i].getName().equals(METADATA_FOLDER)) { |
778 |
try { |
779 |
String canonicalPath = contents[i].getCanonicalPath(); |
780 |
if (!directoriesVisited.add(canonicalPath)) { |
781 |
// already been here --> do not recurse |
782 |
continue; |
783 |
} |
784 |
} catch (IOException exception) { |
785 |
StatusManager.getManager().handle( |
786 |
StatusUtil.newStatus(IStatus.ERROR, exception |
787 |
.getLocalizedMessage(), exception)); |
788 |
|
789 |
} |
790 |
collectProjectFilesFromDirectory(files, contents[i], |
791 |
directoriesVisited, monitor); |
792 |
} |
793 |
} |
794 |
} |
795 |
return true; |
796 |
} |
797 |
|
798 |
/** |
799 |
* The browse button has been selected. Select the location. |
800 |
*/ |
801 |
protected void handleLocationDirectoryButtonPressed() { |
802 |
|
803 |
DirectoryDialog dialog = new DirectoryDialog(directoryPathField |
804 |
.getShell()); |
805 |
dialog |
806 |
.setMessage(Messages.ProjectRefreshSnapshotImportWizardPage_browseSource); |
807 |
|
808 |
String dirName = directoryPathField.getText().trim(); |
809 |
if (dirName.length() == 0) { |
810 |
dirName = previouslyBrowsedDirectory; |
811 |
} |
812 |
|
813 |
if (dirName.length() == 0) { |
814 |
dialog.setFilterPath(IDEWorkbenchPlugin.getPluginWorkspace().getRoot() |
815 |
.getLocation().toOSString()); |
816 |
} else { |
817 |
File path = new File(dirName); |
818 |
if (path.exists()) { |
819 |
dialog.setFilterPath(new Path(dirName).toOSString()); |
820 |
} |
821 |
} |
822 |
|
823 |
String selectedDirectory = dialog.open(); |
824 |
if (selectedDirectory != null) { |
825 |
previouslyBrowsedDirectory = selectedDirectory; |
826 |
directoryPathField.setText(previouslyBrowsedDirectory); |
827 |
updateProjectsList(selectedDirectory); |
828 |
} |
829 |
|
830 |
} |
831 |
|
832 |
/** |
833 |
* The browse button has been selected. Select the location. |
834 |
*/ |
835 |
protected void handleLocationSnapshotDirectoryButtonPressed() { |
836 |
|
837 |
DirectoryDialog dialog = new DirectoryDialog( |
838 |
directorySnapshotPathField.getShell()); |
839 |
dialog |
840 |
.setMessage(Messages.ProjectRefreshSnapshotImportWizardPage_browseSnapshot); |
841 |
|
842 |
String dirName = directorySnapshotPathField.getText().trim(); |
843 |
if (dirName.length() == 0) { |
844 |
dirName = previouslyBrowsedSnapshotDirectory; |
845 |
} |
846 |
|
847 |
if (dirName.length() == 0) { |
848 |
dialog.setFilterPath(IDEWorkbenchPlugin.getPluginWorkspace().getRoot() |
849 |
.getLocation().toOSString()); |
850 |
} else { |
851 |
File path = new File(dirName); |
852 |
if (path.exists()) { |
853 |
dialog.setFilterPath(new Path(dirName).toOSString()); |
854 |
} |
855 |
} |
856 |
|
857 |
String selectedDirectory = dialog.open(); |
858 |
if (selectedDirectory != null) { |
859 |
previouslyBrowsedSnapshotDirectory = selectedDirectory; |
860 |
directorySnapshotPathField |
861 |
.setText(previouslyBrowsedSnapshotDirectory); |
862 |
updateProjectsList(selectedDirectory); |
863 |
checkForComplete(); |
864 |
} |
865 |
|
866 |
} |
867 |
|
868 |
/** |
869 |
* Create the selected projects |
870 |
* |
871 |
* @return boolean <code>true</code> if all project creations were |
872 |
* successful. |
873 |
*/ |
874 |
public boolean createProjects() { |
875 |
|
876 |
saveWidgetValues(); |
877 |
|
878 |
final Object[] selected = projectsList.getCheckedElements(); |
879 |
final IPath snapshotPath = new Path(directorySnapshotPathField |
880 |
.getText().trim()); |
881 |
|
882 |
WorkspaceModifyOperation op = new WorkspaceModifyOperation() { |
883 |
protected void execute(IProgressMonitor monitor) |
884 |
throws InvocationTargetException, InterruptedException { |
885 |
try { |
886 |
monitor.beginTask("", selected.length); //$NON-NLS-1$ |
887 |
if (monitor.isCanceled()) { |
888 |
throw new OperationCanceledException(); |
889 |
} |
890 |
for (int i = 0; i < selected.length; i++) { |
891 |
createExistingProject((ProjectRecord) selected[i], |
892 |
snapshotPath, new SubProgressMonitor(monitor, 1)); |
893 |
} |
894 |
} finally { |
895 |
monitor.done(); |
896 |
} |
897 |
} |
898 |
}; |
899 |
// run the new project creation operation |
900 |
try { |
901 |
getContainer().run(true, true, op); |
902 |
} catch (InterruptedException e) { |
903 |
return false; |
904 |
} catch (InvocationTargetException e) { |
905 |
// one of the steps resulted in a core exception |
906 |
Throwable t = e.getTargetException(); |
907 |
String message = Messages.ProjectRefreshSnapshotImportWizardPage_creationProblems; |
908 |
IStatus status; |
909 |
if (t instanceof CoreException) { |
910 |
status = ((CoreException) t).getStatus(); |
911 |
} else { |
912 |
status = new Status(IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH, 1, |
913 |
message, t); |
914 |
} |
915 |
ErrorDialog.openError(getShell(), message, null, status); |
916 |
return false; |
917 |
} |
918 |
return true; |
919 |
} |
920 |
|
921 |
/** |
922 |
* Performs clean-up if the user cancels the wizard without doing anything |
923 |
*/ |
924 |
public void performCancel() { |
925 |
} |
926 |
|
927 |
/** |
928 |
* Create the project described in record. If it is successful return true. |
929 |
* |
930 |
* @param record |
931 |
* @return boolean <code>true</code> if successful |
932 |
* @throws InterruptedException |
933 |
*/ |
934 |
private boolean createExistingProject(final ProjectRecord record, |
935 |
IPath snapshotPath, IProgressMonitor monitor) throws InvocationTargetException, |
936 |
InterruptedException |
937 |
{ |
938 |
String projectName = record.getProjectName(); |
939 |
final IWorkspace workspace = ResourcesPlugin.getWorkspace(); |
940 |
final IProject project = workspace.getRoot().getProject(projectName); |
941 |
if (record.description == null) |
942 |
{ |
943 |
// error case |
944 |
record.description = workspace.newProjectDescription(projectName); |
945 |
IPath locationPath = new Path(record.projectSystemFile |
946 |
.getAbsolutePath()); |
947 |
|
948 |
// If it is under the root use the default location |
949 |
if (Platform.getLocation().isPrefixOf(locationPath)) |
950 |
{ |
951 |
record.description.setLocation(null); |
952 |
} |
953 |
else |
954 |
{ |
955 |
record.description.setLocation(locationPath); |
956 |
} |
957 |
} |
958 |
else |
959 |
{ |
960 |
record.description.setName(projectName); |
961 |
} |
962 |
// load snapshot and open project |
963 |
try |
964 |
{ |
965 |
monitor |
966 |
.beginTask( |
967 |
Messages.ProjectRefreshSnapshotImportWizardPage_createProjectsTask, |
968 |
100); |
969 |
project.create(record.description, new SubProgressMonitor(monitor, |
970 |
30)); |
971 |
IPath zipPath = snapshotPath.append(projectName + "-index.zip"); //$NON-NLS-1$ |
972 |
URI snapshotLocation = org.eclipse.core.filesystem.URIUtil.toURI(zipPath); |
973 |
project.loadSnapshot(IProject.SNAPSHOT_TREE, snapshotLocation, |
974 |
new SubProgressMonitor(monitor, 40)); |
975 |
project.open(IResource.NONE, new SubProgressMonitor(monitor, 30)); |
976 |
} |
977 |
catch (CoreException e) |
978 |
{ |
979 |
throw new InvocationTargetException(e); |
980 |
} |
981 |
finally |
982 |
{ |
983 |
monitor.done(); |
984 |
} |
985 |
|
986 |
return true; |
987 |
} |
988 |
|
989 |
/** |
990 |
* The <code>WizardDataTransfer</code> implementation of this |
991 |
* <code>IOverwriteQuery</code> method asks the user whether the existing |
992 |
* resource at the given path should be overwritten. |
993 |
* |
994 |
* @param pathString |
995 |
* @return the user's reply: one of <code>"YES"</code>, <code>"NO"</code>, |
996 |
* <code>"ALL"</code>, or <code>"CANCEL"</code> |
997 |
*/ |
998 |
public String queryOverwrite(String pathString) { |
999 |
|
1000 |
Path path = new Path(pathString); |
1001 |
|
1002 |
String messageString; |
1003 |
// Break the message up if there is a file name and a directory |
1004 |
// and there are at least 2 segments. |
1005 |
if (path.getFileExtension() == null || path.segmentCount() < 2) { |
1006 |
messageString = NLS.bind( |
1007 |
Messages.ProjectRefreshSnapshotImportWizardPage_overwrite, |
1008 |
pathString); |
1009 |
} else { |
1010 |
messageString = NLS |
1011 |
.bind( |
1012 |
Messages.ProjectRefreshSnapshotImportWizardPage_overwriteInFolder, |
1013 |
path.lastSegment(), path.removeLastSegments(1) |
1014 |
.toOSString()); |
1015 |
} |
1016 |
|
1017 |
final MessageDialog dialog = new MessageDialog(getContainer() |
1018 |
.getShell(), Messages.ProjectRefreshSnapshotImportWizardPage_question, null, |
1019 |
messageString, MessageDialog.QUESTION, new String[] { |
1020 |
IDialogConstants.YES_LABEL, |
1021 |
IDialogConstants.YES_TO_ALL_LABEL, |
1022 |
IDialogConstants.NO_LABEL, |
1023 |
IDialogConstants.NO_TO_ALL_LABEL, |
1024 |
IDialogConstants.CANCEL_LABEL }, 0); |
1025 |
String[] response = new String[] { YES, ALL, NO, NO_ALL, CANCEL }; |
1026 |
// run in syncExec because callback is from an operation, |
1027 |
// which is probably not running in the UI thread. |
1028 |
getControl().getDisplay().syncExec(new Runnable() { |
1029 |
public void run() { |
1030 |
dialog.open(); |
1031 |
} |
1032 |
}); |
1033 |
return dialog.getReturnCode() < 0 ? CANCEL : response[dialog |
1034 |
.getReturnCode()]; |
1035 |
} |
1036 |
|
1037 |
/** |
1038 |
* Method used for test suite. |
1039 |
* |
1040 |
* @return CheckboxTreeViewer the viewer containing all the projects found |
1041 |
*/ |
1042 |
public CheckboxTreeViewer getProjectsList() { |
1043 |
return projectsList; |
1044 |
} |
1045 |
|
1046 |
/** |
1047 |
* Retrieve all the projects in the current workspace. |
1048 |
* |
1049 |
* @return IProject[] array of IProject in the current workspace |
1050 |
*/ |
1051 |
private IProject[] getProjectsInWorkspace() { |
1052 |
if (wsProjects == null) { |
1053 |
wsProjects = IDEWorkbenchPlugin.getPluginWorkspace().getRoot().getProjects(); |
1054 |
} |
1055 |
return wsProjects; |
1056 |
} |
1057 |
|
1058 |
/** |
1059 |
* Get the array of valid project records that can be imported from the |
1060 |
* source workspace or archive, selected by the user. If a project with the |
1061 |
* same name exists in both the source workspace and the current workspace, |
1062 |
* or if no refresh snapshot for the project is found in the snapshot folder, |
1063 |
* it will not appear in the list of projects to import and thus cannot be |
1064 |
* selected for import. |
1065 |
* |
1066 |
* Method declared public for test suite. |
1067 |
* |
1068 |
* @return ProjectRecord[] array of projects that can be imported into the |
1069 |
* workspace |
1070 |
*/ |
1071 |
public ProjectRecord[] getValidProjects() { |
1072 |
List validProjects = new ArrayList(); |
1073 |
for (int i = 0; i < selectedProjects.length; i++) { |
1074 |
String projectName = selectedProjects[i].getProjectName(); |
1075 |
if (!isProjectInWorkspace(projectName)&& hasSnapshot(projectName)) { |
1076 |
validProjects.add(selectedProjects[i]); |
1077 |
} |
1078 |
} |
1079 |
return (ProjectRecord[]) validProjects |
1080 |
.toArray(new ProjectRecord[validProjects.size()]); |
1081 |
} |
1082 |
|
1083 |
/** |
1084 |
* Determine if the project with the given name is in the current workspace. |
1085 |
* |
1086 |
* @param projectName |
1087 |
* String the project name to check |
1088 |
* @return boolean true if the project with the given name is in this |
1089 |
* workspace |
1090 |
*/ |
1091 |
private boolean isProjectInWorkspace(String projectName) { |
1092 |
if (projectName == null) { |
1093 |
return false; |
1094 |
} |
1095 |
IProject[] workspaceProjects = getProjectsInWorkspace(); |
1096 |
for (int i = 0; i < workspaceProjects.length; i++) { |
1097 |
if (projectName.equals(workspaceProjects[i].getName())) { |
1098 |
return true; |
1099 |
} |
1100 |
} |
1101 |
return false; |
1102 |
} |
1103 |
|
1104 |
/** |
1105 |
* Determine if the named project has a refresh snapshot in the current |
1106 |
* snapshot directory. |
1107 |
* @param projectName |
1108 |
* String the project name to check |
1109 |
* @return boolean true if the project with the given name has a refresh |
1110 |
* snapshot in the current snapshot directory |
1111 |
*/ |
1112 |
private boolean hasSnapshot(String projectName) { |
1113 |
if (projectName == null) { |
1114 |
return false; |
1115 |
} |
1116 |
final IPath snapshotPath = new Path(directorySnapshotPathField |
1117 |
.getText().trim()); |
1118 |
IPath zipPath = snapshotPath.append(projectName + "-index.zip"); //$NON-NLS-1$ |
1119 |
return zipPath.toFile().exists(); |
1120 |
} |
1121 |
/** |
1122 |
* Use the dialog store to restore widget values to the values that they |
1123 |
* held last time this wizard was used to completion. |
1124 |
* |
1125 |
* Method declared public only for use of tests. |
1126 |
*/ |
1127 |
public void restoreWidgetValues() { |
1128 |
IDialogSettings settings = getDialogSettings(); |
1129 |
if (settings != null) { |
1130 |
recurseIntoSubFolders = settings.getBoolean(STORE_RECURSE_SUBFOLDERS); |
1131 |
recurseIntoSubFoldersCheckbox.setSelection(recurseIntoSubFolders); |
1132 |
} |
1133 |
} |
1134 |
|
1135 |
/** |
1136 |
* Since Finish was pressed, write widget values to the dialog store so that |
1137 |
* they will persist into the next invocation of this wizard page. |
1138 |
* |
1139 |
* Method declared public only for use of tests. |
1140 |
*/ |
1141 |
public void saveWidgetValues() { |
1142 |
IDialogSettings settings = getDialogSettings(); |
1143 |
if (settings != null) { |
1144 |
settings.put(STORE_RECURSE_SUBFOLDERS, recurseIntoSubFolders); |
1145 |
} |
1146 |
} |
1147 |
|
1148 |
} |