package test;
import java.util.Random;
import com.trolltech.qt.QSignalEmitter;
import com.
trolltech.
qt.
core.
QObject;
import com.
trolltech.
qt.
core.
QTimer;
/**
* Handler for long operations. Allows operations queueing
* and emit a signal when all operations are completed.
* Uses its own thread to not block the application.
*/
public class LongOpHandler extends
QObject implements Runnable
{ public QSignalEmitter.Signal1<Integer> opCompleted = new QSignalEmitter.Signal1<Integer>();
private boolean allDone = false; // flag for all operations completed
private Object timer1 = null; // reference to timer1
private boolean op1Requested = false; // simulate queueing of operation 1
private boolean op2Requested = false; // simulate queueing of operation 2
private boolean op1Done = false; // flag for completion of operation 1
private boolean op2Done = false; // flag for completion of operation 2
/**
* Starts a new thread so that the requester is not blocked
* while requested operations are performed
*/
public LongOpHandler() {
// rename current thread for convenience
thread().setName("Thread-for-UI");
// start a new thread to execute run(), give it a name for convenience
new QThread(this,
"Thread-for-operations").
start();
}
/**
* Simulate the queueing of an operation.
* @param opId the number of the operation to queue: 1 or 2
*/
public synchronized void enqueue(int opId) {
// queue the requested operation, it will be started within run()
if (opId == 1) op1Requested = true; else op2Requested = true;
// wake up the Thread-for-operations in case it is executing wait()
notifyAll();
}
/**
* Method executed in a separate thread to avoid blocking of the main
* thread by long operations. Operations here are simulated by timers.
* Queued operations are dequeued and executed. When all operations
* have been executed, run() is exited. wait() is call when there is
* nothing to do. Queueing and completion of operation must wake up the
* separate thread executing wait().
*/
public synchronized void run() {
// simulated operations
// store reference to timer1 at instance level to allow access to its value
this.timer1 = timer1;
// connect signals to slots
timer1.timeout.connect(this, "done()");
timer2.timeout.connect(this, "done()");
// loop to monitor new requests and completion of all requests
while (!allDone) {
// look for queued requests
if (op1Requested) {
timer1.setSingleShot(true);
timer1.setInterval(new Random().nextInt(500) + 500);
// QTimer.start() triggers:
// "QObject::startTimer: QTimer can only be used with threads started with QThread"
timer1.start();
op1Requested = false;
op1Done = false;
}
if (op2Requested) {
timer2.setSingleShot(true);
timer2.setInterval(new Random().nextInt(500) + 500);
// QTimer.start() triggers:
// "QObject::startTimer: QTimer can only be used with threads started with QThread"
timer2.start();
op2Requested = false;
op2Done = false;
}
// test if all operations are completed
// for the purpose of this test, "all" means timers 1 and 2 timed out
allDone = op1Done && op2Done;
// wait for something to do
while (!allDone) {
try {wait();} catch (InterruptedException e) {}
// update allDone flag
allDone = op1Done && op2Done;
}
}
// operations now completed, resources created by Thread-for-operations
// will be destroyed after exiting run()
}
@SuppressWarnings("unused")
private synchronized void done() {
// determine which operation has completed
int opId = (signalSender() == timer1) ? 1 : 2;
// inform the requester of the completion
opCompleted.emit(opId);
// record the completion
if (opId == 1) op1Done = true; else op2Done = true;
// release Thread-for-operations if it is waiting
notifyAll();
}
}