1    	package acl2s.plugin.dialogs;
2    	
3    	import java.io.File;
4    	import java.io.FilenameFilter;
5    	import java.lang.reflect.InvocationTargetException;
6    	import java.util.ArrayList;
7    	import java.util.Arrays;
8    	import java.util.LinkedList;
9    	import java.util.List;
10   	
11   	import org.eclipse.core.runtime.IProgressMonitor;
12   	import org.eclipse.jface.dialogs.ProgressMonitorDialog;
13   	import org.eclipse.jface.operation.IRunnableWithProgress;
14   	import org.eclipse.swt.SWT;
15   	import org.eclipse.swt.events.SelectionEvent;
16   	import org.eclipse.swt.events.SelectionListener;
17   	import org.eclipse.swt.graphics.Rectangle;
18   	import org.eclipse.swt.layout.GridData;
19   	import org.eclipse.swt.layout.GridLayout;
20   	import org.eclipse.swt.widgets.Button;
21   	import org.eclipse.swt.widgets.Display;
22   	import org.eclipse.swt.widgets.Group;
23   	import org.eclipse.swt.widgets.Label;
24   	import org.eclipse.swt.widgets.Shell;
25   	import org.peterd.util.Misc;
26   	
27   	import acl2s.plugin.Acl2sPlugin;
28   	import acl2s.plugin.prefs.Acl2Prefs;
29   	
30   	public class RemoveOldStuffDialog implements SelectionListener {
31   		protected static class OldStuff {
32   			public OldStuff(File base, String desc) {
33   				this.base = base.getAbsoluteFile();
34   				this.desc = desc;
35   			}
36   			
37   			public final File base;
38   			public final String desc;
39   			
40   			public boolean equals(Object obj) {
41   				if (!(obj instanceof OldStuff)) return false;
42   				OldStuff that = (OldStuff) obj;
43   				return this.base.equals(that.base);
44   			}
45   			
46   			public int hashCode() {
47   				return base.hashCode();
48   			}
49   			
50   			
51   			private int fileCount = 0;
52   			
53   			public int countFiles() {
54   				if (fileCount == 0) {
55   					fileCount = countFiles(base);
56   				}
57   				return fileCount;
58   			}
59   			
60   			public static int countFiles(File f) {
61   				if (f.isDirectory()) {
62   					int count = 1;
63   					for (File f2 : f.listFiles()) {
64   						count += countFiles(f2);
65   					}
66   					return count;
67   				} else {
68   					return 1;
69   				}
70   			}
71   			
72   			
73   			private long totalSize = 0;
74   			
75   			public long totalSize() {
76   				if (totalSize == 0) {
77   					totalSize = totalSize(base);
78   				}
79   				return totalSize;
80   			}
81   			
82   			public static long totalSize(File f) {
83   				if (f.isDirectory()) {
84   					long size = 4096; // roughly
85   					for (File f2 : f.listFiles()) {
86   						size += totalSize(f2);
87   					}
88   					return size;
89   				} else {
90   					return f.length();
91   				}
92   			}
93   			
94   			
95   			public void remove(IProgressMonitor m) throws InterruptedException {
96   				removeFiles(base,m);
97   			}
98   			
99   			public static boolean removeFiles(File f, IProgressMonitor m) throws InterruptedException {
Event deref: Dereferencing "m".
Also see events: [already_used]
At conditional (1): (!java.lang.Thread.interrupted()): Taking true branch.
At conditional (2): m.isCanceled(): Taking false branch.
100  				if (Thread.interrupted() || m.isCanceled()) throw new InterruptedException();
At conditional (3): f.isDirectory(): Taking false branch.
101  				if (f.isDirectory()) {
102  					for (File f2 : f.listFiles()) {
103  						removeFiles(f2, m);
104  					}
105  				}
106  				boolean b = f.delete();
Event already_used: "m" was already used as non-null.
Also see events: [deref]
At conditional (4): (m != null): Taking false branch.
107  				if (m != null) m.worked(1);
108  				return b;
109  			}
110  			
111  			private String str = null;
112  			
113  			public String toString() {
114  				if (str == null) {
115  					int count = countFiles();
116  					StringBuilder b = new StringBuilder(base.getAbsolutePath().length() + 80);
117  					b.append(base.getAbsolutePath());
118  					b.append("\n");
119  					if (desc != null) {
120  						b.append(desc);
121  						b.append("\n");
122  					}
123  					if (count > 1) {
124  						b.append(countFiles());
125  						b.append(" files");
126  						b.append("\n");
127  					}
128  					long size = totalSize();
129  					if (size < 10000) {
130  						b.append(size);
131  						b.append(" bytes");
132  					} else if (size < 10240000) {
133  						b.append((size + 512) / 1024);
134  						b.append(" KB");
135  					} else {
136  						b.append((size / 1024 + 512) / 1024);
137  						b.append(" MB");
138  					}
139  					str = b.toString();
140  				}
141  				return str;
142  			}
143  		}
144  		
145  		/* This is really old now.  No sense in checking. */
146  		/*
147  		static final String[] oldHomeImageFilenames = {
148  			"acl2s.exe",
149  			"acl2s.image",
150  			"acl2s-sbcl.exe",
151  			"acl2s-dppccl.exe",
152  			"acl2s-dx86cl64.exe",
153  			"hiddencon.exe",
154  			"sendbreak.exe",
155  			"sendctrlc.exe"
156  		};
157  		*/
158  		
159  		static class UnverFilter implements FilenameFilter {
160  			final String basePlus;
161  			final int len;
162  			
163  			public UnverFilter(String base) {
164  				this.basePlus = base.toLowerCase() + "_";
165  				this.len = this.basePlus.length();
166  			}
167  			
168  			public boolean accept(File dir, String name) {
169  				return name.length() > len &&
170  					   name.toLowerCase().startsWith(basePlus) &&
171  				       Character.isDigit(name.charAt(len));
172  			}
173  		}
174  		
175  		private static final File acl2sDir = Acl2sPlugin.getAcl2sBundleDir();
176  		private static final File hooksDir = Acl2sPlugin.getAcl2sHooksDir();
177  		private static final File imageDir = Acl2Prefs.getAcl2ImageDir();
178  		
179  		private static void addAllButNewest(File[] files, ArrayList<OldStuff> v, String desc) {
180  			if (files == null || files.length <= 1) return;
181  			Arrays.sort(files);
182  			for (int i = 0; i < files.length - 1; i++) {
183  				File f = files[i];
184  				
185  				if (Misc.equal(f, acl2sDir) ||
186  					Misc.equal(f, hooksDir) ||
187  					Misc.equal(f, imageDir)) continue; // don't remove current ones
188  				
189  				v.add(new OldStuff(files[i], desc));
190  			}
191  		}
192  		
193  		protected static OldStuff[] getOldStuff() {
194  			ArrayList<OldStuff> v = new ArrayList<OldStuff>();
195  			
196  			/* This is really old now.  No sense in checking. */
197  			/*
198  			File home = new File(System.getProperty("user.home"));
199  			for (String name : oldHomeImageFilenames) {
200  				File f = new File(home,name);
201  				if (f.exists()) {
202  					v.add(new OldStuff(f,"Likely from old ACL2 image downloaded by old ACL2s"));
203  				}
204  			}
205  			*/
206  			
207  			try {
208  				File pluginsDir = acl2sDir.getParentFile();
209  				File featuresDir = new File(pluginsDir.getParentFile(), "features");
210  				
211  				if (featuresDir.isDirectory()) {
212  					for (File f : pluginsDir.listFiles(new UnverFilter("a2s"))) {
213  						v.add(new OldStuff(f, "Old ACL2s plugin"));
214  					}
215  					for (File f : featuresDir.listFiles(new UnverFilter("a2s"))) {
216  						v.add(new OldStuff(f, "Old ACL2s feature"));
217  					}
218  	
219  					addAllButNewest(pluginsDir.listFiles(new UnverFilter("acl2s")),
220  							v, "Old ACL2s plugin");
221  					addAllButNewest(featuresDir.listFiles(new UnverFilter("acl2s")),
222  							v, "Old ACL2s feature");
223  	
224  					addAllButNewest(pluginsDir.listFiles(new UnverFilter("acl2s_hooks")),
225  							v, "Old ACL2s hooks plugin");
226  	
227  					addAllButNewest(pluginsDir.listFiles(new UnverFilter("acl2s_modes")),
228  							v, "Old ACL2s modes plugin");
229  	
230  					addAllButNewest(pluginsDir.listFiles(new UnverFilter(Acl2Prefs.acl2BundleName)),
231  							v, "Old ACL2 image plugin");
232  					addAllButNewest(featuresDir.listFiles(new UnverFilter(Acl2Prefs.acl2BundleName)),
233  							v, "Old ACL2 image feature");
234  				}
235  			} catch (Exception e) {
236  				Acl2sPlugin.logWarning("Error while looking for old stuff", e);
237  			}
238  	
239  			return v.toArray(new OldStuff[v.size()]);
240  		}
241  		
242  		public static void go(Shell parent) {
243  			OldStuff[] oldStuff = getOldStuff();
244  			if (oldStuff.length > 0) {
245  				RemoveOldStuffDialog d = new RemoveOldStuffDialog(parent, oldStuff);
246  				final List<OldStuff> lst = d.open();
247  				if (lst.size() > 0) {
248  					try {
249  						IRunnableWithProgress op = new IRunnableWithProgress() {
250  							public void run(IProgressMonitor monitor)
251  							throws InterruptedException {
252  								int totalWork = 0;
253  								for (OldStuff o : lst) {
254  									totalWork += o.countFiles();
255  								}
256  								monitor.beginTask("Removing old ACL2s files", totalWork);
257  	
258  								for (OldStuff o : lst) {
259  									o.remove(monitor);
260  								}
261  							}
262  						};
263  						new ProgressMonitorDialog(parent).run(true, true, op);
264  					} catch (InvocationTargetException e) {
265  						// shouldn't happen
266  					} catch (InterruptedException e) {
267  						// oh well
268  					}
269  				}
270  			}
271  		}
272  		
273  		protected final Shell parent;
274  		protected final int style;
275  		protected final String text;
276  		protected final Display display;
277  		
278  		protected final OldStuff[] actions;
279  		protected final List<OldStuff> chosenActions = new LinkedList<OldStuff>();
280  		protected Shell sh;
281  		
282  		protected Button[] actionButtons;
283  	
284  		protected Button okButton;
285  		
286  		public RemoveOldStuffDialog(Shell parent, OldStuff[] actions) {
287  			this.parent = parent;
288  			this.actions = actions;
289  			
290  			this.display = parent == null ? Acl2sPlugin.getDisplay() : parent.getDisplay();
291  			this.text = "Select old ACL2s files/versions to remove";
292  			this.style = SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM;
293  		}
294  	
295  		public List<OldStuff> open() {
296  			sh = new Shell(parent, style);
297  			sh.setText(text);
298  			sh.setLayout(new GridLayout(1,true));
299  			
300  			GridData gd;
301  					
302  			Label l = new Label(sh, SWT.WRAP);
303  			l.setText("The following old ACL2s components were found on your system.  If you would like to remove them to free the space, select them below.");
304  			gd = new GridData();
305  			gd.horizontalAlignment = SWT.FILL;
306  			//gd.horizontalSpan = 2;
307  			l.setLayoutData(gd);
308  	
309  			Group modeGroup = new Group(sh, 0);
310  			//modeGroup.setText("Select a mode for " + src + ":");
311  			gd = new GridData();
312  			gd.horizontalAlignment = SWT.FILL;
313  	
314  			modeGroup.setLayoutData(gd);
315  			modeGroup.setLayout(new GridLayout(2,false));
316  			actionButtons = new Button[actions.length];
317  			for (int i = 0; i < actionButtons.length; i++) {
318  				actionButtons[i] = new Button(modeGroup, SWT.CHECK);
319  				
320  				l = new Label(modeGroup,0);
321  				l.setText(actions[i].toString());
322  				gd = new GridData();
323  				gd.horizontalAlignment = SWT.FILL;
324  				l.setLayoutData(gd);
325  				
326  				//actionButtons[i].setText();
327  				//actionButtons[i].setEnabled(true);
328  				//actionButtons[i].setSelection(chosenActions.contains(actions[i]));
329  			}
330  	
331  			okButton = new Button(sh, SWT.PUSH);
332  			okButton.setText("OK");
333  			gd = new GridData(GridData.FILL_HORIZONTAL);
334  			okButton.setLayoutData(gd);
335  			okButton.addSelectionListener(this);
336  			
337  			/*
338  			Label l = new Label(sh,0);
339  			l.setText("Note: Any change will take effect when session is restarted.");
340  			gd = new GridData(GridData.FILL_HORIZONTAL);
341  			gd.horizontalSpan = 2;
342  			l.setLayoutData(gd);
343  			*/
344  			
345  			sh.pack();
346  	
347  			Rectangle bounds = parent == null ? display.getBounds() : parent.getBounds();
348  			Rectangle rect = sh.getBounds ();
349  			int x = bounds.x + (bounds.width - rect.width) / 2;
350  			int y = bounds.y + (bounds.height - rect.height) / 2;
351  			sh.setLocation (x, y);
352  			
353  			sh.open();
354  			
355  			while (!sh.isDisposed()) {
356  				if (!display.readAndDispatch()) {
357  					display.sleep();
358  				}
359  			}
360  			return chosenActions;
361  		}
362  	
363  		public void widgetSelected(SelectionEvent e) {
364  			if (e.getSource() == okButton) {
365  				chosenActions.clear();
366  				for (int i = 0; i < actionButtons.length; i++) {
367  					if (actionButtons[i].getSelection()) {
368  						chosenActions.add(actions[i]);
369  					}
370  				}
371  			}
372  			sh.close();
373  		}
374  	
375  		public void widgetDefaultSelected(SelectionEvent e) { }
376  	}