-
Notifications
You must be signed in to change notification settings - Fork 4
/
PickWorkspaceDialog.java
370 lines (325 loc) · 13.4 KB
/
PickWorkspaceDialog.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
/*******************************************************************************************************
*
* PickWorkspaceDialog.java, in msi.gama.application, is part of the source code of the GAMA modeling and simulation
* platform (v.1.8.2).
*
* (c) 2007-2021 UMI 209 UMMISCO IRD/SU & Partners (IRIT, MIAT, TLU, CTU)
*
* Visit https://github.com/gama-platform/gama for license information and contacts.
*
********************************************************************************************************/
package msi.gama.application.workspace;
// import java.awt.GridLayout;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
/**
* Dialog that lets/forces a user to enter/select a workspace that will be used when saving all configuration files and
* settings. This dialog is shown at startup of the GUI just after the splash screen has shown. Inspired by
* http://hexapixel.com/2009/01/12/rcp-workspaces
*/
public class PickWorkspaceDialog extends TitleAreaDialog {
/*
* This are our preferences we will be using as the IPreferenceStore is not available yet
*/
// FIX: Removed the static reference in case it was causing trouble. Issue
// 240.
// static Preferences preferences = Preferences.userRoot().node("gama");
/** The Constant strMsg. */
/* Various dialog messages */
private static final String strMsg =
"Your workspace is where settings and files of your Gama models will be stored.";
/** The Constant strInfo. */
private static final String strInfo = "Please select a directory that will be the workspace root";
/** The Constant strError. */
private static final String strError = "You must set a directory";
/** The workspace path combo. */
/* Our controls */
protected Combo workspacePathCombo;
/** The last used workspaces. */
protected List<String> lastUsedWorkspaces;
/** The remember workspace button. */
protected Button rememberWorkspaceButton;
/** The Constant splitChar. */
/* Used as separator when we save the last used workspace locations */
private static final String splitChar = "#";
/** The Constant maxHistory. */
/* Max number of entries in the history box */
private static final int maxHistory = 20;
/** The cloning. */
/* Whatever the user picks ends up on this variable */
private boolean cloning = false;
/**
* Creates a new workspace dialog with a specific image as title-area image.
*
* @param switchWorkspace
* true if we're using this dialog as a switch workspace dialog
* @param wizardImage
* Image to show
*/
public PickWorkspaceDialog() {
super(Display.getDefault().getActiveShell());
}
@Override
protected void configureShell(final Shell newShell) {
super.configureShell(newShell);
newShell.setText("GAMA Models Workspace");
}
@Override
protected Control createDialogArea(final Composite parent) {
setTitle("Choose a Workspace to store your models, settings, etc.");
setMessage(strMsg);
try {
final Composite inner = new Composite(parent, SWT.NONE);
final GridLayout l = new GridLayout(4, false);
// double[][] layout =
// new double[][] {
// { 5, LatticeConstants.PREFERRED, 5, 250, 5,
// LatticeConstants.PREFERRED, 5 },
// { 5, LatticeConstants.PREFERRED, 5, LatticeConstants.PREFERRED,
// 40 } };
inner.setLayout(l);
inner.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, true));
/* Label on the left */
final CLabel label = new CLabel(inner, SWT.NONE);
label.setText("GAMA Workspace");
label.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
/* Combo in the middle */
workspacePathCombo = new Combo(inner, SWT.BORDER);
final GridData data = new GridData(SWT.LEFT, SWT.CENTER, true, false);
data.widthHint = 200;
workspacePathCombo.setLayoutData(data);
final String wsRoot = WorkspacePreferences.getLastSetWorkspaceDirectory();
workspacePathCombo.setText(wsRoot);
/* Checkbox below */
rememberWorkspaceButton = new Button(inner, SWT.CHECK);
rememberWorkspaceButton.setText("Remember");
rememberWorkspaceButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
rememberWorkspaceButton.setSelection(WorkspacePreferences.isRememberWorkspace());
final String lastUsed = WorkspacePreferences.getLastUsedWorkspaces();
lastUsedWorkspaces = new ArrayList<>();
if (lastUsed != null) {
final String[] all = lastUsed.split(splitChar);
Collections.addAll(lastUsedWorkspaces, all);
}
for (final String last : lastUsedWorkspaces) { workspacePathCombo.add(last); }
/* Browse button on the right */
final Button browse = new Button(inner, SWT.PUSH);
browse.setText("Browse...");
browse.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
browse.addListener(SWT.Selection, event -> {
final DirectoryDialog dd = new DirectoryDialog(getParentShell());
dd.setText("Select Workspace Root");
dd.setMessage(strInfo);
dd.setFilterPath(workspacePathCombo.getText());
final String pick = dd.open();
if (pick == null) {
if (workspacePathCombo.getText().length() == 0) { setMessage(strError, IMessageProvider.ERROR); }
} else {
setMessage(strMsg);
workspacePathCombo.setText(pick);
}
});
return inner;
} catch (final RuntimeException err) {
err.printStackTrace();
return null;
}
}
/**
* Returns whatever path the user selected in the dialog.
*
* @return Path
*/
public String getSelectedWorkspaceLocation() { return WorkspacePreferences.getSelectedWorkspaceRootLocation(); }
@Override
protected void createButtonsForButtonBar(final Composite parent) {
/* Clone workspace needs a lot of checks */
final Button clone = createButton(parent, IDialogConstants.IGNORE_ID, "Clone existing workspace", false);
clone.addListener(SWT.Selection, arg0 -> cloneCurrentWorkspace());
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
}
/**
* Copy one absolute path over another
*
* @param source
* the source
* @param t
* the t
* @param override
* the override
* @throws IOException
* Signals that an I/O exception has occurred.
*/
static void copy(final File src, final File dest) throws IOException {
/* Check to ensure that the source is valid... */
Path source = src.toPath();
Path target = dest.toPath();
if (Files.notExists(source)) throw new IOException("Can not find: " + source);
if (!Files.isReadable(source)) throw new IOException("Cannot read: " + source);
if (source.startsWith(target) || target.startsWith(source)) throw new IOException(
"Source (" + source + ") and destination (" + target + ") must be separate directories");
Files.walkFileTree(source, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs)
throws IOException {
if (dir.toString().contains("org.eclipse") && !"org.eclipse.core.resources".equals(dir.toString()))
return FileVisitResult.SKIP_SUBTREE;
Files.createDirectories(target.resolve(source.relativize(dir)));
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
Files.copy(file, target.resolve(source.relativize(file)), LinkOption.NOFOLLOW_LINKS,
StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING);
return FileVisitResult.CONTINUE;
}
});
}
/**
* Clone current workspace.
*/
protected void cloneCurrentWorkspace() {
final String currentLocation = WorkspacePreferences.getLastSetWorkspaceDirectory();
if (currentLocation == null || currentLocation.isEmpty()) {
MessageDialog.openError(Display.getDefault().getActiveShell(), "Error",
"No current workspace exists. Can only clone from an existing workspace");
return;
}
final String newLocation = workspacePathCombo.getText();
// Fixes Issue #2848
if (newLocation.startsWith(currentLocation)) {
MessageDialog.openError(Display.getDefault().getActiveShell(), "Error",
"The path entered is either that of the current wokspace or of a subdirectory of it. Neither can be used as a destination.");
return;
}
cloning = true;
try {
okPressed();
} finally {
cloning = false;
}
}
@Override
protected void okPressed() {
final String str = workspacePathCombo.getText();
// scope.getGui().debug("Directory to create " + str);
if (str.length() == 0) {
setMessage(strError, IMessageProvider.ERROR);
return;
}
final String ret = WorkspacePreferences.checkWorkspaceDirectory(str, true, true, cloning);
if (ret != null) {
setMessage(ret, IMessageProvider.ERROR);
return;
}
// scope.getGui().debug("Directory to create (after check " + str);
/* Save it so we can show it in combo later */
lastUsedWorkspaces.remove(str);
if (!lastUsedWorkspaces.contains(str)) { lastUsedWorkspaces.add(0, str); }
/* Deal with the max history */
if (lastUsedWorkspaces.size() > maxHistory) {
final List<String> remove = new ArrayList<>();
for (int i = maxHistory; i < lastUsedWorkspaces.size(); i++) { remove.add(lastUsedWorkspaces.get(i)); }
lastUsedWorkspaces.removeAll(remove);
}
/* Create a string concatenation of all our last used workspaces */
final StringBuilder buf = new StringBuilder();
for (int i = 0; i < lastUsedWorkspaces.size(); i++) {
buf.append(lastUsedWorkspaces.get(i));
if (i != lastUsedWorkspaces.size() - 1) { buf.append(splitChar); }
}
/* Save them onto our preferences */
WorkspacePreferences.isRememberWorkspace(rememberWorkspaceButton.getSelection());
WorkspacePreferences.setLastUsedWorkspaces(buf.toString());
/* Now create it */
final boolean ok = checkAndCreateWorkspaceRoot(str);
if (!ok) {
// scope.getGui().debug("Problem creating " + str);
setMessage("No workspace could be created at location " + str + ", please check the error log");
return;
}
/* Here we set the location so that we can later fetch it again */
WorkspacePreferences.setSelectedWorkspaceRootLocation(str);
/* And on our preferences as well */
// scope.getGui().debug("Writing " + str + " in the preferences");
if (cloning) {
final String previousLocation = WorkspacePreferences.getLastSetWorkspaceDirectory();
File workspaceDirectory = new File(previousLocation);
if (!workspaceDirectory.exists() || previousLocation.equals(str)) {
final DirectoryDialog dialog = new DirectoryDialog(getShell(), SWT.OPEN);
dialog.setText("Choose an existing workspace");
final String result = dialog.open();
if (result != null) {
workspaceDirectory = new File(result);
} else {
workspaceDirectory = null;
}
}
if (workspaceDirectory != null) {
final File targetDirectory = new File(str);
try {
copy(workspaceDirectory, targetDirectory);
// WorkspacePreferences.setApplyPrefs(true);
} catch (final Exception err) {
MessageDialog.openError(Display.getDefault().getActiveShell(), "Error",
"There was an error cloning the workspace: " + err.getMessage());
return;
}
}
}
WorkspacePreferences.setLastSetWorkspaceDirectory(str);
super.okPressed();
}
/**
* Checks to see if a workspace exists at a given directory string, and if not, creates it. Also puts our
* identifying file inside that workspace.
*
* @param wsRoot
* Workspace root directory as string
* @return true if all checks and creations succeeded, false if there was a problem
*/
public static boolean checkAndCreateWorkspaceRoot(final String wsRoot) {
try {
final File fRoot = new File(wsRoot);
if (!fRoot.exists()) // scope.getGui().debug("Folder " + wsRoot + " does not exist");
return false;
File dotFile = new File(wsRoot + File.separator + WorkspacePreferences.WORKSPACE_IDENTIFIER);
if (!dotFile.exists()) {
final boolean created = dotFile.createNewFile();
if (!created) return false;
dotFile = new File(wsRoot + File.separator + WorkspacePreferences.getModelIdentifier());
dotFile.createNewFile();
}
return true;
} catch (final Exception err) {
err.printStackTrace();
return false;
}
}
}