source: release-kits/shared/uninstaller/Uninstaller.java@ 17805

Last change on this file since 17805 was 17805, checked in by oranfry, 15 years ago

the uninstaller now gives output as it goes rather than all in one bang at the end

File size: 16.0 KB
Line 
1import java.util.ResourceBundle;
2import java.awt.*;
3import java.awt.event.*;
4import javax.swing.JFrame;
5import javax.swing.JPanel;
6import javax.swing.JCheckBox;
7import javax.swing.JLabel;
8import javax.swing.JButton;
9import javax.swing.BoxLayout;
10import javax.swing.JTextArea;
11import javax.swing.JScrollPane;
12import javax.swing.border.EmptyBorder;
13import javax.swing.JOptionPane;
14import javax.swing.Box;
15import javax.swing.JDialog;
16import javax.swing.JMenuItem;
17import javax.swing.JPopupMenu;
18
19import java.io.File;
20import java.io.BufferedReader;
21import java.io.FileReader;
22import java.io.FileNotFoundException;
23import java.io.FileWriter;
24import java.io.IOException;
25
26import java.util.regex.Pattern;
27import java.util.regex.Matcher;
28import java.util.ArrayList;
29
30import javax.swing.SwingUtilities;
31
32
33public class Uninstaller {
34
35 public static int SCREEN_WIDTH = 600;
36 public static int SCREEN_HEIGHT = 450;
37
38 public static final ResourceBundle bundle = ResourceBundle.getBundle("resources.LanguagePack");
39
40 public static final File gs2InstallProps = new File("etc/installation.properties");
41 public static final File gs3InstallProps = new File("installation.properties");
42
43 boolean keepCollections = true;
44 //boolean keepModifiedFiles = false;
45 boolean ignoreReadOnlys = false;
46
47 JFrame frame;
48 JCheckBox keepCollectionsCheckbox;
49 //JCheckBox keepModifiedFilesCheckbox;
50
51 //panels
52 JPanel progressPanel;
53 JPanel introPanel;
54
55 //toolbars
56 JPanel initialToolbar;
57 JPanel finishToolbar;
58
59
60 JScrollPane logPane;
61 FollowingJTextArea log;
62 JButton uninstallButton;
63
64 boolean confirmationGiven = false;
65 Thread mainThread = null;
66
67 public static void main( String[] args ) {
68 (new Uninstaller()).go();
69 }
70
71 public void go() {
72
73 mainThread = Thread.currentThread();
74
75 frame = new JFrame();
76 frame.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
77 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
78 frame.setLocation(screenSize.width/2 - frame.getWidth()/2, screenSize.height/2 - frame.getHeight()/2);
79
80 //The panel to introduce and ask for options
81 introPanel = new JPanel(new BorderLayout());
82 JPanel innerPanel = new JPanel();
83 innerPanel.setLayout( new BoxLayout(innerPanel,BoxLayout.Y_AXIS) );
84 innerPanel.setBorder( new EmptyBorder(10, 10, 5, 10) );
85 introPanel.add( BorderLayout.WEST, innerPanel );
86
87 //The panel to be displayed while the uninstall is happening
88 progressPanel = new JPanel(new BorderLayout());
89 log = new FollowingJTextArea();
90 log.setEditable(false);
91 logPane = new JScrollPane(log);
92 logPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
93 logPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
94 progressPanel.add( BorderLayout.NORTH, new JLabel("Progress") );
95 progressPanel.add( BorderLayout.CENTER, logPane );
96
97 //initial toolbar
98 initialToolbar = new JPanel();
99 uninstallButton = new JButton(bundle.getString("uninstaller.uninstall"));
100 uninstallButton.addActionListener( new StartUninstallListener() );
101 JButton cancelButton = new JButton(bundle.getString("uninstaller.cancel"));
102 cancelButton.addActionListener( new CancelListener() );
103 initialToolbar.add(uninstallButton);
104 initialToolbar.add(cancelButton);
105
106 //finish toolbar
107 finishToolbar = new JPanel();
108 JButton finishButton = new JButton(bundle.getString("uninstaller.finish"));
109 finishButton.addActionListener( new FinishListener() );
110 finishToolbar.add( finishButton );
111
112
113 String pwd = (new File(".")).getAbsolutePath();
114 if ( pwd.endsWith("/.") ) {
115 pwd = pwd.substring( 0, pwd.length()-2 );
116 }
117
118 JLabel l;
119
120 l = new JLabel(bundle.getString("uninstaller.will.uninstall.from"));
121 innerPanel.add( l );
122 innerPanel.add( Box.createRigidArea(new Dimension(5,5)) );
123
124 l = new JLabel(" " + pwd);
125 l.setFont( new Font( "Monospaced", Font.BOLD, 14 ) );
126 innerPanel.add( l );
127 innerPanel.add( Box.createRigidArea(new Dimension(5,20)) );
128
129 l = new JLabel(bundle.getString("uninstaller.uninstall.options"));
130 innerPanel.add( l );
131
132 keepCollectionsCheckbox = new JCheckBox(bundle.getString("uninstaller.keep.collections"));
133 keepCollectionsCheckbox.setSelected(true);
134 innerPanel.add( keepCollectionsCheckbox );
135
136 //keepModifiedFilesCheckbox = new JCheckBox("Keep Modified Files");
137 //innerPanel.add( keepModifiedFilesCheckbox );
138
139 frame.setTitle( bundle.getString("uninstaller.greenstone.uninstaller") );
140 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
141
142 //the initial screen
143 frame.getContentPane().add( BorderLayout.CENTER, introPanel );
144 frame.getContentPane().add( BorderLayout.SOUTH, initialToolbar );
145
146 frame.setVisible(true);
147
148 boolean ready = precheck();
149 if ( !ready ) {
150 System.exit(0);
151 }
152
153 //block and wait for signal to do the uninstall
154 do {
155 try {
156 Thread.sleep( Long.MAX_VALUE );
157 } catch ( InterruptedException ie ) {
158 }
159 } while ( !confirmationGiven );
160
161 doUninstall();
162
163 }
164
165 class CancelListener implements ActionListener {
166 public void actionPerformed( ActionEvent e ) {
167 System.exit(0);
168 }
169 }
170
171 class FinishListener implements ActionListener {
172 public void actionPerformed( ActionEvent e ) {
173 System.exit(0);
174 }
175 }
176
177 class StartUninstallListener implements ActionListener {
178 public void actionPerformed( ActionEvent e ) {
179
180 //The dialog to ask "are you sure"
181 Object[] options = { bundle.getString("uninstaller.uninstall"), bundle.getString("uninstaller.cancel") };
182 int n = JOptionPane.showOptionDialog(
183 frame,
184 bundle.getString("uninstaller.are.you.sure"),
185 bundle.getString("uninstaller.confirmation"),
186 JOptionPane.YES_NO_CANCEL_OPTION,
187 JOptionPane.QUESTION_MESSAGE,
188 null,
189 options,
190 options[0]
191 );
192 if ( n == 1 ) {
193 return;
194 }
195
196 keepCollections = keepCollectionsCheckbox.isSelected();
197 //keepModifiedFiles = keepModifiedFilesCheckbox.isSelected();
198
199 //confirm delete of collections
200 if ( !keepCollections ) {
201 options[0] = bundle.getString("uninstaller.continue");
202 options[1] = bundle.getString("uninstaller.cancel");
203 n = JOptionPane.showOptionDialog(
204 frame,
205 bundle.getString("uninstaller.are.you.sure.collections"),
206 bundle.getString("uninstaller.confirmation"),
207 JOptionPane.YES_NO_CANCEL_OPTION,
208 JOptionPane.WARNING_MESSAGE,
209 null,
210 options,
211 options[0]
212 );
213 if ( n == 1 ) {
214 return;
215 }
216 }
217
218
219 introPanel.setVisible( false );
220 frame.getContentPane().remove(introPanel);
221 frame.getContentPane().add( BorderLayout.CENTER, progressPanel );
222
223 initialToolbar.setVisible( false );
224 frame.getContentPane().remove( initialToolbar );
225 frame.getContentPane().add( BorderLayout.SOUTH, finishToolbar);
226
227 confirmationGiven = true;
228 mainThread.interrupt();
229 }
230 }
231
232 /**
233 * Do some checks
234 */
235 public boolean precheck() {
236
237 if ( !gs2InstallProps.exists() && !gs3InstallProps.exists() ) {
238 log( bundle.getString("uninstaller.error.couldnt.find.install.props") + "\n" );
239 JOptionPane.showMessageDialog(frame, bundle.getString("uninstaller.error.couldnt.find.install.props"), bundle.getString("uninstaller.error"), 0);
240 return false;
241 }
242 return true;
243
244 }
245
246 public void log( String s ) {
247 SwingUtilities.invokeLater( new LogAppender( s ) );
248 //log.append( s );
249
250 }
251
252 /**
253 * Does the uninstall
254 */
255 public void doUninstall() {
256
257 File startMenuPath = null;
258
259 //delete the start menu group if present
260
261 if ( gs2InstallProps.exists() ) {
262 String smp = null;
263 try {
264 smp = getPropertyValue( "startmenu.path", gs2InstallProps );
265 } catch ( Exception e ) {}
266 if ( smp != null ) {
267 startMenuPath = new File( smp );
268 }
269 } else if ( gs3InstallProps.exists() ) {
270 String smp = null;
271 try {
272 smp = getPropertyValue( "startmenu.path", gs3InstallProps );
273 } catch ( Exception e ) {}
274 if ( smp != null ) {
275 startMenuPath = new File( smp );
276 }
277 }
278
279 if ( startMenuPath == null ) {
280
281 log( bundle.getString("uninstaller.info.no.startmenu") + "\n" );
282
283 } else {
284 log( "StartMenu Path: " + startMenuPath.getAbsolutePath() + "\n" );
285
286 try {
287 recursiveDelete( startMenuPath, null );
288 } catch ( CancelledException ce ) {
289 log( bundle.getString("uninstaller.cancelled") + "\n" );
290 changeToFinishToolbar();
291 JOptionPane.showMessageDialog(frame, bundle.getString("uninstaller.cancelled"), bundle.getString("uninstaller.complete"), 1);
292 return;
293 }
294 }
295
296 //delete the files
297 try {
298 ArrayList exceptions = new ArrayList();
299
300 //never delete the things we are currently running
301 exceptions.add( new File("bin/search4j.exe") );
302 exceptions.add( new File("bin/search4j") );
303
304 exceptions.add( new File("bin/windows/search4j.exe") );
305 exceptions.add( new File("bin/linux/search4j") );
306 exceptions.add( new File("bin/darwin/search4j") );
307
308 exceptions.add( new File("packages/jre") );
309 exceptions.add( new File("uninst.jar") );
310 exceptions.add( new File("Uninstall.bat") );
311 exceptions.add( new File("Uninstall.sh") );
312
313 if ( keepCollections ) {
314 exceptions.add( new File("web/sites/localsite/collect") );
315 exceptions.add( new File("collect") );
316 }
317
318
319 File cd = null;
320 try {
321 cd = new File( new File(".").getCanonicalPath() );
322 } catch ( Exception e ) {
323 JOptionPane.showMessageDialog(frame, bundle.getString("uninstaller.failed.to.figure.cd"), bundle.getString("uninstaller.error") , 0);
324 System.exit(0);
325 }
326
327 File[] ex = new File[exceptions.size()];
328 for ( int i=0; i<exceptions.size(); i++ ) {
329 ex[i] = (File)exceptions.get(i);
330 }
331
332 recursiveDelete( cd , ex );
333 } catch ( CancelledException ce ) {
334 log( bundle.getString("uninstaller.cancelled") + "\n" );
335 JOptionPane.showMessageDialog(frame, bundle.getString("uninstaller.cancelled"), bundle.getString("uninstaller.complete"), 1);
336 changeToFinishToolbar();
337 return;
338 }
339
340 //create the flag file to indicate the uninstaller wants jre and uninst.jar to be deleted
341 try {
342 (new File("uninst.flag")).createNewFile();
343 } catch (Exception e) {
344 log( bundle.getString("uninstaller.couldnt-create-flagfile") + "\n" );
345 }
346
347 changeToFinishToolbar();
348 log( bundle.getString("uninstaller.finished") );
349 JOptionPane.showMessageDialog(frame, bundle.getString("uninstaller.finished"), bundle.getString("uninstaller.complete"), 1);
350 }
351
352 class LogAppender implements Runnable {
353 String s;
354
355 public LogAppender( String s ) {
356 this.s = s;
357 }
358
359 public void run() {
360 log.append( s );
361 }
362
363 }
364
365 public String getPropertyValue( String propertyName, File file ) throws Exception {
366 String regex = "^" + propertyName.replaceAll("\\.","\\\\.") + "[:=]\\s*(.*)$";
367 Pattern wantedLine = Pattern.compile( regex );
368 BufferedReader in = null;
369 try {
370 in = new BufferedReader(new FileReader( file ));
371 } catch ( Exception e ) {
372 throw new Exception( "Error - couldn't open the properties file " + file );
373 }
374
375 String line, value = null;
376
377 try {
378 boolean found = false;
379 while ( (line = in.readLine()) != null && !found ) {
380
381 Matcher matcher = wantedLine.matcher( line );
382 if ( matcher.matches() ) {
383 //found the property
384 //System.err.println( "found the property" );
385 value = matcher.group(1);
386 value = value.replaceAll( "#.*", "" ).trim();
387 return value;
388 }
389
390 }
391
392 //close the input stream
393 //System.err.println( "close the input stream" );
394 in.close();
395
396 } catch ( Exception e ) {
397 throw new Exception( "Error - couldn't read from the properties file" );
398 }
399 return null;
400
401 }
402
403 public void recursiveDelete( File f, File[] exceptions ) throws CancelledException {
404
405 //log.append( "Processing: " + f.getAbsolutePath() + "\n" );
406
407 // Make sure the file or directory exists
408 if (!f.exists()) {
409 log( Strings.replaceAll( bundle.getString("uninstaller.warning.nonexistent"), "{file}", f.getAbsolutePath() ) + "\n" );
410 return;
411 }
412
413 // if this is an exception, return
414 if ( exceptions != null ) {
415 for ( int i=0; i<exceptions.length; i++ ) {
416 //System.out.println( "Comparing '" + f.getAbsolutePath() + "' with '" + exceptions[i].getAbsolutePath() + "'" );
417 try {
418 if ( f.equals( exceptions[i] ) || f.getCanonicalPath().equals(exceptions[i].getCanonicalPath()) ) {
419 log( Strings.replaceAll( bundle.getString("uninstaller.info.skipping"), "{file}", f.getAbsolutePath() ) + "\n" );
420 return;
421 }
422 } catch ( Exception e ) {
423 System.err.println("ERROR: Failed to resolve a path");
424 return;
425 }
426 }
427 }
428
429 //check existance
430 if ( !f.exists() ) {
431 log( Strings.replaceAll( bundle.getString("uninstaller.error.nonexistent"), "{file}", f.getAbsolutePath() ) + "\n" );
432 return;
433 }
434
435 //if it is a directory, recurse
436 if (f.isDirectory()) {
437 File[] files = f.listFiles();
438 if ( files != null && files.length > 0) {
439 for ( int i=0; i<files.length; i++ ) {
440 try {
441 recursiveDelete( files[i], exceptions );
442 } catch ( CancelledException ce ) {
443 throw new CancelledException();
444 }
445 }
446 }
447 }
448
449 //if this is now an empty directory, or a file, delete it
450 boolean doDelete = true;
451 if ( f.isDirectory() ) {
452 File[] files = f.listFiles();
453 doDelete = ( files == null || files.length == 0 );
454 }
455
456 if ( doDelete ) {
457
458 Object[] options = null;
459 int n = 0;
460 log( Strings.replaceAll( bundle.getString("uninstaller.deleting"), "{file}", f.getAbsolutePath() ) + "\n" );
461
462 if ( !f.delete() ) {
463 log( "*********\n" + Strings.replaceAll( bundle.getString("uninstaller.warning.couldnt.delete"), "{file}", f.getAbsolutePath() ) + "\n*********\n" );
464 return;
465 }
466 }
467
468 }
469
470 class CancelledException extends Exception {}
471
472 public void changeToFinishToolbar() {
473 initialToolbar.setVisible(false);
474 frame.getContentPane().remove(initialToolbar);
475 frame.getContentPane().add( BorderLayout.SOUTH, finishToolbar );
476 finishToolbar.setVisible(true);
477 }
478
479}
480
481class Strings {
482 static String replaceAll( String s, String nugget, String replacement ) {
483 StringBuffer string = new StringBuffer(s);
484 StringBuffer r = new StringBuffer();
485
486 int io = 0;
487 while ( (io=string.toString().indexOf(nugget)) != -1 ) {
488 r.append( string.toString().substring( 0, io ) );
489 r.append( replacement );
490 string.delete( 0, io + nugget.length() );
491 }
492 r.append( string.toString() );
493 return r.toString();
494 }
495}
496
497class FollowingJTextArea extends JTextArea {
498
499 private boolean follow = true;
500
501 public FollowingJTextArea() {
502 jInit();
503 }
504
505
506 private void jInit(){
507 final JPopupMenu popUp = getPopupMenu();
508 this.add(popUp);
509 this.addMouseListener(new MouseAdapter(){
510 public void mouseClicked(MouseEvent e) {
511 if (e.getButton() == e.BUTTON3) {
512 popUp.show(FollowingJTextArea.this,e.getX(),e.getY());
513 }
514 }
515 });
516 }
517
518 public boolean isFollow() {
519 return follow;
520 }
521 public void setFollow(boolean follow) {
522 this.follow = follow;
523 }
524
525 private void scrollToEnd(){
526 setCaretPosition(getDocument().getLength());
527 }
528 private void toggleFollow(){
529 setFollow(!isFollow());
530 }
531
532 /**
533 * Appends the given text to the end of the document.
534 *
535 * @param str the text to insert
536 * @todo Implement this javax.swing.JTextArea method
537 */
538 public void append(String str) {
539 super.append(str);
540 if(follow)scrollToEnd();
541 }
542 private JPopupMenu getPopupMenu() {
543 JPopupMenu contextMenu = new JPopupMenu("Options");
544
545 JMenuItem toggleFollowMenu = new JMenuItem("Toggle Follow");
546 toggleFollowMenu.addActionListener(new ActionListener() {
547 public void actionPerformed(ActionEvent e) {
548 toggleFollow();
549 }
550 });
551 contextMenu.add(toggleFollowMenu);
552
553 JMenuItem jumpToEndMenu = new JMenuItem("Jump To End");
554 jumpToEndMenu.addActionListener(new ActionListener() {
555 public void actionPerformed(ActionEvent e) {
556 setCaretPosition(getDocument().getLength());
557 }
558 });
559 contextMenu.add(toggleFollowMenu);
560
561 JMenuItem clearTextMenu = new JMenuItem("Clear Text");
562 clearTextMenu.addActionListener(new ActionListener() {
563 public void actionPerformed(ActionEvent e) {
564 setText("");
565 }
566 });
567 contextMenu.add(clearTextMenu);
568 return contextMenu;
569 }
570}
Note: See TracBrowser for help on using the repository browser.