#! /usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import pickle
import tempfile
import ConfigParser
import shutil
import time
import functions
from model import Model
from minimclass import Minim
from minimpypreferences import PrefWin
from export import Export
from editvariable import EditVariable
try:
import pysvn
pysvn_available = True
except:
pysvn_available = False
try:
import pygtk
pygtk.require("2.0")
import gobject
except:
print("pygtk Not Availible")
sys.exit(1)
try:
import gtk
except:
print("GTK Not Availible")
sys.exit(1)
class ModelInteface(object):
if os.name == 'posix':
invalid_chars = '/'
else:
invalid_chars = '\\/:* ?"<>|'
def _(self, key):
assert len(key) > 0
if self.tr_dict.has_key(key):
return self.tr_dict[key]
else:
return key.replace('_', '.')
def query_trial_dismis(self):
# this method checks whether the trial has unsaved data.
# if there are unsaved data, prompt a warning.
# output: True: means the dismis current state (e.g. start a new trial)
if self.trial_file_name:
return True
else:
if len(self.group_liststore) or len(self.variable_liststore) or len(
self.trial_title_entry.get_text()) or len(functions.get_text_buffer(self.trial_description_text)):
msg = self._('query_trial_dismis_msg')
dialog = gtk.MessageDialog(self.window, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format = msg)
dialog.set_title(self._('query_trial_dismis_dialog_title'))
if dialog.run() == gtk.RESPONSE_NO:
dialog.destroy()
return False
dialog.destroy()
return True
def delete_event(self, widget, event):
if not self.query_trial_dismis():
# do not exit
return True
self.window.destroy()
gtk.main_quit()
def group_cell_edited(self, cell, row, new_text, col):
if col == 0:
# names must not be repeated
for r in range(len(self.group_liststore)):
if r != row and new_text == self.group_liststore[r][0]:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_Group_name_already_in_use'))
return False
if len(new_text) == 0:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_group_name_can_not_be_empty'))
return False
if col == 1:
if not new_text.isdigit():
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_allocation_ratio_must_be_an_integer'))
return False
new_text = int(new_text)
if not new_text:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_allocation_ratio_must_not_be_zero'))
return False
self.group_liststore[row][col] = new_text
self.update_interface()
def group_add_button(self, widget, data=None):
self.group_liststore.append(('Group {0}'.format(len(self.group_liststore)+1), 1))
self.update_interface()
def group_delete_button(self, widget, data=None):
if self.group_treeview.get_cursor()[0]:
row = self.group_treeview.get_cursor()[0][0]
self.group_liststore.remove(self.group_liststore.get_iter(row))
for idx, record in enumerate(self.allocations):
if record['allocation'] == row:
self.ui_pool.append(self.allocations[idx]['UI'])
self.allocations[idx] = False
elif record['allocation'] > row:
record['allocation'] -= 1
self.allocations = filter(None, self.allocations)
self.update_interface()
else:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_please_select_a_group_first'))
return False
def variable_cell_edited(self, cell, row, new_text, col):
if col == 0:
for r in range(len(self.variable_liststore)):
if r != row and new_text == self.variable_liststore[r][0]:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_variable_name_already_in_use'))
return False
if len(new_text) == 0:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_variable_names_can_not_be_empty'))
return False
if col == 1:
if not new_text.replace('.', '').isdigit():
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_variable_weight_must_be_numeric'))
return False
new_text = float(new_text)
if col == 2:
# check for deleting a level
new_levels = map(str.strip, new_text.split(','))
new_text = ','.join(new_levels)
if len(new_levels) < 2:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_two_variable_levels_required'))
return False
self.variable_liststore[row][col] = new_text
self.update_interface()
def variable_add_button(self, widget, data=None):
self.variable_liststore.append(('Variable {0}'.format(len(self.variable_liststore)+1), 1.0, 'Level 0,Level 1'))
self.update_interface()
def variable_delete_button(self, widget, data=None):
if self.variable_treeview.get_cursor()[0]:
row = self.variable_treeview.get_cursor()[0][0]
self.variable_liststore.remove(self.variable_liststore.get_iter(row))
for idx in range(len(self.allocations)):
self.allocations[idx]['levels'].pop(row)
self.update_interface()
else:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_select_a_variable_first'))
return False
def update_interface(self):
n = len(self.allocations_treeview.get_columns())
while n:
n = self.allocations_treeview.remove_column(self.allocations_treeview.get_column(n-1))
widgets = self.combo_vbox.get_children()
for widget in widgets:
widget.destroy()
table = gtk.Table(2, len(self.variable_liststore)+1)
table.show()
min_group_old_index = self.min_group_combo.get_active()
if min_group_old_index < 0:
min_group_old_index = 0
if (min_group_old_index + 1) > len(self.group_liststore):
min_group_old_index = 0
if self.min_group_combo.get_model():
self.min_group_combo.get_model().clear()
for group in self.group_liststore:
self.min_group_combo.append_text(group[0])
if len(self.group_liststore):
self.min_group_combo.set_active(min_group_old_index)
self.variable_combos = []
n = 0
for variable in self.variable_liststore:
lbl = gtk.Label(variable[0])
lbl.show()
table.attach(lbl, 0, 2, n, n+1)
n += 1
cbo = gtk.combo_box_new_text()
cbo.show()
for level in map(str.strip, variable[2].split(',')):
cbo.append_text(level)
self.variable_combos.append(cbo)
table.attach(cbo, 0, 2, n, n+1)
n += 1
self.combo_vbox.pack_start(table, False, False)
types = ((str,) * (len(self.variable_liststore) + 4))
liststore = gtk.ListStore(*types)
tvcolumn = gtk.TreeViewColumn('#')
self.allocations_treeview.append_column(tvcolumn)
cell = gtk.CellRendererText()
tvcolumn.pack_start(cell, True)
tvcolumn.add_attribute(cell, 'text', 0)
tvcolumn.set_resizable(True)
tvcolumn.set_expand(True)
tvcolumn = gtk.TreeViewColumn('UI')
self.allocations_treeview.append_column(tvcolumn)
cell = gtk.CellRendererText()
tvcolumn.pack_start(cell, True)
tvcolumn.add_attribute(cell, 'text', 1)
tvcolumn.set_resizable(True)
tvcolumn.set_expand(True)
tvcolumn = gtk.TreeViewColumn(self._('general_group'))
self.allocations_treeview.append_column(tvcolumn)
cell = gtk.CellRendererText()
tvcolumn.pack_start(cell, True)
tvcolumn.add_attribute(cell, 'text', 2)
tvcolumn.set_resizable(True)
tvcolumn.set_expand(True)
n = 2
for variable in self.variable_liststore:
n += 1
tvcolumn = gtk.TreeViewColumn(variable[0])
self.allocations_treeview.append_column(tvcolumn)
cell = gtk.CellRendererText()
tvcolumn.pack_start(cell, True)
tvcolumn.add_attribute(cell, 'text', n)
tvcolumn.set_resizable(True)
tvcolumn.set_expand(True)
self.allocations_treeview.set_model(liststore)
self.allocations_treeview.show()
variable_models = [cbo.get_model() for cbo in self.variable_combos]
for row, record in enumerate(self.allocations):
liststore.append()
liststore[row][0] = row
liststore[row][1] = record['UI']
liststore[row][2] = self.group_liststore[record['allocation']][0]
for col, variable_model in enumerate(variable_models):
liststore[row][col+3] = variable_model[record['levels'][col]][0]
def get_minimize_case(self, new_case):
model = Model()
model.groups = range(len(self.group_liststore))
model.variables = [range(len(self.variable_liststore[row][2].split(','))) for row in range(len(self.variable_liststore))]
model.variables_weight = [self.variable_liststore[row][1] for row in range(len(self.variable_liststore))]
model.allocation_ratio = [self.group_liststore[row][1] for row in range(len(self.group_liststore))]
model.allocations = self.allocations
model.prob_method = self.get_prob_method()
model.distance_measure = self.get_distance_measure()
model.high_prob = self.high_prob_spin.get_value()
model.min_group = self.min_group_combo.get_active()
m = Minim(random=self.random, model=model)
m.build_probs(model.high_prob, model.min_group)
m.build_freq_table()
if self.initial_freq_table:
self.add_to_initial(m.freq_table)
return m.enroll(new_case, m.freq_table)
def add_to_initial(self, freq_table):
for row, group in enumerate(freq_table):
for v, variable in enumerate(group):
for l, level in enumerate(variable):
freq_table[row][v][l] += self.initial_freq_table[row][v][l]
def release_trial_lock(self):
model = self.allocations_treeview.get_model()
if model == None or len(model) == 0:
if self.trial_file_name:
self.want_trial_unlock(prompt)
return False
def remove_allocation(self, row=-1):
model = self.allocations_treeview.get_model()
if model == None or len(model) == 0:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_no_subject_allocated'))
return False
self.ui_pool.append(model[row][1])
if row == -1:
row = len(model) -1
path = (row,)
iter = model.get_iter(path)
model.remove(iter)
self.allocations.pop(row)
for r in range(len(model)):
model[r][0] = r
return True
def allocations_delete(self, row=-1, prompt=False):
if self.network_sync_dict['sync'] and self.trial_file_name:
repo_path = self.update_network_trial()
model = self.allocations_treeview.get_model()
if prompt:
msg = self._('allocations_delete_msg')
dialog = gtk.MessageDialog(self.window, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format = msg)
dialog.set_title(self._('allocations_delete_dialog_title'))
if dialog.run() == gtk.RESPONSE_NO:
dialog.destroy()
return False
dialog.destroy()
self.remove_allocation(row)
if self.network_sync_dict['sync']:
path = repo_path
else:
path = self.trial_file_name
self.save_trial(path)
if row != -1 and prompt:
if model == None or len(model) == 0:
if self.trial_file_name:
self.want_trial_unlock(True)
def allocations_delete_button(self, widget, data=None):
model = self.allocations_treeview.get_model()
if model and len(model) == 0:
# unlock
if self.trial_file_name:
self.want_trial_unlock(True)
return False
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_no_subject_allocated'))
return False
if self.allocations_treeview.get_cursor()[0]:
row = self.allocations_treeview.get_cursor()[0][0]
else:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_please_select_an_allocation_first'))
return False
if model == None or len(model) == 0:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_no_subject_allocated'))
return False
self.waiting_function(self.allocations_delete, (row, True))
def allocations_clear(self):
if self.network_sync_dict['sync'] and self.trial_file_name:
repo_path = self.update_network_trial()
model = self.allocations_treeview.get_model()
if model == None or len(model) == 0:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_allocation_table_is_empy'))
return
msg = self._('allocations_clear_msg')
dialog = gtk.MessageDialog(self.window, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format = msg)
dialog.set_title(self._('allocations_clear_dialog_title'))
if dialog.run() == gtk.RESPONSE_NO:
dialog.destroy()
return False
dialog.destroy()
model = self.allocations_treeview.get_model()
for row in range(len(model)):
self.ui_pool.append(model[row][1])
model.clear()
self.allocations = []
if self.network_sync_dict['sync']:
path = repo_path
else:
path = self.trial_file_name
self.save_trial(path)
def allocations_clear_button(self, widget, data=None):
self.waiting_function(self.allocations_clear, ())
def add_one_allocation(self, model):
model.append()
ui = self.ui_pool.pop()
new_case = {'levels': [], 'allocation': -1, 'UI': ui}
row = len(model)-1
model[row][0] = row
model[row][1] = ui
for col, cbo in enumerate(self.variable_combos):
model[row][col+3] = cbo.get_active_text()
new_case['levels'].append(cbo.get_active())
try:
m_group = self.get_minimize_case(new_case)
if m_group == -1:
self.waiting_function(self.allocations_delete, ())
functions.error_dialog(self.window, self._('allocation_error_dialog_msg'), self._('allocation_error_dialog_title'))
return False
except Exception as ex:
self.waiting_function(self.allocations_delete, ())
functions.error_dialog(self.window, self._('allocation_error_dialog_msg'), self._('allocation_error_dialog_title'))
return False
new_case['allocation'] = m_group
model[row][2] = self.group_liststore[m_group][0]
self.allocations.append(new_case)
return row
def allocations_add_all(self):
if self.network_sync_dict['sync'] and self.trial_file_name:
repo_path = self.update_network_trial()
model = self.allocations_treeview.get_model()
if not model:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_groups_prognostic_factors_must_be_defined'))
return False
if not self.ui_pool:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_trial_finished_or_not_saved'))
return False
while self.ui_pool:
for cbo in self.variable_combos:
item = self.random.choice(range(len(cbo.get_model())))
cbo.set_active(item)
self.add_one_allocation(model)
if self.network_sync_dict['sync']:
path = repo_path
else:
path = self.trial_file_name
self.save_trial(path)
def allocations_add_all_button(self, widget, data=None):
self.waiting_function(self.allocations_add_all, ())
def random_case_button(self, button, data=None):
for cbo in self.variable_combos:
item = self.random.choice(range(len(cbo.get_model())))
cbo.set_active(item)
def allocations_add(self):
cbo_selects = []
for cbo in self.variable_combos:
if cbo.get_active() == -1:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_factor_levels_not_selected'))
return False
cbo_selects.append(cbo.get_active())
if self.network_sync_dict['sync'] and self.trial_file_name:
repo_path = self.update_network_trial()
for i, cbo in enumerate(self.variable_combos):
cbo.set_active(cbo_selects[i])
model = self.allocations_treeview.get_model()
if not model:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_groups_factors_defined_first'))
return False
if not self.ui_pool:
if len(model):
if not self.set_extra_sample_size():
return False
else:
model = self.allocations_treeview.get_model()
else:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_trial_not_saved'))
return False
row = self.add_one_allocation(model)
if self.network_sync_dict['sync']:
path = repo_path
else:
path = self.trial_file_name
self.save_trial(path)
self.allocations_treeview.scroll_to_cell((row,))
self.allocations_treeview.set_cursor((row,),)
self.window.set_focus(self.allocations_treeview)
if not self.report_allocation(model):
self.waiting_function(self.allocations_delete, ())
else:
if len(self.ui_pool) == 0:
self.end_trial()
def allocations_add_button(self, widget, data=None):
self.waiting_function(self.allocations_add, ())
def report_allocation(self, model):
column = self.allocations_treeview.get_columns()
row = len(model)-1
ret = []
for col, column in enumerate(column):
ret.append(column.get_title() + ': ' + model[row][col])
# if dialog is not desired return here
msg = self._('allocating_new_case').format('\n'.join(ret))
dialog = gtk.MessageDialog(self.window, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_YES_NO, message_format = msg)
dialog.set_title(self._('new_allocation'))
if dialog.run() == gtk.RESPONSE_YES:
dialog.destroy()
return True
dialog.destroy()
return False
def end_trial(self):
msg = self._('extend_sample').format(len(self.allocations))
dialog = gtk.MessageDialog(self.window, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format = msg)
dialog.set_title(self._('trial_finished'))
if dialog.run() == gtk.RESPONSE_YES:
dialog.destroy()
return self.set_extra_sample_size()
dialog.destroy()
def set_extra_sample_size(self):
extra_sample = 0
extra_sample = functions.simple_spin_dialog(self._('extra_sample'), self.window)
if extra_sample == 0: return False
ss = len(self.allocations)+int(extra_sample)
self.trial_sample_size_spin.set_value(ss)
self.build_ui_pool(range(len(self.allocations), ss))
self.save_trial_changes()
model = self.allocations_treeview.get_model()
for row in range(len(model)):
model[row][1] = model[row][1].zfill(len(str(ss)))
return True
def refresh_freq_table(self):
model = Model()
model.groups = range(len(self.group_liststore))
model.variables = [range(len(self.variable_liststore[row][2].split(','))) for row in range(len(self.variable_liststore))]
model.variables_weight = [self.variable_liststore[row][1] for row in range(len(self.variable_liststore))]
model.allocation_ratio = [self.group_liststore[row][1] for row in range(len(self.group_liststore))]
model.allocations = self.allocations
m = Minim(random=self.random, model=model)
m.build_freq_table()
if self.initial_freq_table:
self.add_to_initial(m.freq_table)
if not len(m.freq_table):
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_no_allocation'))
return False
n = len(self.freq_table_treeview.get_columns())
while n:
n = self.freq_table_treeview.remove_column(self.freq_table_treeview.get_column(n-1))
cols = 0
column_names = []
for variable in self.variable_liststore:
column_names.extend([level for level in map(str.strip, variable[2].split(','))])
column_names = [self._('general_group')] + column_names + [self._('general_total')]
for var in m.freq_table[0]:
cols += len(var)
col_types = [str] + [int] * (cols + 1)
liststore = gtk.ListStore(*col_types)
for n in range(len(column_names)):
tvcolumn = gtk.TreeViewColumn(column_names[n])
self.freq_table_treeview.append_column(tvcolumn)
cell = gtk.CellRendererText()
tvcolumn.pack_start(cell, True)
tvcolumn.add_attribute(cell, 'text', n)
tvcolumn.set_resizable(True)
tvcolumn.set_expand(True)
self.freq_table_treeview.set_model(liststore)
for row, group in enumerate(m.freq_table):
liststore.append()
liststore[row][0] = self.group_liststore[row][0]
col = 1
for variable in group:
for level in variable:
liststore[row][col] = level
col += 1
liststore[row][col] = sum(variable)
liststore.append()
liststore[len(m.freq_table)][0] = self._('general_total')
total = 0
for c in range(1, col):
col_total = sum([liststore[row][c] for row in range(len(m.freq_table))])
total += col_total
liststore[len(m.freq_table)][c] = col_total
liststore[len(m.freq_table)][c+1] = total / len(self.variable_liststore)
if self.freq_table_enable_edit_button.get_label() == self._("button_save_as_initial_table"):
self.freq_table_enable_edit()
def notebook_switch_page(self, page_num):
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self.notbook_tabs[page_num])
if page_num < 4: return
if not self.trial_is_valid(show_msg=False, table_edit=True): return
if self.freq_table_enable_edit_button.get_label() == self._("button_save_as_initial_table"): return
self.refresh_freq_table()
self.balance_table_refresh()
def notebook_switch_page_event(self, notebook, page, page_num, data=None):
if not page_num in (4, 5): return
self.waiting_function(self.notebook_switch_page, (page_num,))
def license_button_clicked(self, widget, data=None):
self.display_about_dialog()
def display_about_dialog(self):
dialog = gtk.AboutDialog()
dialog.set_name(self._("minimpy_program"))
dialog.set_version("0.1")
dialog.set_copyright("Copyright (c) 2010-2011 Mahmoud Saghaei")
dialog.set_license("Distributed under the GNU GPL v3.\nFor full terms refer to http://www.gnu.org/copyleft/gpl.html.")
dialog.set_website("http://minimpy.sourceforge.net")
dialog.set_authors(["Mahmoud Saghaei"])
dialog.set_logo(self.pixbuf)
dialog.run()
dialog.destroy()
return False
dialog = gtk.MessageDialog(self.window, flags = gtk.DIALOG_MODAL, type =
gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_OK, message_format = "MinimPy Program\nCopyright (c) 2010-2011 Mahmoud Saghaei\nDistributed under the GNU GPL v3.\nFor full terms refer to http://www.gnu.org/copyleft/gpl.html.")
dialog.set_title(self._("about_minimpy_program"))
dialog.run()
dialog.destroy()
def trial_properties_cell_edited(self, cell, row, new_text, col):
self.trial_properties_liststore[row][col] = new_text
def trial_properties_add_button(self, widget, data=None):
self.trial_properties_liststore.append((self._('property_name'), self._('property_value')))
def trial_properties_delete_button(self, widget, data=None):
if self.network_sync_dict['sync'] and self.trial_file_name:
# with network trials, deleting trial properties after saving the trials may be too complicated.
return False
if self.trial_properties_treeview.get_cursor()[0]:
row = self.trial_properties_treeview.get_cursor()[0][0]
self.trial_properties_liststore.remove(self.trial_properties_liststore.get_iter(row))
def show_info_message(self, widget, event, message, tooltip):
dialog = gtk.MessageDialog(self.window, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_OK, message_format = message)
dialog.set_title(tooltip)
dialog.run()
dialog.destroy()
def create_image_info(self, parent, tooltip, message=""):
eb = gtk.EventBox()
img = gtk.Image()
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'b_info.png')
img.set_from_file(image_file)
eb.add(img)
if len(message):
eb.connect("button-press-event", self.show_info_message, message, tooltip)
tooltip += self._("click_to_see_more")
img.set_tooltip_text(tooltip)
img.set_has_tooltip(True)
parent.pack_start(eb, False, False)
def network_sync_ssl_server_trust_prompt(self, trust_dict):
return True, 3, True
def network_sync_get_login(self, realm, username, may_save):
self.get_repo_login()
return self.network_sync_dict['auth'], self.network_sync_user, self.network_sync_pw, True
def network_sync_chk_toggled(self, chk, data=None):
if not chk.get_active():
self.network_sync_dict['sync'] = False
return
dlg = gtk.Dialog(title= self._('network_sync'),
parent=self.window,
flags=gtk.DIALOG_MODAL,
buttons=(gtk.STOCK_APPLY, gtk.RESPONSE_APPLY, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
dlg.set_default_response(gtk.RESPONSE_APPLY)
dlg.set_has_separator(True)
lbl = gtk.Label(self._('enter_base_url'))
lbl.set_line_wrap(True)
dlg.vbox.pack_start(lbl)
sep = gtk.HSeparator()
dlg.vbox.pack_start(sep)
hb = gtk.HBox(False)
lbl = gtk.Label(self._('repository_url'))
hb.pack_start(lbl, False, False)
url = gtk.Entry()
if self.network_sync_dict.has_key('url'):
url.set_text(self.network_sync_dict['url'])
hb.pack_start(url, True, True)
dlg.vbox.pack_start(hb)
auth = gtk.CheckButton(self._('requires_authentication'))
auth.set_active(self.network_sync_dict['auth'])
dlg.vbox.pack_start(auth)
dlg.vbox.show_all()
controls = url, auth, chk
dlg.connect('response', self.network_sync_dialog_respnse, controls)
dlg.run()
def network_sync_dialog_respnse(self, dialog, response_id, controls):
if response_id in (gtk.RESPONSE_CANCEL, gtk.RESPONSE_DELETE_EVENT):
controls[-1].set_active(False)
dialog.hide()
return
url, auth, chk = controls
if url.get_text() == '':
dialog.set_focus(url)
return
self.network_sync_dict['sync'] = True
self.network_sync_dict['url'] = url.get_text()
self.network_sync_dict['auth'] = auth.get_active()
dialog.hide()
def get_repo_login(self):
if not self.network_sync_dict['auth']: return False
dlg = gtk.Dialog(title= self._('network_login'),
parent=self.window,
flags=gtk.DIALOG_MODAL,
buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
dlg.set_default_response(gtk.RESPONSE_OK)
dlg.set_has_separator(True)
lbl = gtk.Label(self._('enter_user_pw').format(self.network_sync_dict['url']))
dlg.vbox.pack_start(lbl)
hb = gtk.HBox(False)
lbl = gtk.Label(self._('username') + ': ')
hb.pack_start(lbl, False, False)
user = gtk.Entry()
user.set_text(self.network_sync_user)
hb.pack_start(user, True, True)
dlg.vbox.pack_start(hb)
hb = gtk.HBox(False)
lbl = gtk.Label(self._('password') + ': ')
hb.pack_start(lbl, False, False)
pw = gtk.Entry()
pw.set_visibility(False)
pw.set_text(self.network_sync_pw)
hb.pack_start(pw, True, True)
dlg.vbox.pack_start(hb)
dlg.vbox.show_all()
controls = user, pw
dlg.connect('response', self.get_repo_login_respnse, controls)
dlg.run()
def get_repo_login_respnse(self, dialog, response_id, controls):
if response_id in (gtk.RESPONSE_CANCEL, gtk.RESPONSE_DELETE_EVENT):
# self.network_sync_user = ''
# self.network_sync_pw = ''
dialog.hide()
self.network_sync_cancel_command = True
return
user, pw = controls
if user.get_text() == '':
dialog.set_focus(user)
return
if pw.get_text() == '':
dialog.set_focus(pw)
return
self.network_sync_user = user.get_text()
self.network_sync_pw = pw.get_text()
dialog.hide()
def variable_treeview_row_activated(self, treeview, path, view_column, data=None):
EditVariable(self, path[0])
def __init__(self):
self.restart = False
self.config_file = os.path.join(os.path.dirname(sys.argv[0]), 'config.cfg')
self.config = ConfigParser.RawConfigParser()
self.config.read(self.config_file)
if self.config.get('interface', 'layout_dir') == 'rtl':
gtk.widget_set_default_direction(gtk.TEXT_DIR_RTL)
elif self.config.get('interface', 'layout_dir') == 'ltr':
gtk.widget_set_default_direction(gtk.TEXT_DIR_LTR)
fp = open(os.path.join(os.path.dirname(sys.argv[0]), 'locale', self.config.get('interface', 'locale'), 'locale.dat'), 'rb')
self.tr_dict = pickle.load(fp)
fp.close()
self.factory = gtk.IconFactory()
self.factory.add_default()
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'undo-last.png')
functions.add_icon('UNDO_LAST', self._('undo_last'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'import.png')
functions.add_icon('IMPORT', self._('import'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'export.png')
functions.add_icon('EXPORT', self._('export'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'random-case.png')
functions.add_icon('RANDOM_CASE', self._('random_case'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'add-all.png')
functions.add_icon('ADD_ALL', self._('add_all'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'start-edit.png')
functions.add_icon('START_EDIT', self._('start_edit'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'clear-refresh.png')
functions.add_icon('CLEAR_REFRESH', self._('clear_refresh'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'dialog-apply.png')
functions.add_icon(gtk.STOCK_APPLY, self._('apply'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'dialog-cancel.png')
functions.add_icon(gtk.STOCK_CANCEL, self._('cancel'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'dialog-apply.png')
functions.add_icon(gtk.STOCK_OK, self._('ok'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'network-transmit-receive.png')
functions.add_icon(gtk.STOCK_CONNECT, self._('connected'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'list-add.png')
functions.add_icon(gtk.STOCK_ADD, self._('add'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'edit-delete.png')
functions.add_icon(gtk.STOCK_DELETE, self._('delete'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'document-new.png')
functions.add_icon(gtk.STOCK_NEW, self._('new'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'document-open.png')
functions.add_icon(gtk.STOCK_OPEN, self._('open'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'document-save.png')
functions.add_icon(gtk.STOCK_SAVE, self._('save'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'preferences-system.png')
functions.add_icon(gtk.STOCK_PREFERENCES, self._('preferences'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'dialog-information.png')
functions.add_icon(gtk.STOCK_INFO, self._('information'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'gtk-edit.png')
functions.add_icon(gtk.STOCK_EDIT, self._('edit'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'edit-clear.png')
functions.add_icon(gtk.STOCK_CLEAR, self._('clear'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'help-about.png')
functions.add_icon(gtk.STOCK_ABOUT, self._('about'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'network-offline.png')
functions.add_icon(gtk.STOCK_DISCONNECT, self._('disconnect'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'dialog-cancel.png')
functions.add_icon(gtk.STOCK_CLOSE, self._('close'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'dialog-cancel.png')
functions.add_icon(gtk.STOCK_NO, self._('no'), image_file, self.factory)
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'dialog-apply.png')
functions.add_icon(gtk.STOCK_YES, self._('yes'), image_file, self.factory)
self.file_chooser_current_folder = os.getcwd()
self.network_sync_cancel_command = False
self.random = functions.get_app_random(self.config)
if self.config.getboolean('project', 'load_recent'):
self.trial_file_name = self.config.get('project', 'recent_trial')
else:
self.trial_file_name = None
self.notbook_tabs = []
self.ui_pool = []
self.initial_freq_table = False
self.allocations = []
self.network_sync_dict = dict(sync=False, url='', auth=False)
self.network_sync_user = ''
self.network_sync_pw = ''
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_title(self._("minimpy_program"))
self.window.connect("delete_event", self.delete_event)
self.window.set_border_width(2)
self.window.set_size_request(int(0.99 * gtk.gdk.screen_width()), int(0.85 * gtk.gdk.screen_height()))
module_list = ['os', 'sys', 'pickle', 'tempfile', 'ConfigParser', 'shutil', 'time', 'math', 'random', 'pygtk', 'gtk', 'gobject', 'pickle', 'pysvn']
ret = functions.check_dependencies(module_list)
if ret:
msg = self._('required_module_msq'.format('\t'.join(ret)))
functions.error_dialog(self.window, msg, self._('module_not_found'))
self.window.destroy()
gtk.main_quit()
label = gtk.Label("")
label.show()
dialog = gtk.MessageDialog(self.window, flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
dialog.set_title("")
dialog.vbox.pack_end(label)
self.network_sync_dialog = dialog
self.network_sync_dialog_label = label
self.notebook = gtk.Notebook()
self.notebook.set_tab_pos(self.config.getint('interface', 'tab_pos'))
self.notebook.popup_enable()
self.notebook.connect("switch-page", self.notebook_switch_page_event)
img = gtk.Image()
image_file = os.path.join(os.path.dirname(sys.argv[0]), 'images', 'logo.png')
img.set_from_file(image_file)
img.show()
self.pixbuf = img.get_pixbuf()
win_vbox = gtk.VBox(False)
win_vbox.pack_start(self.notebook, True, True)
hb = gtk.HBox(False)
self.statusbar = gtk.Statusbar()
hb.pack_start(self.statusbar, True, True)
icon_box = gtk.HBox(False)
self.network_sync_icon = gtk.Image()
self.network_sync_icon.set_from_stock(gtk.STOCK_CONNECT, gtk.ICON_SIZE_SMALL_TOOLBAR)
self.network_sync_icon.set_tooltip_text(self._('network_sync_enabled'))
icon_box.pack_start(self.network_sync_icon, False, False)
hb.pack_start(icon_box, False, False)
win_vbox.pack_start(hb, False, False, 0)
self.sb_context_id = self.statusbar.get_context_id("Statusbar")
nb_vbx = gtk.VBox(False)
hbx1 = gtk.HBox(False)
label = gtk.Label(self._("trial_title") + ": ")
hbx1.pack_start(label, False, False)
self.create_image_info(hbx1, self._("trial_title"), self._("trial_title_info"))
self.trial_title_entry = gtk.Entry()
hbx1.pack_start(self.trial_title_entry, True, True)
label = gtk.Label(self._("sample_size") + ": ")
hbx1.pack_start(label, False, False)
self.create_image_info(hbx1, self._("sample_size"), self._("sample_size_info"))
adj = gtk.Adjustment(value=30, lower=5, upper=1000000, step_incr=1, page_incr=10)
self.trial_sample_size_spin = gtk.SpinButton(adj)
hbx1.pack_start(self.trial_sample_size_spin, False, False)
nb_vbx.pack_start(hbx1, False, False)
hbx2 = gtk.HBox(False)
label = gtk.Label(self._("description") + ": ")
hbx2.pack_start(label, False, False)
self.create_image_info(hbx2, self._("trial_description"), self._("trial_description_info"))
nb_vbx.pack_start(hbx2, False, False)
sep = gtk.HSeparator()
nb_vbx.pack_start(sep, False, False)
hbx3 = gtk.HBox(False)
sep = gtk.VSeparator()
hbx3.pack_start(sep, False, False)
self.trial_description_text = gtk.TextView()
hbx3.pack_start(self.trial_description_text, True, True)
sep = gtk.VSeparator()
hbx3.pack_start(sep, False, False)
nb_vbx.pack_start(hbx3, True, True)
sep = gtk.HSeparator()
nb_vbx.pack_start(sep, False, False)
hbx4 = gtk.HBox(False)
nb_vbx.pack_start(hbx4, True, True)
label = gtk.Label(self._("probability_method") + ": ")
hb = gtk.HBox(False)
hb.pack_start(label, False, False)
self.create_image_info(hb, self._("probability_method"), self._("probability_method_info"))
vbox_prob = gtk.VBox(False)
vbox_prob.pack_start(hb, False, False)
radio = gtk.RadioButton(None, label= self._("biased_coin_minimization"))
vbox_prob.pack_start(radio, False, False)
radio = gtk.RadioButton(radio, label= self._("naive_minimization"))
vbox_prob.pack_start(radio, False, False)
# this method returns the radios in revese order
self.prob_method_radios = radio.get_group()
# so we need to invert the returned list
self.prob_method_radios.reverse()
hb = gtk.HBox(False)
lbl = gtk.Label(self._("min_group") + ": ")
hb.pack_start(lbl, False, False)
self.create_image_info(hb, self._("min_group_tip"), self._("min_group_info"))
self.min_group_combo = gtk.combo_box_new_text()
hb.pack_start(self.min_group_combo, False, False)
vbox_prob.pack_start(hb, False, False)
hb = gtk.HBox(False)
lbl = gtk.Label(self._("high_probability") + ": ")
hb.pack_start(lbl, False, False)
self.create_image_info(hb, self._("high_probability_tip"), self._("high_probability_info"))
adj = gtk.Adjustment(value=0.7, lower=0.1, upper=1.0, step_incr=0.01, page_incr=0.1)
self.high_prob_spin = gtk.SpinButton(adj, digits=2)
hb.pack_start(self.high_prob_spin, False, False)
vbox_prob.pack_start(hb, False, False)
hbx4.pack_start(vbox_prob, False, False)
sep = gtk.VSeparator()
hbx4.pack_start(sep, False, False)
label = gtk.Label(self._("distance_measure") + ": ")
hb = gtk.HBox(False)
hb.pack_start(label, False, False)
self.create_image_info(hb, self._("distance_measure_tip"))
vbox = gtk.VBox(False)
vbox.pack_start(hb, False, False)
radio = gtk.RadioButton(None, label= self._("marginal_balance") + ": ")
hb = gtk.HBox(False)
hb.pack_start(radio, False, False)
self.create_image_info(hb, self._("marginal_balance"), self._("marginal_balance_info"))
vbox.pack_start(hb, False, False)
radio = gtk.RadioButton(radio, label= self._("range") + ": ")
hb = gtk.HBox(False)
hb.pack_start(radio, False, False)
vbox.pack_start(hb, False, False)
self.create_image_info(hb, self._("range"), self._("range_info"))
radio = gtk.RadioButton(radio, label= self._("standard_deviation") + ": ")
hb = gtk.HBox(False)
hb.pack_start(radio, False, False)
vbox.pack_start(hb, False, False)
self.create_image_info(hb, self._("standard_deviation"), self._("standard_deviation_info"))
radio = gtk.RadioButton(radio, label= self._("variance") + ": ")
hb = gtk.HBox(False)
hb.pack_start(radio, False, False)
vbox.pack_start(hb, False, False)
self.create_image_info(hb, self._("variance"), self._("variance_info"))
hbx4.pack_start(vbox, False, False)
self.distance_measure_radios = radio.get_group()
self.distance_measure_radios.reverse()
sep = gtk.VSeparator()
hbx4.pack_start(sep, False, False)
vbox = gtk.VBox(False)
lbl = gtk.Label(self._("trial_properties") + ": ")
hb = gtk.HBox(False)
hb.pack_start(lbl, False, False)
vbox.pack_start(hb, False, False)
self.create_image_info(hb, self._("trial_properties"), self._("trial_properties_info"))
hb = gtk.HBox(False)
self.trial_properties_liststore, self.trial_properties_treeview = functions.make_treeview(
(str, str), [self._('name'), self._('value')],
editable=True, edit_handler=self.trial_properties_cell_edited)
hb.pack_start(self.trial_properties_treeview, True, True)
vbuttonbox = gtk.VButtonBox()
vbuttonbox.set_layout(gtk.BUTTONBOX_START)
button = gtk.Button(None, gtk.STOCK_ADD)
button.connect("clicked", self.trial_properties_add_button)
vbuttonbox.pack_start(button, False, False)
button = gtk.Button(None, gtk.STOCK_DELETE)
button.connect("clicked", self.trial_properties_delete_button)
vbuttonbox.pack_start(button, False, False)
hb.pack_start(vbuttonbox, False, False)
vbox.pack_start(hb, False, False)
hbx4.pack_start(vbox, True, True)
sep = gtk.VSeparator()
hbx4.pack_start(sep, False, False)
sep = gtk.HSeparator()
nb_vbx.pack_start(sep, False, False)
hbuttonbox = gtk.HButtonBox()
hbuttonbox.set_layout(gtk.BUTTONBOX_START)
self.trial_new_button = gtk.Button(None, gtk.STOCK_NEW)
self.trial_new_button.connect("clicked", self.new_trial_clicked)
hbuttonbox.pack_start(self.trial_new_button, False, False)
self.trial_load_button = gtk.Button(None, gtk.STOCK_OPEN)
self.trial_load_button.connect("clicked", self.load_trial_clicked)
hbuttonbox.pack_start(self.trial_load_button, False, False)
self.trial_save_button = gtk.Button(None, gtk.STOCK_SAVE)
self.trial_save_button.connect("clicked", self.save_trial_clicked)
hbuttonbox.pack_start(self.trial_save_button, False, False)
self.network_sync_chk = gtk.CheckButton(self._('network_sync'))
self.network_sync_chk.set_sensitive(False)
self.network_sync_chk_event_id = self.network_sync_chk.connect("toggled", self.network_sync_chk_toggled)
hbuttonbox.pack_start(self.network_sync_chk, False, False)
if pysvn_available:
self.network_sync_chk.set_sensitive(True)
self.pref_button = gtk.Button(None, gtk.STOCK_PREFERENCES)
self.pref_button.connect("clicked", self.pref_clicked)
hbuttonbox.pack_start(self.pref_button, False, False)
button = gtk.Button(None, gtk.STOCK_INFO)
button.connect("clicked", self.trial_info_button_clicked)
hbuttonbox.pack_start(button, False, False)
nb_vbx.pack_start(hbuttonbox, False, False)
lbl = gtk.Label(self._("settings_tab"))
self.notbook_tabs.append(self._("settings_tab_info"))
self.notebook.append_page(nb_vbx, lbl)
hbox = gtk.HBox(False)
self.group_liststore, self.group_treeview = functions.make_treeview(
(str, int), [self._('group_name'), self._('allocation_ratio')],
editable=True, edit_handler=self.group_cell_edited)
vb = gtk.VBox(False)
self.create_image_info(vb, self._('group_table'), self._('group_table_info'))
vb.pack_start(self.group_treeview, True, True)
hbox.pack_start(vb, True, True)
vbuttonbox = gtk.VButtonBox()
vbuttonbox.set_layout(gtk.BUTTONBOX_START)
button = gtk.Button(None, gtk.STOCK_ADD)
button.connect("clicked", self.group_add_button)
vbuttonbox.pack_start(button, False, False)
button = gtk.Button(None, gtk.STOCK_DELETE)
button.connect("clicked", self.group_delete_button)
vbuttonbox.pack_start(button, False, False)
hbox.pack_start(vbuttonbox, False, False)
lbl = gtk.Label(self._('groups_tab'))
self.notbook_tabs.append(self._("groups_tab_info"))
self.group_hbox = hbox
self.notebook.append_page(hbox, lbl)
hbox = gtk.HBox(False)
self.variable_liststore, self.variable_treeview = functions.make_treeview(
(str, float, str), [self._('variable_name'), self._('weight'), self._('levels')],
editable=True, edit_handler=self.variable_cell_edited)
tvcolumn = gtk.TreeViewColumn(self._('doubl_click_to_edit'))
self.variable_treeview.append_column(tvcolumn)
cell = gtk.CellRendererPixbuf()
tvcolumn.pack_start(cell, True)
cell.set_property('stock-id', gtk.STOCK_EDIT)
tvcolumn.set_resizable(False)
tvcolumn.set_expand(False)
self.variable_treeview.connect('row-activated', self.variable_treeview_row_activated)
vb = gtk.VBox(False)
self.create_image_info(vb, self._("variable_table"), self._("variable_table_info"))
vb.pack_start(self.variable_treeview, True, True)
hbox.pack_start(vb, True, True)
vbuttonbox = gtk.VButtonBox()
vbuttonbox.set_layout(gtk.BUTTONBOX_START)
button = gtk.Button(None, gtk.STOCK_ADD)
button.connect("clicked", self.variable_add_button)
vbuttonbox.pack_start(button, False, False)
button = gtk.Button(None, gtk.STOCK_DELETE)
button.connect("clicked", self.variable_delete_button)
vbuttonbox.pack_start(button, False, False)
hbox.pack_start(vbuttonbox, False, False)
lbl = gtk.Label(self._('variables_tab'))
self.notbook_tabs.append(self._("variables_tab_info"))
self.variable_hbox = hbox
self.notebook.append_page(hbox, lbl)
hbox = gtk.HBox(False)
vbox = gtk.VBox(False)
vb = gtk.VBox(False)
self.create_image_info(vb, self._("allocations_table"), self._("allocations_table_info"))
hb_button_box = gtk.HBox()
self.hbuttonbox_batch_mode = gtk.HButtonBox()
self.hbuttonbox_batch_mode.set_layout(gtk.BUTTONBOX_START)
button = gtk.Button(None, "ADD_ALL")
button.connect("clicked", self.allocations_add_all_button)
self.hbuttonbox_batch_mode.pack_start(button, False, False)
button = gtk.Button(None, "RANDOM_CASE")
button.connect("clicked", self.random_case_button)
self.hbuttonbox_batch_mode.pack_start(button, False, False)
button = gtk.Button(None, gtk.STOCK_CLEAR)
button.connect("clicked", self.allocations_clear_button)
self.hbuttonbox_batch_mode.pack_start(button, False, False)
hb_button_box.pack_start(self.hbuttonbox_batch_mode, True, True)
hbuttonbox = gtk.HButtonBox()
hbuttonbox.set_layout(gtk.BUTTONBOX_START)
button = gtk.Button(None, gtk.STOCK_ADD)
button.connect("clicked", self.allocations_add_button)
hbuttonbox.pack_start(button, False, False)
button = gtk.Button(None, gtk.STOCK_DELETE)
button.connect("clicked", self.allocations_delete_button)
hbuttonbox.pack_start(button, False, False)
button = gtk.Button(None, 'IMPORT')
button.connect("clicked", self.allocations_import_button)
hbuttonbox.pack_start(button, False, False)
button = gtk.Button(None, 'EXPORT')
button.connect("clicked", self.allocations_export_button)
hbuttonbox.pack_start(button, False, False)
hb_button_box.pack_start(hbuttonbox, True, True)
vb.pack_start(hb_button_box, False, False)
self.allocations_treeview = gtk.TreeView()
vb.pack_start(self.allocations_treeview, True, True)
hbox.pack_start(vb, True, True)
self.combo_vbox = gtk.VBox(False)
vbox.pack_start(self.combo_vbox, False, False)
hbox.pack_start(vbox, False, False)
lbl = gtk.Label(self._('allocations_tab'))
self.notbook_tabs.append(self._('allocations_tab_info'))
self.notebook.append_page(hbox, lbl)
vbox = gtk.VBox(False)
self.create_image_info(vbox, self._("frequency_table"), self._("frequency_table_info"))
self.freq_table_treeview = gtk.TreeView()
vbox.pack_start(self.freq_table_treeview, False, False)
self.initial_table_hbox = gtk.HBox(False)
self.freq_table_enable_edit_button = gtk.Button(None, "START_EDIT")
self.freq_table_enable_edit_button.connect("clicked", self.freq_table_start_edit_clicked)
self.initial_table_hbox.pack_start(self.freq_table_enable_edit_button, False, False)
button = gtk.Button(None, "CLEAR_REFRESH")
button.connect("clicked", self.freq_table_delete_initial_clicked)
self.initial_table_hbox.pack_start(button, False, False)
vbox.pack_start(self.initial_table_hbox, False, False)
lbl = gtk.Label(self._('table_tab'))
self.notbook_tabs.append(self._("table_tab_info"))
self.notebook.append_page(vbox, lbl)
hbox = gtk.HBox(False)
vb = gtk.VBox(False)
self.create_image_info(vb, self._("balance_table"), self._("balance_table_info"))
treestore = gtk.TreeStore(str, float, float, float, float)
self.balance_table_treeview = gtk.TreeView(treestore)
col_names = [self._('variable_level'), self._('marginal_balance'), self._('range'), self._('variance'), 'SD']
for i in range(5):
cell = gtk.CellRendererText()
column = gtk.TreeViewColumn(col_names[i], cell, text=i)
self.balance_table_treeview.append_column(column)
vb.pack_start(self.balance_table_treeview, True, True)
hbox.pack_start(vb, True, True)
lbl = gtk.Label(self._('balance_tab'))
self.notbook_tabs.append(self._("balance_tab_info"))
self.notebook.append_page(hbox, lbl)
hbox = gtk.HBox(True)
self.about_text = gtk.TextView()
self.about_text.set_wrap_mode(gtk.WRAP_WORD)
self.about_text.set_editable(False)
self.about_text.set_cursor_visible(False)
self.about_text.set_left_margin(20)
self.about_text.set_right_margin(20)
about_text = self._('about_text')
functions.set_text_buffer(self.about_text, about_text)
hbox.pack_start(self.about_text)
button = gtk.Button(None, gtk.STOCK_ABOUT)
button.connect("clicked", self.license_button_clicked)
functions.textview_add_widget(self.about_text, 0, button)
uri = 'file://' + os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), 'doc', 'index.html')
button = gtk.LinkButton(uri, self._("quick_start_guide"))
functions.textview_add_widget(self.about_text, 0, button)
self.notbook_tabs.append(self._("help_tab_info"))
lbl = gtk.Label(self._('help_tab'))
self.notebook.append_page(hbox, lbl)
self.notebook.set_show_tabs(True)
self.window.add(win_vbox)
self.window.show_all()
if self.trial_file_name:
self.waiting_function(self.load_trial, (self.trial_file_name,))
if not self.trial_file_name:
functions.error_dialog(self.window, self._('load_error_msg'))
self.set_new_trial()
else:
self.set_new_trial()
if not self.config.getboolean('interface', 'batch_allocation'):
self.hbuttonbox_batch_mode.hide()
def allocations_import(self):
if self.network_sync_dict['sync'] and self.trial_file_name:
repo_path = self.update_network_trial()
model = self.allocations_treeview.get_model()
if not model:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._("statusbar_groups_prognostic_factors_must_be_defined"))
return False
if not self.ui_pool:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._('statusbar_trial_finished_or_not_saved'))
return False
file_name = self.select_file(self._("select_file"), gtk.FILE_CHOOSER_ACTION_OPEN)
if not file_name:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._("statusbar_import_canceled"))
return False
rows = open(file_name).readlines()
if not rows:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._("statusbar_empty_file"))
return False
for cnt, row in enumerate(rows):
if len(self.ui_pool) == 0:
msg = '{0} record{1} imported'.format(cnt, ('', 's')[cnt>0])
dialog = gtk.MessageDialog(self.window, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_INFO,
buttons=gtk.BUTTONS_OK, message_format = msg)
dialog.set_title(self._("finished_importing"))
dialog.run()
dialog.destroy()
break
try:
row = map(str.strip, row.split(','))[2:]
group = row[0]
if not group.isdigit():
raise Exception, self._('bad_file_format')
group = int(group)
row = row[1:]
if len(row) != len(self.variable_combos):
raise Exception, self._('bad_file_format')
if not all(map(str.isdigit, row)):
raise Exception, self._('bad_file_format')
for idx, level in enumerate(row):
cbo = self.variable_combos[idx]
cbo.set_active(int(level))
model.append()
ui = self.ui_pool.pop()
new_case = {'levels': [], 'allocation': -1, 'UI': ui}
row = len(model)-1
model[row][0] = row
model[row][1] = ui
for col, cbo in enumerate(self.variable_combos):
model[row][col+3] = cbo.get_active_text()
new_case['levels'].append(cbo.get_active())
new_case['allocation'] = group
model[row][2] = self.group_liststore[group][0]
self.allocations.append(new_case)
except Exception as err:
msg = self._('error_in_import') + str(err) + self._('original_data_will_resotre')
dialog = gtk.MessageDialog(self.window, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_INFO,
buttons=gtk.BUTTONS_OK, message_format = msg)
dialog.set_title(self._("import_failed"))
dialog.run()
dialog.destroy()
if self.trial_file_name:
self.load_trial(self.trial_file_name)
if not self.trial_file_name:
functions.error_dialog(self.window, self._('critical_error_restoring_trial'), self._('trial_restore_failed'))
self.set_new_trial()
else:
self.set_new_trial()
return
if self.network_sync_dict['sync']:
path = repo_path
else:
path = self.trial_file_name
self.save_trial(path)
def allocations_import_button(self, widget, data=None):
self.waiting_function(self.allocations_import, ())
def allocations_export(self):
if self.network_sync_dict['sync'] and self.trial_file_name:
repo_path = self.update_network_trial()
self.remove_folder(repo_path)
if not self.trial_file_name:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._("statusbar_save_trial_first"))
return False
Export(self)
def allocations_export_button(self, widget, data=None):
self.waiting_function(self.allocations_export, ())
def trial_info_button_clicked(self, widget, data=None):
det_file_name = self.save_trial_details_temp()
uri = 'file://' + det_file_name
button = gtk.LinkButton(uri, self._('more'))
button.show()
info = self.get_trial_info()
info = info[:80] + ' ...'
dialog = gtk.MessageDialog(self.window, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_OK, message_format = info)
dialog.vbox.pack_start(button)
dialog.set_title(self._("trial_information"))
dialog.run()
self.remove_temp_file(det_file_name)
dialog.destroy()
def pref_clicked(self, widget, data=None):
PrefWin(self)
def new_trial_clicked(self, widget, data=None):
if not self.query_trial_dismis():
return False
self.set_new_trial()
def set_new_trial(self):
self.trial_file_name = None
self.trial_title_entry.set_text('')
self.trial_sample_size_spin.set_value(30)
functions.set_text_buffer(self.trial_description_text, '')
self.trial_properties_liststore.clear()
self.high_prob_spin.set_value(0.7)
self.prob_method_radios[0].set_active(True)
self.distance_measure_radios[0].set_active(True)
self.group_liststore.clear()
self.variable_liststore.clear()
self.allocations_treeview.set_model()
self.allocations = []
self.freq_table_treeview.set_model()
self.initial_freq_table = False
self.freq_table_treeview.set_model()
self.update_interface()
self.min_group_combo.get_model().clear
self.lock_trial(unlock=True)
self.ui_pool = []
self.network_sync_chk.set_active(False)
self.network_sync_dict = dict(sync=False, url='', auth=False)
self.window.set_title(self._('window_untitled'))
self.notebook.set_current_page(0)
def balance_table_refresh(self):
if self.network_sync_dict['sync'] and self.trial_file_name:
repo_path = self.update_network_trial()
self.remove_folder(repo_path)
liststore = self.freq_table_treeview.get_model()
if not liststore:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._("statusbar_no_allocation"))
return False
table = []
for row in range(len(liststore)-1):
table.append([])
for col in range(1, len(liststore[0])-1):
table[row].append(liststore[row][col])
balance = self.get_trial_balances(table)
treestore = self.balance_table_treeview.get_model()
treestore.clear()
variables = [range(len(self.variable_liststore[row][2].split(','))) for row in range(len(self.variable_liststore))]
row = 0
for idx, variable in enumerate(variables):
wt = self.variable_liststore[idx][1]
var_total = [0] * 4
level_rows = []
for level in variable:
for i in range(4):
# here I applied the var weights to the final balance.
# I am not sure if we should do this
# fixme
balance[row][i] *= float(wt)
var_total[i] += balance[row][i]
level_rows.append(balance[row])
row += 1
var_total = [self.variable_liststore[idx][0]] + [var_total[i] / len(variable) for i in range(4)]
variable_node = treestore.append(None, var_total)
level_names = map(str.strip, self.variable_liststore[idx][2].split(','))
for level, level_row in enumerate(level_rows):
treestore.append(variable_node, [level_names[level]] + level_row)
last_row = row
rows = len(balance)-2
for col in range(4):
balance[rows].append(1.0 * sum([balance[row][col] for row in range(rows)]) / rows)
balance[rows+1].append(max([balance[row][col] for row in range(rows)]))
treestore.append(None, [self._('mean')] + balance[last_row])
treestore.append(None, [self._('max')] + balance[last_row+1])
def get_trial_balances(self, table):
model = Model()
m = Minim(random=self.random, model=model)
levels = [[] for col in table[0]]
balances = [[] for col in table[0]] + [[], []]
for row in table:
for col, value in enumerate(row):
levels[col].append(value)
allocation_ratio = [self.group_liststore[r][1] for r in range(len(self.group_liststore))]
for row, level_count in enumerate(levels):
adj_count = [(1.0 * level_count[i]) / allocation_ratio[i] for i in range(len(level_count))]
balances[row].append(m.get_marginal_balance(adj_count))
balances[row].append(max(adj_count) - min(adj_count))
balances[row].append(m.get_variance(adj_count))
balances[row].append(m.get_standard_deviation(adj_count))
return balances
def freq_table_disable_edit(self):
functions.treeview_disable_edit(self.freq_table_treeview)
def freq_table_enable_edit(self):
functions.treeview_enable_edit(self.freq_table_treeview, self.freq_table_treeview_edit_handler)
def freq_table_start_edit_clicked(self, button, data=False):
initial_freq_model = self.freq_table_treeview.get_model()
if not initial_freq_model:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._("statusbar_trial_not_initialized"))
return False
if not len(initial_freq_model):
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._("statusbar_trial_not_initialized"))
return False
if button.get_label() == self._("start_edit"):
self.freq_table_enable_edit()
button.set_label(self._("save_as_initial_table"))
else:
if initial_freq_model[-1][-1] == -1:
functions.error_dialog(self.window, self._('initial_frequency_table_error'), self._('frequency_table_error'))
return False
groups = range(len(self.group_liststore))
variables = [range(len(self.variable_liststore[row][2].split(','))) for row in range(len(self.variable_liststore))]
table = [[[0 for l in v] for v in variables] for g in groups]
for row, group in enumerate(table):
col = 1
for v, variable in enumerate(group):
for l, level in enumerate(variable):
table[row][v][l] = initial_freq_model[row][col]
col += 1
self.initial_freq_table = table
button.set_label(self._("start_edit"))
self.freq_table_disable_edit()
def freq_table_treeview_edit_handler(self, cell, row, new_text, col):
model = self.freq_table_treeview.get_model()
if (col == 0) or (int(row) == (len(model) - 1)) or (col == (len(model[0]) - 1)):
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._("statusbar_cell_can_not-be_changed"))
return False
if not new_text.isdigit():
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._("statusbar_only_interger_values"))
return False
model[row][col] = int(new_text)
col_sum = 0
for r in range(len(model)-1):
col_sum += model[r][col]
model[-1][col] = col_sum
variables = [range(len(self.variable_liststore[r][2].split(','))) for r in range(len(self.variable_liststore) )]
table_row = [[0 for L in v] for v in variables]
cum_cols = 0
for v, variable in enumerate(table_row):
cum_cols += len(variable)
if cum_cols >= col:
sel_cols = range(cum_cols - len(variable) + 1, cum_cols + 1)
break
row_sum = 0
for c in sel_cols:
row_sum += model[row][c]
err_sum = False
cum_cols = 0
for v, variable in enumerate(table_row):
cum_cols += len(variable)
sel_cols = range(cum_cols - len(variable) + 1, cum_cols + 1)
row_sum_ext = 0
for c in sel_cols:
row_sum_ext += model[row][c]
if row_sum_ext != row_sum: err_sum = True
if not err_sum:
model[row][-1] = row_sum
else:
model[row][-1] = -1
total = 0
for r in range(len(model)-1):
total += model[r][-1]
if not err_sum:
model[-1][-1] = total
else:
model[-1][-1] = -1
def freq_table_delete_initial_clicked(self, button, data=None):
initial_freq_model = self.freq_table_treeview.get_model()
if not initial_freq_model:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._("statusbar_trial_not_initialized"))
return False
msg = self._("warning_initial_frequency_table_delete")
dialog = gtk.MessageDialog(self.window, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format = msg)
dialog.set_title(self._("initial_table_delete_refresh"))
if dialog.run() == gtk.RESPONSE_NO:
dialog.destroy()
return False
dialog.destroy()
self.refresh_freq_table()
self.initial_freq_table = False
self.freq_table_disable_edit()
self.freq_table_enable_edit_button.set_label(self._("start_edit"))
def load_trial_clicked(self, button, data=None):
if not self.query_trial_dismis():
return False
file_name = self.select_file(self._("enter_file_name"), gtk.FILE_CHOOSER_ACTION_OPEN)
if not file_name:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._("statusbar_trial_save_canceled"))
return False
self.waiting_function(self.load_trial, (file_name,))
def try_network_info_file(self, file_name):
try:
fp = open(file_name, 'rb')
data = pickle.load(fp)
fp.close()
except:
# file is invalid
return -1
if data.has_key('network_sync') and data.has_key('trial_name'):
self.trial_file_name = file_name
if self.update_network_trial():
self.lock_trial()
# file is valid and trial loaded
return 1
else:
self.set_new_trial()
# file is valid but trial not loaded
return 0
else:
self.set_new_trial()
# file is invalid
return -1
def save_trial_changes(self):
trial_title = self.trial_title_entry.get_text()
sample_size = self.trial_sample_size_spin.get_value()
ui_pool = self.ui_pool
trial_description = functions.get_text_buffer(self.trial_description_text)
cbo_selects = []
for cbo in self.variable_combos:
cbo_selects.append(cbo.get_active())
trial_properties = self.get_trial_properties()
if self.network_sync_dict['sync'] and self.trial_file_name:
repo_path = self.update_network_trial()
self.trial_title_entry.set_text(trial_title)
self.trial_sample_size_spin.set_value(sample_size)
self.ui_pool = ui_pool
functions.set_text_buffer(self.trial_description_text, trial_description)
for i, cbo in enumerate(self.variable_combos):
cbo.set_active(cbo_selects[i])
self.set_trial_properties(trial_properties)
if self.network_sync_dict['sync']:
path = repo_path
else:
path = self.trial_file_name
self.save_trial(path)
def save_trial_event(self):
# is this an update or save
if self.trial_file_name:
self.save_trial_changes()
return False
if not self.trial_is_valid():
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._("trial_not_ready_to_save"))
return False
file_name = self.select_file(self._("enter_file_name"), gtk.FILE_CHOOSER_ACTION_SAVE)
if not file_name:
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, self._("statusbar_trial_save_canceled"))
return False
self.build_ui_pool()
self.trial_file_name = self.save_trial(file_name, initial=True)
def save_trial_clicked(self, button, data=None):
self.waiting_function(self.save_trial_event, ())
def set_groups_data(self, groups):
self.group_liststore.clear()
for group in groups:
self.group_liststore.append((group['name'], group['allocation_ratio']))
def set_variables_data(self, variables):
self.variable_liststore.clear()
for variable in variables:
self.variable_liststore.append((variable['name'], variable['weight'], variable['levels']))
def build_ui_pool(self, lst=None):
if not lst:
ss = self.trial_sample_size_spin.get_value_as_int()
lst = range(ss)
self.random.shuffle(lst)
self.ui_pool = map(lambda x: x.zfill(len(str(max(lst)))), map(str, lst))
def get_trial_properties(self):
table = [['', ''] for row in range(len(self.trial_properties_liststore))]
for row in range(len(table)):
for col in range(len(table[0])):
table[row][col] = self.trial_properties_liststore[row][col]
return table
def set_trial_properties(self, table):
self.trial_properties_liststore.clear()
for row in range(len(table)):
self.trial_properties_liststore.append(table[row])
def trial_is_valid(self, show_msg=True, ret_code=None, table_edit=False):
if not self.trial_title_entry.get_text() and not table_edit:
if show_msg:
functions.error_dialog(self.window, self._("trial_title_first"), self._("trial_title"))
self.notebook.set_current_page(0)
self.window.set_focus(self.trial_title_entry)
return False
if self.trial_title_entry.get_text():
if self.network_sync_dict['sync']:
title = '_'.join(self.trial_title_entry.get_text().split())[:10]
for char in title:
if char in self.invalid_chars:
if show_msg:
functions.error_dialog(self.window, self._("invalid_character").format(char), self._("trial_title"))
return False
if not functions.get_text_buffer(self.trial_description_text) and not table_edit:
if show_msg:
functions.error_dialog(self.window, self._("enter_trial_description"), self._("trial_description"))
self.notebook.set_current_page(0)
self.window.set_focus(self.trial_description_text)
return False
if len(self.group_liststore) < 2:
if show_msg:
functions.error_dialog(self.window, self._("two_groups_needed"), self._("trial_groups"))
self.notebook.set_current_page(1)
self.window.set_focus(self.group_treeview)
return False
if len(self.variable_liststore) < 1:
if show_msg:
functions.error_dialog(self.window, self._("prognostic_factor_required"), self._("trial_variables"))
self.notebook.set_current_page(2)
self.window.set_focus(self.variable_treeview)
return False
if not show_msg: return True
return self.display_trial_details_response()
def save_trial_details_temp(self):
details = '<html><head><title>' + self._('trial_details') + '</title></head><body>' + self.get_trial_info().replace('\n', '<br />') + '</body></html>'
det_file_name = tempfile.mkstemp(suffix='.html')[1]
fp = open(det_file_name, 'w')
fp.write(details)
fp.flush()
fp.close()
return det_file_name
def display_trial_details_response(self):
msg = self._("want_save_trial")
dialog = gtk.MessageDialog(self.window, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format = msg)
dialog.set_title(self._("trial_save"))
det_file_name = self.save_trial_details_temp()
uri = 'file://' + det_file_name
button = gtk.LinkButton(uri, self._("trial_details"))
button.show()
dialog.vbox.pack_start(button)
if dialog.run() == gtk.RESPONSE_YES:
self.remove_temp_file(det_file_name)
dialog.destroy()
return True
dialog.destroy()
self.remove_temp_file(det_file_name)
return False
def remove_temp_file(self, file_name):
try:
os.remove(file_name)
except:
pass
def want_trial_unlock(self, prompt=True):
if prompt:
msg = self._("want_unlock_trial")
dialog = gtk.MessageDialog(self.window, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format = msg)
dialog.set_title(self._("unlock_trial"))
if dialog.run() == gtk.RESPONSE_NO:
dialog.destroy()
return False
dialog.destroy()
self.lock_trial(unlock=True)
self.ui_pool = []
self.trial_file_name = None
def lock_trial(self, unlock=False):
if pysvn_available:
self.network_sync_chk.set_property("sensitive", unlock)
self.trial_sample_size_spin.set_property("sensitive", unlock)
for radio in self.prob_method_radios:
radio.set_property("sensitive", unlock)
self.min_group_combo.set_property("sensitive", unlock)
self.high_prob_spin.set_property("sensitive", unlock)
for radio in self.distance_measure_radios:
radio.set_property("sensitive", unlock)
for child in self.group_hbox.get_children():
child.set_property("sensitive", unlock)
for child in self.variable_hbox.get_children():
child.set_property("sensitive", unlock)
for child in self.initial_table_hbox.get_children():
child.set_property("sensitive", unlock)
self.statusbar.pop(self.sb_context_id)
self.statusbar.push(self.sb_context_id, (self._("trial_locked"), self._("trial_unlocked"))[unlock])
def get_trial_info(self):
ret = []
ret.append(self._("title") + ": " + self.trial_title_entry.get_text())
ret.append(self._("sample_size") + ": " + str(self.trial_sample_size_spin.get_value_as_int()))
ret.append(self._("description") + ": " + functions.get_text_buffer(self.trial_description_text))
ret.append(self._("probability_method") + ": " + self.get_prob_method_name())
ret.append(self._("distance_measure") + ": " + self.get_distance_measure_name())
ret.append(self._("high_probability") + ": " + str(self.high_prob_spin.get_value()))
ret.append(self._("groups") + ":\n" + str(self.get_groups_info()))
ret.append(self._("variables") + ":\n" + str(self.get_variables_info()))
return '\n'.join(ret)
def load_trial_from_file(self, file_name):
fp = open(file_name, 'rb')
data = pickle.load(fp)
fp.close()
self.ui_pool = data['ui_pool']
self.trial_title_entry.set_text(data['trial_title'])
if self.network_sync_dict['url']:
self.window.set_title(self._('main_window_title_url').format(self.network_sync_dict['url'], data['trial_title']))
else:
self.window.set_title(self._('main_window_title').format(data['trial_title']))
functions.set_text_buffer(self.trial_description_text, data['trial_description'])
self.set_trial_properties(data['trial_properties'])
self.allocations = data['allocations']
self.trial_sample_size_spin.set_value(data['sample_size'])
self.high_prob_spin.set_value(data['high_prob'])
self.initial_freq_table = data['initial_freq_table']
self.prob_method_radios[data['prob_method']].set_active(True)
self.distance_measure_radios[data['distance_measure']].set_active(True)
self.set_groups_data(data['groups'])
self.set_variables_data(data['variables'])
self.update_interface()
if len(self.group_liststore):
self.min_group_combo.set_active(data['min_group'])
if pysvn_available:
if data.has_key('network_sync'):
# previous versions of data files may not have this field
self.network_sync_dict = data['network_sync']
self.network_sync_chk.handler_block(self.network_sync_chk_event_id)
self.network_sync_chk.set_active(self.network_sync_dict['sync'])
self.network_sync_chk.handler_unblock(self.network_sync_chk_event_id)
if self.network_sync_dict['url']:
self.window.set_title(self._('main_window_title_url').format(self.network_sync_dict['url'], data['trial_title']))
else:
self.window.set_title(self._('main_window_title').format(data['trial_title']))
def waiting_function(self, func, args):
gdk_cursor = gtk.gdk.Cursor(gtk.gdk.WATCH)
win = gtk.gdk.get_default_root_window()
win.set_cursor(gdk_cursor)
gobject.idle_add(func, *args)
gobject.idle_add(self.exit_waiting, win)
self.network_sync_dialog.show()
def exit_waiting(self, win):
gdk_cursor = gtk.gdk.Cursor(gtk.gdk.ARROW)
win.set_cursor(gdk_cursor)
self.network_sync_dialog.hide()
def load_trial(self, file_name):
# checking the file if this is a network sync info file. If yes, then we checkout and
# load the trial from the checkout
self.network_sync_dialog_label.set_text(self._('please_wait').format(self.network_sync_dict['url']))
ret = self.try_network_info_file(file_name)
self.file_chooser_current_folder = os.path.dirname(file_name)
if ret > 0:
self.network_sync_dialog_label.set_text('network_syncing_wait'.format(self.network_sync_dict['url']))
self.config.set('project', 'recent_trial', file_name)
self.notebook.set_current_page(3)
with open(self.config_file, 'wb') as config_file:
self.config.write(config_file)
config_file.flush()
config_file.close()
self.config.read(self.config_file)
return
if ret == 0: return
try:
self.load_trial_from_file(file_name)
self.lock_trial()
self.trial_file_name = file_name
self.notebook.set_current_page(3)
except Exception as ex:
functions.error_dialog(self.window, self._("trial_load_failed").format(file_name), self._("error_loading_file"))
self.lock_trial(unlock=True)
self.set_new_trial()
self.trial_file_name = False
def get_svn_client(self):
self.network_sync_cancel_command = False
client = pysvn.Client()
client.callback_cancel = self.network_sync_cancel
client.callback_get_login = self.network_sync_get_login
client.callback_ssl_server_trust_prompt = self.network_sync_ssl_server_trust_prompt
client.callback_notify = self.network_sync_notify
client.set_auth_cache(self.config.getboolean('operations', 'cach_cred'))
client.set_store_passwords(self.config.getboolean('operations', 'cach_cred'))
client.exception_style = 1
return client
def network_sync_notify(self, event_dict):
return
def save_trial_to_file(self, file_name):
data = {}
data['ui_pool'] = self.ui_pool
data['trial_title'] = self.trial_title_entry.get_text()
data['sample_size'] = self.trial_sample_size_spin.get_value_as_int()
data['trial_description'] = functions.get_text_buffer(self.trial_description_text)
data['trial_properties'] = self.get_trial_properties()
data['high_prob'] = self.high_prob_spin.get_value()
data['min_group'] = self.min_group_combo.get_active()
data['initial_freq_table'] = self.initial_freq_table
data['prob_method'] = self.get_prob_method()
data['distance_measure'] = self.get_distance_measure()
data['allocations'] = self.allocations
data['groups'] = self.get_groups_data()
data['variables'] = self.get_variables_data()
data['network_sync'] = self.network_sync_dict
fp = open(file_name, 'wb')
pickle.dump(data, fp)
fp.flush()
fp.close()
if self.network_sync_dict['sync']:
if self.config.getboolean('operations', 'backup_network'):
backup_folder_name = self.config.get('operations', 'backup_network_path')
if backup_folder_name:
back_file_name = os.path.join(backup_folder_name, os.path.basename(file_name))
# turning sync off to enable offline opening of the backup file
data['network_sync'] = dict(sync=False, url='', auth=False)
fp = open(back_file_name, 'wb')
pickle.dump(data, fp)
fp.flush()
fp.close()
def save_trial_local(self, file_name):
self.save_trial_to_file(file_name)
self.window.set_title(self._('main_window_title').format(file_name.split(os.sep)[-1]))
self.config.set('project', 'recent_trial', file_name)
with open(self.config_file, 'wb') as config_file:
self.config.write(config_file)
config_file.flush()
config_file.close()
self.config.read(self.config_file)
return file_name
def load_network_trial_info(self):
fp = open(self.trial_file_name, 'rb')
data = pickle.load(fp)
fp.close()
try:
if data.has_key('network_sync'):
self.network_sync_dict = data['network_sync']
else:
raise Exception, self._("trial_info_file_not_valid")
if data.has_key('trial_name'):
trial_name = data['trial_name']
else:
raise Exception, self._("trial_info_file_not_valid")
return trial_name
except Exception as ex:
functions.error_dialog(self.window, self._("network_trial_info_file_problem") + repr(ex), self._("trial_info_file"))
return False
def update_network_trial(self):
# this method checkout the repo, load the trial from it, and then return the local path
if not self.trial_file_name:
self.set_new_trial()
return False
trial_name = self.load_network_trial_info()
if not trial_name:
self.set_new_trial()
return False
try:
client = self.get_svn_client()
url = self.network_sync_dict['url'] + '/' + trial_name
tempfolder = tempfile.mkdtemp()
rev = False
while True:
rev = client.checkout(url, tempfolder)
if rev:
if type(rev) == type(pysvn.Revision(pysvn.opt_revision_kind.head)): break
temp_file_name = os.path.join(tempfolder, trial_name)
self.load_trial_from_file(temp_file_name)
return tempfolder
except Exception as ex:
functions.error_dialog(self.window, self._("unknown_error_network_sync") + repr(ex), self._("network_sync_error"))
return False
def checkin_trial(self, path):
if not self.trial_file_name:
self.set_new_trial()
return False
trial_name = self.load_network_trial_info()
if not trial_name:
self.set_new_trial()
return False
url = self.network_sync_dict['url'] + '/' + trial_name
file_name = os.path.join(path, trial_name)
self.save_trial_to_file(file_name)
client = self.get_svn_client()
try:
rev = False
while True:
rev = client.checkin(path, time.ctime())
if rev:
if type(rev) == type(pysvn.Revision(pysvn.opt_revision_kind.head)): break
stats = client.status(path)
for stat in stats:
if stat.repos_text_status == pysvn.wc_status_kind.modified:
break
else:
break
self.config.set('project', 'recent_trial', self.trial_file_name)
with open(self.config_file, 'wb') as config_file:
self.config.write(config_file)
config_file.flush()
config_file.close()
self.remove_folder(path)
except pysvn.ClientError, e:
for message, code in e.args[1]:
if code == 160024 or 'Conflict' in message:
msg = self._("network_sync_conflict")
dialog = gtk.MessageDialog(self.window, flags = gtk.DIALOG_MODAL, type = gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format = msg)
dialog.set_title(self._("trial_conflict"))
if dialog.run() == gtk.RESPONSE_YES:
dialog.destroy()
self.update_network_trial()
dialog.destroy()
break
else:
functions.error_dialog(self.window, self._("unknown_error_network_sync") + str(e.args[0]), self._("network_sync_error"))
if os.path.exists(path):
self.remove_folder(path)
return False
except Exception as ex:
functions.error_dialog(self.window, self._("unknown_error_network_sync") + repr(ex), self._("network_sync_error"))
if os.path.exists(path):
self.remove_folder(path)
return False
def import_trial(self, file_name):
trial_name = '_'.join(self.trial_title_entry.get_text().split())[:10] + str.partition(str(time.time()), '.')[0]
temp_dir = tempfile.mkdtemp(prefix=trial_name)
temp_file = os.path.join(temp_dir, trial_name)
self.save_trial_to_file(temp_file)
try:
client = self.get_svn_client()
url = self.network_sync_dict['url'] + '/' + trial_name
rev = False
while True:
rev = client.import_(temp_dir, url, self._('minimization_initialized'))
if rev:
if type(rev) == type(pysvn.Revision(pysvn.opt_revision_kind.head)): break
data = {}
data['network_sync'] = self.network_sync_dict
data['trial_name'] = trial_name
fp = open(file_name, 'wb')
pickle.dump(data, fp)
fp.flush()
fp.close()
self.config.set('project', 'recent_trial', file_name)
with open(self.config_file, 'wb') as config_file:
self.config.write(config_file)
config_file.flush()
config_file.close()
self.remove_folder(temp_dir)
self.lock_trial()
return file_name
except Exception as ex:
functions.error_dialog(self.window, self._("unknown_error_network_sync") + repr(ex), self._("network_sync_error"))
if os.path.exists(temp_dir):
self.remove_folder(temp_dir)
return False
def remove_folder(self, folder):
try:
shutil.rmtree(folder)
except:
pass
def save_trial(self, file_name, initial=False):
if self.network_sync_dict['sync']:
if initial:
# here file_name is the file containing trial info: rep url etc
self.trial_file_name = self.import_trial(file_name)
else:
# here file name is the path. A temp folder for checkin into the repo.
self.checkin_trial(file_name)
self.network_sync_icon.set_from_stock(gtk.STOCK_CONNECT, gtk.ICON_SIZE_SMALL_TOOLBAR)
self.network_sync_icon.set_tooltip_text(self._('network_sync_enabled'))
else:
self.trial_file_name = self.save_trial_local(file_name)
self.network_sync_icon.set_from_stock(gtk.STOCK_DISCONNECT, gtk.ICON_SIZE_SMALL_TOOLBAR)
self.network_sync_icon.set_tooltip_text(self._('network_sync_disabled'))
if self.trial_file_name: self.lock_trial()
return file_name
def network_sync_cancel(self):
return self.network_sync_cancel_command
def get_distance_measure_name(self):
for distance_measure_radio in self.distance_measure_radios:
if distance_measure_radio.get_active():
return distance_measure_radio.get_label()
return self._("unknown")
def get_distance_measure(self):
for idx, distance_measure_radio in enumerate(self.distance_measure_radios):
if distance_measure_radio.get_active():
return idx
return 0
def get_prob_method_name(self):
for prob_method_radio in self.prob_method_radios:
if prob_method_radio.get_active():
return prob_method_radio.get_label()
return self._("unknown")
def get_prob_method(self):
for idx, prob_method_radio in enumerate(self.prob_method_radios):
if prob_method_radio.get_active():
return idx
return 0
def get_variables_info(self):
variables = []
n = 0
for row in self.variable_liststore:
n += 1
variable = self._("weight_levels").format(n, *row)
variables.append(variable)
return '\n'.join(variables)
def get_variables_data(self):
variables = []
for row in self.variable_liststore:
variable = {}
variable['name'] = row[0]
variable['weight'] = row[1]
variable['levels'] = row[2]
variables.append(variable)
return variables
def get_groups_info(self):
groups = []
n = 0
for row in self.group_liststore:
n += 1
group = self._("allocation_ratio_format").format(n, *list(row))
groups.append(group)
return '\n'.join(groups)
def get_groups_data(self):
groups = []
for row in self.group_liststore:
group = {}
group['name'] = row[0]
group['allocation_ratio'] = row[1]
groups.append(group)
return groups
def select_file(self, title, action):
"""
A generic method returning file name
"""
stock = {
gtk.FILE_CHOOSER_ACTION_OPEN: gtk.STOCK_OPEN,
gtk.FILE_CHOOSER_ACTION_SAVE: gtk.STOCK_SAVE}
buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, stock[action], gtk.RESPONSE_OK)
fdialog = gtk.FileChooserDialog(title, self.window, action, buttons)
if action == gtk.FILE_CHOOSER_ACTION_SAVE:
fdialog.set_do_overwrite_confirmation(True)
fdialog.set_default_response(gtk.RESPONSE_OK)
fdialog.set_current_folder(self.file_chooser_current_folder)
response = fdialog.run()
if response == gtk.RESPONSE_OK:
file_name = fdialog.get_filename()
self.file_chooser_current_folder = os.path.dirname(file_name)
else:
file_name = None
fdialog.destroy()
return file_name
def main():
gtk.main()
return 0
if __name__ == "__main__":
m = ModelInteface()
ret = main()
while m.restart:
m = ModelInteface()
ret = main()