def start_job(self):
        max_jobs = max(1, QThread.idealThreadCount())

        self.mutex.lock()
        if len(self.job_queue) > 0 and len(self.job_working) < max_jobs:
            job = self.job_queue.pop()
            setattr(self, "lbl_" + job.name, "   started")

            # if data for this job already computed
            if job.name in self.analdata:
                if job.type == NODELEVEL:
                    self.analfeatures.append((job.name, \
                                Orange.data.ContinuousVariable(job.label)))
                    setattr(self, "lbl_" + job.name, "  finished")

                elif job.type == GRAPHLEVEL:
                    setattr(self, "lbl_" + job.name,("%.4f" % \
                            self.analdata[job.name]).rstrip('0').rstrip('.'))

                job.quit()
                self.send_data()
            else:
                self.job_working.append(job)
                job.start()
        self.mutex.unlock()

        if len(self.job_queue) > 0 and len(self.job_working) < max_jobs:
            self.start_job()
 def run_more_jobs(self):
     known = set(self.known)
     needed = self.needed_methods()
     for method in needed:
         if method.name not in self.running_jobs:
             setattr(self, "lbl_" + method.name, "pending")
     doable = [method for method in needed
               if method.name not in self.running_jobs
               and set(method.args) <= known]
     free = max(1, QThread.idealThreadCount()) - len(self.running_jobs)
     for method in doable[:free]:
         job = WorkerThread(method, self.known)
         job.finished.connect(lambda job=job: self.job_finished(job))
         self.running_jobs[method.name] = job
         job.start()
         if not method.level == INTERNAL:
             setattr(self, "lbl_" + method.name, "running")
     self.show_computing()