Ejemplo n.º 1
0
    def add_record(self):
        """
        Fires up GUI for budget record creation.
        """
        if len(self.categories) == 0:
            show_warning('You have to create categories first.')
            return

        manager = Manager(self.categories.values())
        manager.createdRecord.connect(self.record_created)
        manager.exec()
Ejemplo n.º 2
0
	def jobtree_menu(self, pos):
		selected = self.ui.treeWidget.selectedItems()
		# show menu
		menu = QtGui.QMenu()
		a1 = menu.addAction("Delete job(s)")
		# exec
		action = menu.exec_(self.ui.treeWidget.mapToGlobal(pos))

		success = 1
		if action == a1:
			warning = "Are you sure to delete all of the outputs of these job(s) ?\nNote: they cannot be restored after deletion.\n"
			for si in selected:
				warning = warning + str(si.text(0)) + '\n'
			re = utils.show_warning(warning)
			if re == 1:
				for si in selected:
					jid = self.mainwindow.JobCenter.run_view[str(si.text(0))]
					job_path = self.mainwindow.JobCenter.jobs[jid].savepath
					job_status = self.mainwindow.JobCenter.get_run_status_2(jid)
					if job_status is None or job_status == self.mainwindow.JobCenter.RUN or job_status == self.mainwindow.JobCenter.SUB:
						utils.show_message("The status of job %s is %s, cannot be deleted !" % (str(si.text()), str(job_status)) )
						success = 0
						continue
					else:
						try:
							shutil.rmtree(job_path)
						except:
							utils.show_message("Fail to remove job %s !\n(%s)" % (str(si.text(0)), job_path) )
							success = 0
							continue
						success = self.mainwindow.JobCenter.del_job_record(jid)
		if success:
			utils.show_message("All done!")
		self.load_jobs()
Ejemplo n.º 3
0
    def delete_category(self):
        """
        Tries to delete selected category from DB. On success reloads
        all categories in the GUI.
        """
        index_list = self.categoriesView.selectedIndexes()
        if index_list and index_list[0].isValid():
            index = index_list[0]
            category = index.data(Qt.UserRole)

            deletion = self.orm.delete_category(category)
            if not deletion:
                show_warning("Can't delete category")
            else:
                self.show_categories()
                if category.parent is None:
                    self.show_available_parents()
Ejemplo n.º 4
0
    def add_category(self):
        """
        Gets the name of new category and creates category or subcategory
        in DB. On success reloads all categories in the GUI.
        """
        name = self.caregoryName.text()
        if name == '':
            return
        parent = self.categoryParent.currentText()

        addition = self.orm.add_category(name, parent)
        if not addition:
            show_warning("Category already exists.")
        else:
            self.show_categories()
            if parent == '':
                self.show_available_parents()
Ejemplo n.º 5
0
    def delete_account(self):
        """
        Tries to delete the account from DB, if successful deletes it from GUI.
        """
        model_indexes = self.selection.selectedIndexes()
        if not model_indexes:  # the list of accounts is empty
            return None

        model_index = model_indexes[0]
        acc = model_index.data(role=Qt.UserRole)

        msgBox = QMessageBox()
        msgBox.setText("Delete the {} account?".format(acc.name))
        msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        msgBox.setDefaultButton(QMessageBox.Cancel)
        ret = msgBox.exec()

        if ret == QMessageBox.Ok:
            deletion = self.orm.delete_account(acc)
            if not deletion:
                show_warning("Can't delete account.")
            else:
                self.accounts.removeRow(model_index.row())
Ejemplo n.º 6
0
    def OK(self):
        if self.datadir is None:
            utils.show_message("Please choose data directory !")
            return False
        if self.dirname is None:
            utils.show_message("Please choose work directory !")
            return False

        # check & set jss
        if str(self.ui.comboBox.currentText()).strip()[:2] == "NO":
            self.jss = None
        elif str(self.ui.comboBox.currentText()).strip()[:3] == "PBS":
            # check if PBS is working
            if not utils.check_PBS():
                utils.show_message("NO PBS detected !")
                return False
            self.jss = "PBS"
        else:
            utils.show_message("I can not recognize the job submitting system")
            return False

        # check data format
        self.format_index = self.ui.comboBox_2.currentIndex()

        # check subDir
        if self.ui.checkBox.checkState() == QtCore.Qt.Checked:
            self.subDir = True

        # check data dir
        if not os.path.exists(os.path.join(self.datadir)):
            utils.show_message("Data directory is invalid !")
            return False
        else:
            stat = utils.check_datadir(self.datadir, self.format_index,
                                       self.namespace['data_format'],
                                       self.subDir)
            # checking results, interact with user
            if stat[0] == 0 and stat[1] == 0:
                re = utils.show_warning("I can not find any %s files in the data folder, still go on ?" \
                    % self.namespace['data_format'][self.format_index])
                if re == 1:
                    pass
                else:
                    return False
            elif stat[0] == -1 and stat[1] == -1:
                utils.show_message("Some error occurred ! Please report it")
                return False
            elif stat[0] == 1:
                if stat[1] == 1:
                    pass
                elif stat[1] == -1:
                    subdre = ''
                    if self.subDir:
                        subdre = ' no'
                    re = utils.show_warning(
                        "It seems there are%s sub directories in data folder, still go on ?"
                        % subdre)
                    if re == 1:
                        pass
                    else:
                        return False
                else:
                    utils.show_message(
                        "Some error occurred ! Please report it")
                    return False
            elif type(stat[0]) == str:
                if stat[1] == 1:
                    re = utils.show_warning("It seems the data format is '%s', still use '%s' ?" \
                       % (stat[0], self.namespace['data_format'][self.format_index]) )
                    if re == 1:
                        pass
                    else:
                        return False
                elif stat[1] == -1:
                    subdre = ''
                    if self.subDir:
                        subdre = ' no'
                    re = utils.show_warning("It seems there are%s sub directories in data folder, \
								and the data format is '%s', still go on and use '%s' ?"                \
                       % (subdre, stat[0], self.namespace['data_format'][self.format_index]) )
                    if re == 1:
                        pass
                    else:
                        return False
                else:
                    utils.show_message(
                        "Some error occurred ! Please report it")
                    return False

        # make dir
        # if not os.path.exists(os.path.join(self.dirname, self.namespace['ini'])):
        self.makedirs()
        # copy darkcal to Process/config
        project_darkcal_path = os.path.join(
            self.dirname, self.namespace['project_structure'][0],
            "config/darkcal_default.ini")
        if not os.path.exists(project_darkcal_path):
            shutil.copyfile(
                os.path.join(
                    os.path.split(os.path.realpath(__file__))[0],
                    "darkcal.ini"), project_darkcal_path)
        subprocess.check_call( "ln -fs %s %s" % ( project_darkcal_path, \
         os.path.join(self.dirname, self.namespace['project_structure'][0], "config/darkcal.ini") ), shell=True )

        # write project.ini
        config_name = self.namespace['project_ini'][0]
        config_item = self.namespace['project_ini'][1].split(',')
        utils.write_config(os.path.join(self.dirname, self.namespace['ini']),\
          {config_name:{config_item[0]:self.datadir, config_item[1]:self.jss, \
          config_item[2]:self.format_index, config_item[3]:self.subDir, \
          config_item[4]:self.job_control[0], config_item[5]:self.job_control[1]}}, 'w')

        utils.print2projectLog(self.dirname,
                               "Select data dir %s" % self.datadir)
        utils.print2projectLog(self.dirname,
                               "Choose work dir %s" % self.dirname)
        utils.print2projectLog(self.dirname, "Spipy GUI opened successfully")

        # close and open main gui
        self.mainapp.setup(self.dirname, self.datadir, self.jss, self.subDir,
                           self.format_index)
        self.mainapp.show()
        self.close()
Ejemplo n.º 7
0
def SecurityCheck(command):
	for st in MaliciousStrings:
		if command.find(st) != -1:
			utils.show_warning(_('GnoMenu detected a malicious script in this theme.\nThe script was blocked!\nYou should uninstall the selected theme and contact the website where you got it.\n\nThe script that tried to run was:')+ ' ' + command.replace('&',''))
			return ''
	return command
Ejemplo n.º 8
0
	def table_menu(self, position):
		"""
		entrance to submit jobs
		"""
		# selected cells
		selected_runs = []
		selected_tag_remarks = {}
		selected_datafile = {}
		for pos in self.ui.tableWidget.selectionModel().selection().indexes():
			row = pos.row()
			run_name = str(self.ui.tableWidget.item(row, 0).text())
			if len(self.process_data[run_name][0]) == 0:
				utils.show_message("Run %s does not contain any data. Skip." % run_name)
				continue
			tag_remarks_name = str(self.ui.tableWidget.item(row, 1).text())
			selected_runs.append(run_name)
			selected_tag_remarks[run_name] = self.split_tag_remarks(tag_remarks_name)
			selected_datafile[run_name] = self.process_data[run_name][0]

		# show menu
		if len(selected_runs) > 0:
			# get assignments
			assignments = str(self.ui.comboBox.currentText())
			# show menu
			menu = QtGui.QMenu()
			a1 = menu.addAction("Run %s" % assignments)
			menu.addSeparator()
			# a2 = menu.addAction("Terminate all")
			menu_sub = menu.addMenu("Terminate")
			b = []
			if len(selected_runs) > 1:
				for assign in self.namespace['process_assignments']:
					b.append(menu_sub.addAction(assign))
				if selected_tag_remarks[selected_runs[0]][0] != "--":
					menu.addSeparator()
					a4 = menu.addAction("Open %s results in data viewer" % assignments)
			elif len(selected_runs) == 1:
				run_tag_remarks = self.get_existing_runtags(assignments, selected_runs[0])
				for tr in run_tag_remarks:
					tr_status = self.JobCenter.get_run_status(selected_runs[0], self.namespace['project_structure'][0], assignments, tr[0], tr[1])
					if tr_status == self.JobCenter.RUN:
						b.append( menu_sub.addAction("%s.%s.%s.%s" % (assignments, selected_runs[0], tr[0], tr[1])) )
				menu.addSeparator()
				if selected_tag_remarks[selected_runs[0]][0] == "darkcal":
					a4 = menu.addAction("Set as current darkcal")
				elif selected_tag_remarks[selected_runs[0]][0] != "--":
					a4 = menu.addAction("Open %s results in data viewer" % assignments)
				else:
					a4 = 0
			else:
				pass

			# exec
			action = menu.exec_(self.ui.tableWidget.mapToGlobal(position))

			# parse selection
			job_type  = self.namespace['project_structure'][0] + "/" + assignments

			if action == a1:
				utils.print2projectLog(self.dirname, "Choose %s on %s" % (assignments, str(selected_runs)))
				self.JobCenter.TableRun_showoff(job_type, selected_runs, selected_datafile, selected_tag_remarks)
			#elif action == a2:
			#	print("Terminate all jobs of %s" % str(selected_runs))
			elif len(selected_runs) == 1 and action == a4:
				if selected_tag_remarks[selected_runs[0]][0] == "darkcal":
					# re-link current-darkcal.h5
					tmp_darkfile = utils.fmt_job_dir(selected_runs[0], \
						selected_tag_remarks[selected_runs[0]][0], selected_tag_remarks[selected_runs[0]][1])
					tmp_darkfile = os.path.join(self.dirname, self.namespace['project_structure'][0], self.namespace['process_HF'], tmp_darkfile)
					try:
						tmp_darkfile = glob.glob(os.path.join(tmp_darkfile, "*darkcal.h5"))[0]
					except:
						utils.show_message("I cannot find ?.darkcal.h5 in this run. Fail to set current darkcal.")
						return
					tmp_curr_darklink = os.path.join(self.dirname, self.namespace['project_structure'][0], self.namespace['process_HF'], self.namespace['darkcal'])
					prev_dark_run = None
					if os.path.exists(tmp_curr_darklink):
						prev_dark_run = subprocess.check_output("ls -l %s | awk -F'->' '{print $2}' | tr -d ' '" % tmp_curr_darklink, shell=True)
						prev_dark_run = os.path.split(prev_dark_run.strip("\n"))[-1].split('.')[0]
					subprocess.check_call("ln -fs %s %s" % (tmp_darkfile, tmp_curr_darklink), shell=True)
					# refresh table info
					if prev_dark_run is not None:
						self.process_data[prev_dark_run][6] = "--"
					self.process_data[selected_runs[0]][6] = "Current-Darkcal"
					utils.print2projectLog(self.dirname, "Set %s as current darkcal" % selected_runs[0])
					# draw table
					self.draw_table()
				else:
					# open data viewer and add files
					tmp = utils.fmt_job_dir(selected_runs[0], \
						selected_tag_remarks[selected_runs[0]][0], selected_tag_remarks[selected_runs[0]][1])
					tmp = os.path.join(self.dirname, self.namespace['project_structure'][0], assignments, tmp, '*.h5')
					tmp = glob.glob(tmp)
					if not data_viewer.is_shown():
						data_viewer.show_data_viewer(self)
					data_viewer.add_files(tmp)
					utils.print2projectLog(self.dirname, "Add %s results of %s to data viewer." % (assignments, selected_runs[0]))
			elif len(selected_runs) == 1 and action in b:
				tmp = str(action.text()).split('.')
				jid = self.JobCenter.get_jid(tmp[0], tmp[1], tmp[2], tmp[3])
				re = utils.show_warning("Terminate job %d of %s ?" % (jid, str(selected_runs)))
				if re == 1:
					tmp = self.JobCenter.kill_job(jid)
					if tmp[0] == 1:
						utils.print2projectLog(self.dirname, "Terminate job %d of %s" % (jid, str(selected_runs)))
						utils.show_message("Job %s is successfully terminated" % str(action.text()))
					else:
						utils.print2projectLog(self.dirname, "Fail to terminate job %d of %s" % (jid, str(selected_runs)))
						utils.show_message("**FAIL** to terminate job !" % str(action.text()))
					# refresh
					self.update_table_runs()
					self.draw_table()
			elif len(selected_runs) > 1 and action in b:
				assign = str(action.text())
				all_jid = []
				for run_name in selected_runs:
					tag_remarks = self.get_existing_runtags(assign, run_name)
					for tr in tag_remarks:
						tr_status = self.JobCenter.get_run_status(run_name, self.namespace['project_structure'][0], assign, tr[0], tr[1])
						if tr_status == self.JobCenter.RUN:
							tmp_jid = self.JobCenter.run_view[utils.fmt_runview_key(assign, run_name, tr[0], tr[1])]
							all_jid.append(tmp_jid)
				re = utils.show_warning("Terminate all these %d jobs ?" % len(all_jid))
				if re == 1:
					killed = 0
					for tmp_jid in all_jid:
						killed += self.JobCenter.kill_job(jid)
					utils.print2projectLog("Terminate %d %s jobs of %s" % (killed, assign, str(selected_runs)))
					utils.show_message("Successfully terminate %d jobs" % killed)
					# refresh
					self.update_table_runs()
					self.draw_table()
			elif len(selected_runs) > 1 and action == a4:
				if not data_viewer.is_shown():
					data_viewer.show_data_viewer(self)
				for selected_run in selected_runs:
					tmp = utils.fmt_job_dir(selected_run, \
						selected_tag_remarks[selected_run][0], selected_tag_remarks[selected_run][1])
					tmp = os.path.join(self.dirname, self.namespace['project_structure'][0], assignments, tmp, '*.h5')
					tmp = glob.glob(tmp)
					data_viewer.add_files(tmp)
				utils.print2projectLog(self.dirname, "Add %s results of %s to data viewer." % (assignments, str(selected_runs)))
			else:
				pass
		else:
			menu = QtGui.QMenu()
			if self.ui.tableWidget.horizontalHeader().resizeMode(0) == QtGui.QHeaderView.Stretch:
				a1 = menu.addAction("Unfill table window")	
			else:
				a1 = menu.addAction("Fill table window")
			menu.addSeparator()
			a2 = menu.addAction("Set 'force overwrite' to %s" % str(not self.JobCenter.force_overwrite))

			action = menu.exec_(self.ui.tableWidget.mapToGlobal(position))
			if action == a1:
				if self.ui.tableWidget.horizontalHeader().resizeMode(0) == QtGui.QHeaderView.Stretch:
					self.ui.tableWidget.horizontalHeader().setResizeMode(QtGui.QHeaderView.Interactive)
				else:
					self.ui.tableWidget.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
			elif action == a2:
				self.JobCenter.reverseForceOverwrite()
			else:
				pass
Ejemplo n.º 9
0
    def packSubmit(self, job_obj):
        def get_mpi_ranks(runtime_data, inh5, pat_per_job, max_jobs):
            pat_num = 0
            try:
                for ind, f in enumerate(runtime_data):
                    fp = h5py.File(f, 'r')
                    if len(fp[inh5].shape) != 3:
                        return None
                    pat_num += fp[inh5].shape[0]
                    fp.close()
            except:
                return None
            return min(pat_num / pat_per_job + 1, max_jobs)

        proj_conf = utils.read_config(
            os.path.join(self.rootdir, self.namespace['ini']))
        pat_per_job = int(
            proj_conf.get(self.namespace['project_ini'][0],
                          self.namespace['project_ini'][1].split(',')[4]))
        max_jobs = int(
            proj_conf.get(self.namespace['project_ini'][0],
                          self.namespace['project_ini'][1].split(',')[5]))
        del proj_conf
        # runtime json
        runtime = {}
        # config file
        config_file = None

        # jss
        sub_jss = self.jss
        # queue
        sub_submit_queue = self.submit_queue
        # write run shell to workdir
        sub_prepare_sub_script = os.path.join(
            os.path.split(os.path.realpath(__file__))[0],
            "scripts/submission.sh")
        # python script
        sub_python_exec = None
        # number of process
        sub_nproc = 0
        # workdir
        sub_workdir = None

        ############ These are irrelevent to assignments' type
        runtime['run_name'] = job_obj.run_name
        runtime['dataset'] = job_obj.datafile
        runtime['savepath'] = job_obj.savepath
        config_file = job_obj.config
        sub_workdir = job_obj.savepath
        # get inh5
        try:
            inh5 = utils.read_config(
                config_file,
                [self.namespace['config_head'], 'data-path in cxi/h5'])
        except:
            inh5 = utils.read_config(config_file, ['darkcal', 'inh5'])
        inh5 = utils.compile_h5loc(inh5, job_obj.run_name)
        ############
        '''
			choose correct code blocks to run according to the given job type
		'''
        if job_obj.assignments == self.namespace['process_HF']:
            # hit-finding

            if str(self.ui.lineEdit_2.text()).lower() == "none":
                runtime['darkcal'] = None
            else:
                runtime['darkcal'] = str(self.ui.lineEdit_2.text())

            sub_python_exec = os.path.join(
                os.path.split(os.path.realpath(__file__))[0], "scripts",
                self.python_scripts["hf"])

            # decide mpi rank size
            # actually I want to be free from inh5, but can not find any good ways
            if self.data_format.lower() in ["cxi", "h5"]:
                sub_nproc = get_mpi_ranks(runtime['dataset'], inh5,
                                          pat_per_job, max_jobs)
                if sub_nproc is None:
                    utils.show_message(
                        "The data file '%s' seem seem to have some problems. Check whether the 'Data-path in cxi/h5' is correct."
                        % f)
                    return None
            else:
                # TODO
                pass

        elif job_obj.assignments == self.namespace['process_AP']:
            # adu2photon

            sub_python_exec = os.path.join(
                os.path.split(os.path.realpath(__file__))[0], "scripts",
                self.python_scripts["ap"])
            # get data source path
            this_datadir = utils.read_config(
                config_file, [self.namespace['config_head'], 'Data Dir'])
            # do not use raw dataset
            if not job_obj.datafile[0].startswith(this_datadir):
                assignments = os.path.split(this_datadir)[-1]
                try:
                    tag_remarks = self.main_gui.tag_buffer[assignments][
                        runtime['run_name']]
                    tag_remarks = self.main_gui.split_tag_remarks(tag_remarks)
                    if len(tag_remarks) != 2:
                        raise ValueError("boomb")
                except:
                    utils.show_message(
                        "%s:\nI cannot find the data source, please check the parameters agian."
                        % runtime['run_name'])
                    return None
                '''
				tag_remarks = self.tag_remarks_buffer[runtime['run_name']]
				if len(tag_remarks) != 2:
					utils.show_message("%s:\nI cannot find the data source, please check the parameters agian." % runtime['run_name'])
					return None
				'''
                datafile = os.path.join(
                    this_datadir,
                    utils.fmt_job_dir(runtime['run_name'], tag_remarks[0],
                                      tag_remarks[1]), '*.h5')
                datafile = glob.glob(datafile)
                if len(datafile) == 0:
                    utils.show_message(
                        "%s:\nI cannot find the data source, please check the parameters agian."
                        % runtime['run_name'])
                    return None
                runtime['dataset'] = datafile

            # decide mpi rank size
            sub_nproc = get_mpi_ranks(runtime['dataset'], inh5, pat_per_job,
                                      max_jobs)
            if sub_nproc is None:
                utils.show_message("The data files in '%s' seem to have some problems.\n" % this_datadir + \
                     "Check : data location, 'Data-path in cxi/h5' are correct;\n" + \
                     "Check : data files are multi-pattern HDf5 format.")
                return None

        else:
            return None
        '''
			prepare and submit jobs : 
				job_dir/status stores all status_xxx.txt of every process
				and there will be a status.txt if the job finished
		'''
        try:
            # make workdir if not exists
            if not os.path.isdir(runtime['savepath']):
                os.mkdir(runtime['savepath'])
                os.mkdir(os.path.join(runtime['savepath'], 'status'))
            else:
                if not self.force_overwrite:
                    re = utils.show_warning(
                        "project %s already exists, overwrite it?" %
                        runtime['savepath'])
                    if re == 0:
                        utils.show_message(
                            "Don't overwrite project %s, EXIT." %
                            runtime['savepath'])
                        return None
                shutil.rmtree(runtime['savepath'])
                os.mkdir(runtime['savepath'])
                os.mkdir(os.path.join(runtime['savepath'], 'status'))
            # write runtimejson and config to workdir
            with open(os.path.join(runtime['savepath'], 'runtime.json'),
                      'w') as rjson:
                json.dump(runtime, rjson)
            shutil.copyfile(config_file,
                            os.path.join(runtime['savepath'], 'config.ini'))
            # write submit script to workdir
            SUB_cmd = subprocess.check_output(
                "bash %s -s %s -t %d -p %s -q %s -y %s" %
                (sub_prepare_sub_script, sub_python_exec, sub_nproc,
                 sub_workdir, sub_submit_queue, sub_jss),
                shell=True)
            SUB_cmd = SUB_cmd.strip("\n")
            if len(SUB_cmd) == 0:
                return None
            # submit
            pobj = utils.submit_job(sub_workdir, SUB_cmd, self.jss)
            # return
            if pobj is None:
                return None
            else:
                return pobj
        except:
            return None
Ejemplo n.º 10
0
    def run(self):
        # update self.run_view
        # update run_tag, config, run_remarks, pid, savepath, stime, status in self.jobs

        # read tag, remarks and darkcal
        title = str(self.windowTitle())
        module, assignments = title.split('.')
        config_file_name = str(self.ui.comboBox.currentText())  # 'xxx.ini'

        config_file = os.path.join(self.rootdir, module, "config",
                                   config_file_name)
        tag_name = self.extract_tag(config_file_name)
        self.submit_queue = str(self.ui.lineEdit_3.text())

        if not os.path.isfile(config_file):
            utils.show_message("Choose a configuration file !")
            return
        remarks = utils.fmt_remarks(str(self.ui.lineEdit.text()))
        if len(remarks) == 0:
            remarks = "default"

        # hit-finding has darkcal
        if assignments == self.namespace['process_HF']:
            if config_file_name == "darkcal.ini":
                if len(str(self.ui.lineEdit_2.text())) == 0:
                    utils.show_message(
                        "Dark calibration needs data location in raw h5/cxi file."
                    )
                    return
                if not str(self.ui.lineEdit_2.text()) == self.darkcal_inh5:
                    self.darkcal_inh5 = str(self.ui.lineEdit_2.text())
                    utils.write_config(
                        os.path.join(self.rootdir,
                                     self.namespace['project_structure'][0],
                                     'config/darkcal.ini'),
                        {'darkcal': {
                            'inh5': self.darkcal_inh5
                        }}, "a")
            else:
                if not os.path.isfile(str(self.ui.lineEdit_2.text())):
                    re = utils.show_warning(
                        "Dark calibration file is invalid, \
						which may affect the hit-finding accuracy. Ignore and go on?")
                    if re == 0:
                        return
                    else:
                        self.ui.lineEdit_2.setText("None")

        while not self.job_queue['waiting'].empty():
            wjid = self.job_queue['waiting'].get()
            jobdir = utils.fmt_job_dir(self.jobs[wjid].run_name, tag_name,
                                       remarks)
            self.jobs[wjid].run_tag = tag_name
            self.jobs[wjid].config = config_file
            self.jobs[wjid].run_remarks = remarks
            self.jobs[wjid].savepath = os.path.join(self.jobs[wjid].savepath,
                                                    jobdir)
            # submit
            pobj = self.packSubmit(self.jobs[wjid])
            if pobj is not None:
                self.jobs[wjid].jss = self.jss
                self.jobs[wjid].submit_time = time.time()
                self.jobs[wjid].process_obj = pobj
                # self.run_view
                run_view_key = utils.fmt_runview_key(self.jobs[wjid].assignments, \
                 self.jobs[wjid].run_name, tag_name, remarks)
                self.run_view[run_view_key] = wjid
                # write to project log
                utils.print2projectLog(
                    self.rootdir, "Submit %s job on %s : pid is %s" %
                    (self.jobs[wjid].assignments, self.jobs[wjid].run_name,
                     str(pobj.pid)))
                # write job infomation into jobHub
                self.write_job_hub(wjid)
                # refresh
                self.main_gui.update_table_runs()
                self.main_gui.draw_table()
            else:
                utils.show_message("Fail to submit job %s" % jobdir)
                utils.print2projectLog(
                    self.rootdir, "Fail to submit job : %s (%s.%s)" %
                    (self.jobs[wjid].assignments, self.jobs[wjid].run_name,
                     self.jobs[wjid].run_tag))
                self.jobs.pop(wjid)
        self.close()
        pass