Developer Documentation
Process Interface


ProcessInterface.png


The Process interface can be used to run arbitrary slots of your plugin within a separate thread of OpenFlipper. OpenFlipper supports a process manager, visualizing currently running operations to the user. Process dialogs and user information can be provided via special signals.

As in qt user interface operations are only allowed from within the main thread, you can not interact with the ui in your threads. Feedback like the progress or other messages need to be passed through the ProcessInterface. Additionally you have to make sure, that your operations can actually run in parallel to others. If not, you have to mark your thread as blocking, which would prevent the user from starting additional operations until your job gets finished.

Using threads in OpenFlipper is quite simple. All necessary class definitions are already available to plugins. A tutorial for the thread interface is available: Using threads from within a plugin

Process Setup

So the first thing we have to do is instantiate an OpenFlipperThread object and tell the core that we just created a thread via ProcessInterface::startJob().

// Create job named "My Thread" .. Name will e visible in OpenFlippers process manager.
OpenFlipperThread* thread = new OpenFlipperThread(name() + "My thread");
// Tell OpenFlipper about the newly created job. In this case, it gets a description and
// a span for its steps. This job has 100 steps from 0 to 100. These values are used
// to display a progress bar.
// The last parameter means that the job will be non-blocking, so the ui will still be available.
emit startJob( name() + "My thread", "My thread's description" , 0 , 100 , false);

Next thing to do is connecting the thread's signal to local signals/slots in order to keep track of updates concerning the processing of our thread.

// Slot connection required to tell the core, that the thread has finished
connect(thread, SIGNAL(finished(QString)), this, SIGNAL(finishJob(QString)));
// Slot connection required setting the function in your plugin that should run inside the thread.
// It will get the job name which can be used to control the ui elements like progress.
// If you don't want to show progress you can skip the jobId QString.
connect(thread, SIGNAL(function(QString)), this, SLOT(testFunctionThread(QString)), Qt::DirectConnection);

Process Startup

The function() signal needs to be connected to the function that will actually be processed in the thread. Once having connected these signals, we're about to start our thread:

// Launch the thread
thread->start();
// Start processing of the function code (connected via signal OpenFlipperThread::function() )
// This function is non-blocking and will return immediately.
thread->startProcessing();

Status Reports

There are two signals that you can use to inform the user about your threads state. The first is ProcessInterface::setJobState(). It gets the jobId and an int. The int is the process status. It has to be in the values that have been given with ProcessInterface::startJob() before. OpenFlipper will calculate the percentage on its own and display a progress bar at the specific position.

The second function is ProcessInterface::setJobDescription() getting a description, that can be changed wile the thread is running. The following example shows a simple thread slot,using these signals.

// Useless example function which runs in a thread and updates the ui state.
// The QString parameter is only necessary if you want to provide feedback.
void testFunctionThread(QString _jobId) {
for (int i = 0 ; i < 1000000; ++i) {
// Emit new progress state
if(i % 10000 == 0)
emit setJobState(_jobId, (int)(i / 10000));
if(i == 500000) {
// When half of the processing is finished
// change the job's description
emit setJobDescription(_jobId, "Half way done");
}
}
}

Usage

To use the ProcessInterface:

  • include ProcessInterface.hh in your plugins header file
  • derive your plugin from the class ProcessInterface
  • add Q_INTERFACES(ProcessInterface) to your plugin class
  • And add the signals or slots you want to use to your plugin class (You don't need to implement all of them)
Note
In general, OpenFlipper signals should not be emitted from other threads than the main thread. However, there are some signals, which are save to call outside of another thread. Some will block, until the main thread executed the function, some run asnyc. If a function is guaranteed to be threadsafe, you will find a note in the documentation e.g. LoggingInterface::log()

Quick example

A quick example for stating a thread:

OpenFlipperThread* thread = new OpenFlipperThread(name() + "unique id"); // Create your thread containing a unique id
connect(thread,SIGNAL( finished(QString)), this,SIGNAL(finishJob(QString))); // connect your threads finish info to the global one ( you can do the same for a local one )
connect(thread,SIGNAL( function(QString)), this,SLOT(testFunctionThread(QString)),Qt::DirectConnection); // You can directly give a slot of your app that gets called
emit startJob( name() + "unique id", "Description" , 0 , 100 , false); // Tell the core about your thread
thread->start(); // start thread
thread->startProcessing(); // start processing

Note: If your class is derived from OpenFlipperThread, do not reimplement the run() function. Instead, use the function(QString) to connect the your running function with Qt::DirectConnection. Short example: Be MyThread the derived thread class

class MyThread : public OpenFlipperThread

and parallelFunction(QString) the function which should run by different threads.

void MyThread::parallelFunction(QString) // function which will run in parallel
{
std::cout << "I am running in another thread." << currentThreadId() << std::endl;
}

Instead of reimplementing the run function, connect the parallelFunction(QString) with the function(QString) signal in e.g. the constructor:

MyThread::MyThread(QString _jobId):OpenFlipperThread(_jobId)
{
// connect signal function(QString) with the self defined slot function
connect(this,SIGNAL(function(QString)),this,SLOT(parallelFunction(QString)), Qt::DirectConnection);
}

Note: The OpenFlipperThread will not be notified about job cancelling. You plugin has to be aware of it.

Note: You might also want to connect the signal OpenFlipperThread::state() to the plugin's signal setJobState():

connect(thread, SIGNAL(state(QString, int)), this, SIGNAL(setJobState(QString, int)));

Use signal OpenFlipperThread::state() within your run() function in order to correctly update the job's state.