0

I have a long running operation such as copying a large zip file to a temp directory, extracting it and then copying it's contents to a destination path. I also show a progress bar while the operation is in progress.

I am supposed to implement this in a standalone SWT UI which is a Java Project(non Eclipse/RCP).

I understand that you need to use a separate thread to perform this task in the UI. There is a cancel button in my UI, which when clicked should roll back the tasks performed and return to the UI/exit from it gracefully without freezing it. How can I achieve this effectively. Below is sample code which I've used to get started. Any help will be appreciated.

import java.io.File;
import java.io.IOException;

import org.apache.commons.io.FileUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.swt.widgets.Shell;


public class TestProgressBar {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        final Display display=new Display();
        final Shell shell=new Shell(display,SWT.MIN|SWT.CLOSE);
        shell.setSize(500,200);

        GridLayout gdLayout=new GridLayout();
        gdLayout.numColumns=2;
        shell.setLayout(gdLayout);


        Composite composite = new Composite(shell, SWT.NONE);
        composite.setLayout(gdLayout);

        GridData gd=new GridData();
        final Label lab=new Label(composite, 0);
        lab.setText("Performing Job :");
        gd.horizontalIndent=10;
        gd.horizontalAlignment=SWT.FILL;
        lab.setLayoutData(gd);

        GridData gdPg=new GridData();
        gdPg.horizontalAlignment=SWT.FILL;
        final ProgressBar bar = new ProgressBar(composite, SWT.NONE);
        bar.setLayoutData(gdPg);
        final int maximum = bar.getMaximum();
        //System.err.println(maximum);

        final Button cancelButton=new Button(composite,SWT.NONE);
        cancelButton.setText("Cancel Copy");


        new Thread() {
            public void run() {
                for (final int[] i = new int[1]; i[0] <= maximum; i[0]++) {

                try {Thread.sleep (10);} catch (Throwable th) {}

                copyOperation();

                    if (display.isDisposed()) return;

                    display.asyncExec(new Runnable() {
                        public void run() {
                        if (bar.isDisposed ()) return;
                            bar.setSelection(i[0]);

                            if(i[0]==maximum) 
                                {
                                    lab.setText("Job Finished!!!");
                                    cancelButton.setEnabled(false);
                                }
                        }


                    });
                }

            }
        }.start();

        shell.open();
        while(!shell.isDisposed())
        {
            if(!display.readAndDispatch())
                    display.sleep();
        }


    }

    protected static void copyOperation() {
        // TODO Auto-generated method stub
        File zipFile=new File("D:\\Sample.zip");

        try {
            FileUtils.copyFileToDirectory(zipFile,new File("C:\\Users\\komail\\Desktop"));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }



    }


}
Abbas
  • 3,144
  • 2
  • 25
  • 45

2 Answers2

1

Why not use a boolean cancelled = false, when you click on the button Cancel this is switched to true ? the copier regulary check if it is false or true. You can also use Thread#destroy()

Vinz243
  • 9,654
  • 10
  • 42
  • 86
  • Thanks, but you cannot use a global variable inside a listener without making it final, and final variables cannot be assigned :( – Abbas Aug 18 '13 at 05:39
  • @Abbas You can modify `field`s in `Listener`s, i.e. class member variables. – Baz Aug 19 '13 at 07:49
0

You can create a wrapper on your "cancelled" variable like this:

/**
 * Wrapper on  any type T.
 */
public class Wrapper<T> {

    /**
     * The encapsulated value.
     */
    public T value;

    public Wrapper(T value) {
        this.value = value;
    }
}

And use it like this:

final Wrapper<Boolean> cancelled = new Wrapper<Boolean>(false);
...
cancelled.value=true;

This way you have a final field which is visible and you can change it's value.