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