843
744
if response_id == gtk.RESPONSE_OK:
844
745
self.configure_event(self.event, {})
849
if brick.get_type() == "Qemu":
850
for dev in "hda", "hdb", "hdc", "hdd", "fda", "fdb", "mtdblock":
851
yield brick.config[dev]
854
class CommitImageDialog(Window):
856
resource = "data/commitdialog.ui"
860
def __init__(self, progessbar, factory):
861
Window.__init__(self)
862
self.progessbar = progessbar
863
model = self.get_object("model1")
864
for brick in factory.bricks:
865
for disk in (disk for disk in disks_of(brick) if disk.cow):
866
model.append((disk.device + " on " + brick.name, disk))
868
def show(self, parent=None):
870
Window.show(self, parent)
872
def _do_image_commit(self, path):
874
def log_err((out, err, exit_status)):
876
logger.error(commit_failed, err=err)
878
d = utils.getProcessOutputAndValue("qemu-img", ["commit", path],
880
d.addCallback(log_err)
883
def do_image_commit(self, path):
884
self.window.destroy()
885
self.progessbar.wait_for(self._do_image_commit, path)
887
def commit_file(self, pathname):
888
question = ("Warning: the base image will be updated to the\n"
889
"changes contained in the COW. This operation\n"
890
"cannot be undone. Are you sure?")
891
ConfirmDialog(question, on_yes=self.do_image_commit,
892
on_yes_arg=pathname).show(self.parent)
894
def _commit_vm(self, img):
895
logger.warning(not_implemented)
896
# img.VM.commit_disks()
897
self.window.destroy()
900
combobox = self.get_object("disk_combo")
901
model = combobox.get_model()
902
itr = combobox.get_active_iter()
905
if not self.get_object("cow_checkbutton").get_active():
906
question = ("Warning: the private COW image will be "
907
"updated.\nThis operation cannot be undone.\n"
909
ConfirmDialog(question, on_yes=self._commit_vm,
910
on_yes_arg=img).show(self.parent)
912
pathname = os.path.join(img.basefolder,
913
"{0.vm_name}_{0.device}.cow".format(img))
914
self.commit_file(pathname)
916
logger.error(img_invalid)
918
def on_CommitImageDialog_response(self, dialog, response_id):
919
if response_id == gtk.RESPONSE_OK:
920
if self.get_object("file_radiobutton").get_active():
921
pathname = self.get_object(
922
"cowpath_filechooser").get_filename()
923
self.commit_file(pathname)
929
def on_file_radiobutton_toggled(self, button):
930
active = button.get_active()
931
filechooser = self.get_object("cowpath_filechooser")
932
filechooser.set_visible(active)
933
filechooser.unselect_all()
934
combo = self.get_object("disk_combo")
935
combo.set_visible(not active)
937
self.get_object("cow_checkbutton").set_visible(not active)
938
self.get_object("msg_label").set_visible(False)
940
def _commit_image_show_result(self, (out, err, code)):
942
logger.error(base_not_found, err=err)
944
label = self.get_object("msg_label")
945
for line in out.splitlines():
946
if line.startswith("backing file: "):
950
label.set_text(_("Base not found (invalid cow?)"))
951
label.set_visible(True)
953
def on_cowpath_filechooser_file_set(self, filechooser):
954
if self._set_label_d is not None:
955
self._set_label_d.cancel()
956
filename = filechooser.get_filename()
957
if os.access(filename, os.R_OK):
958
code = utils.getProcessOutputAndValue("qemu-img",
959
["info", filename], os.environ)
960
code.addCallback(self._commit_image_show_result)
961
self._set_label_d = code
964
def set_label(self, combobox=None, button=None):
965
if self._set_label_d is not None:
966
self._set_label_d.cancel()
968
combobox = self.get_object("disk_combo")
970
button = self.get_object("cow_checkbutton")
971
label = self.get_object("msg_label")
972
label.set_visible(False)
973
model = combobox.get_model()
974
itr = combobox.get_active_iter()
977
base = disk.image and disk.image.path or None
978
if base and button.get_active():
979
# XXX: make disk.get_real_disk_name's deferred cancellable
980
deferred = disk.get_real_disk_name()
981
deferred.addCallback(label.set_text)
982
deferred.addCallback(lambda _: label.set_visible(True))
983
deferred.addErrback(logger.failure_eb, img_combo)
984
self._set_label_d = deferred
986
label.set_visible(True)
989
label.set_visible(True)
990
label.set_text("base not found")
992
label.set_visible(True)
993
label.set_text("base not found")
995
def on_disk_combo_changed(self, combobox):
996
self.set_label(combobox=combobox)
998
def on_cow_checkbutton_toggled(self, button):
999
self.set_label(button=button)
1002
def choose_new_image(gui, factory):
1003
main = gui.get_object("main_win")
1004
dialog = gtk.FileChooserDialog(_("Open a disk image"), main,
1005
gtk.FILE_CHOOSER_ACTION_OPEN,
1006
(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
1007
gtk.STOCK_OPEN, gtk.RESPONSE_OK))
1008
if dialog.run() == gtk.RESPONSE_OK:
1009
pathname = dialog.get_filename()
1010
LoadImageDialog(factory, pathname).show(main)
1014
class LoadImageDialog(Window):
1016
resource = "data/loadimagedialog.ui"
1018
def __init__(self, factory, pathname):
1019
Window.__init__(self)
1020
self.pathname = pathname
1021
self.factory = factory
1023
def show(self, parent=None):
1024
name = os.path.basename(self.pathname)
1025
self.get_object("name_entry").set_text(name)
1026
buf = self.get_object("description_textview").get_buffer()
1027
buf.set_text(self.load_desc())
1028
Window.show(self, parent)
1030
def load_desc(self):
1032
with open(self.pathname + ".vbdescr") as fd:
1037
def on_LoadImageDialog_response(self, dialog, response_id):
1038
if response_id == gtk.RESPONSE_OK:
1039
name = self.get_object("name_entry").get_text()
1040
buf = self.get_object("description_textview").get_buffer()
1041
desc = buf.get_text(buf.get_start_iter(), buf.get_end_iter())
1043
self.factory.new_disk_image(name, self.pathname, desc)
1050
class CreateImageDialog(Window):
1052
resource = "data/createimagedialog.ui"
1054
def __init__(self, gui, factory):
1056
self.factory = factory
1057
Window.__init__(self)
1059
def create_image(self, name, pathname, fmt, size, unit):
1061
def _create_disk(result):
1062
out, err, code = result
1066
return self.factory.new_disk_image(name, pathname)
1068
exit = utils.getProcessOutputAndValue("qemu-img",
1069
["create", "-f", fmt, pathname, size + unit], os.environ)
1070
exit.addCallback(_create_disk)
1071
exit.addErrback(logger.failure_eb, img_create_err)
1074
def on_CreateImageDialog_response(self, dialog, response_id):
1075
if response_id == gtk.RESPONSE_OK:
1076
logger.info(img_create)
1077
name = self.get_object("name_entry").get_text()
1079
logger.error(img_choose)
1081
folder = self.get_object("folder_filechooserbutton").get_filename()
1082
fmt_cmb = self.get_object("format_combobox")
1083
itr = fmt_cmb.get_active_iter()
1085
fmt = fmt_cmb.get_model()[itr][0]
1089
logger.info(img_invalid_type)
1091
size = str(self.get_object("size_spinbutton").get_value_as_int())
1092
# Get size unit and remove the last character "B"
1093
# because qemu-img want k, M, G or T suffixes.
1094
unit_cmb = self.get_object("unit_combobox")
1095
itr = unit_cmb.get_active_iter()
1097
unit = unit_cmb.get_model()[itr][0][0]
1099
logger.info(img_invalid_unit)
1101
pathname = os.path.join(folder, name, os.path.extsep, fmt)
1102
self.gui.user_wait_action(self.create_image(name, pathname, fmt,
1107
class NewProjectDialog(Window):
1109
resource = "data/newproject.ui"
1111
def __init__(self, factory):
1112
self.factory = factory
1113
Window.__init__(self)
1115
def on_NewProjectDialog_response(self, dialog, response_id):
1117
if response_id == gtk.RESPONSE_OK:
1118
name = self.get_object("name_entry").get_text()
1119
project.manager.create(name, self.factory)
1124
class OpenProjectDialog(Window):
1126
resource = "data/openproject.ui"
1128
def __init__(self, gui):
1130
Window.__init__(self)
1132
def show(self, parent=None):
1133
model = self.get_object("liststore1")
1134
for prj in project.manager:
1135
model.append((prj, ))
1136
Window.show(self, parent)
1138
def on_treeview1_row_activated(self, treeview, path, column):
1139
model = treeview.get_model()
1140
name = model[path][0]
1141
self.on_OpenProjectDialog_response(self.get_object(
1142
"OpenProjectDialog"), gtk.RESPONSE_OK, name)
1144
def on_OpenProjectDialog_response(self, dialog, response_id, name=""):
1145
if response_id == gtk.RESPONSE_OK:
1147
treeview = self.get_object("treeview1")
1148
model, itr = treeview.get_selection().get_selected()
1150
name = model.get_value(itr, 0)
1154
self.gui.on_open(name)
1161
return brick.get_type() == "Qemu"
1165
return disk.image and disk.cow
1168
def cowname(brick, disk):
1169
return os.path.join(project.current.path,
1170
"{0.name}_{1.device}.cow".format(brick, disk))
1173
def gather_selected(model, parent, workspace, lst):
1174
itr = model.iter_children(parent)
1176
fp = model[itr][FILEPATH]
1177
if model[itr][SELECTED] and fp.isfile():
1178
lst.append(os.path.join(*fp.segmentsFrom(workspace)))
1180
gather_selected(model, itr, workspace, lst)
1181
itr = model.iter_next(itr)
1184
class ImportCanceled(Exception):
1188
SELECTED, ACTIVABLE, TYPE, NAME, FILEPATH = range(5)
1191
class ExportProjectDialog(Window):
1193
resource = "data/exportproject.ui"
1194
include_images = False
1196
def __init__(self, progressbar, prjpath, disk_images):
1197
super(Window, self).__init__()
1198
self.progressbar = progressbar
1199
self.prjpath = prjpath
1200
self.image_files = [(image.name, filepath.FilePath(image.path))
1201
for image in disk_images]
1202
# self.image_files = set(filepath.FilePath(image.path) for image in
1204
self.required_files = set([prjpath.child(".project"),
1205
prjpath.child("README")])
1206
self.internal_files = set([prjpath.child("vde.dot"),
1207
prjpath.child("vde_topology.plain"),
1208
prjpath.child(".images")])
1210
def append_dirs(self, dirpath, dirnames, model, parent, nodes):
1211
for dirname in sorted(dirnames):
1212
child = dirpath.child(dirname)
1213
if child in self.required_files | self.internal_files:
1214
dirnames.remove(dirname)
1216
row = (True, True, gtk.STOCK_DIRECTORY, dirname, child)
1217
nodes[child.path] = model.append(parent, row)
1219
def append_files(self, dirpath, filenames, model, parent):
1220
for filename in sorted(filenames):
1221
child = dirpath.child(filename)
1222
if (child not in self.required_files | self.internal_files and
1223
child.isfile() and not child.islink()):
1224
row = (True, True, gtk.STOCK_FILE, filename, child)
1225
model.append(parent, row)
1227
def build_path_tree(self, model, prjpath):
1228
row = (True, True, gtk.STOCK_DIRECTORY, prjpath.basename(), prjpath)
1229
root = model.append(None, row)
1230
nodes = {prjpath.path: root}
1231
for dirpath, dirnames, filenames in os.walk(prjpath.path):
1232
parent = nodes[dirpath]
1233
dp = filepath.FilePath(dirpath)
1234
self.append_dirs(dp, dirnames, model, parent, nodes)
1235
self.append_files(dp, filenames, model, parent)
1237
def show(self, parent_w=None):
1238
model = self.get_object("treestore1")
1239
self.build_path_tree(model, self.prjpath)
1240
pixbuf_cr = self.get_object("icon_cellrenderer")
1241
pixbuf_cr.set_property("stock-size", gtk.ICON_SIZE_MENU)
1242
size_c = self.get_object("treeviewcolumn2")
1243
size_cr = self.get_object("size_cellrenderer")
1244
size_c.set_cell_data_func(size_cr, self._set_size)
1245
self.get_object("selected_cellrenderer").connect(
1246
"toggled", self.on_selected_cellrenderer_toggled, model)
1247
self.get_object("treeview1").expand_row(0, False)
1248
Window.show(self, parent_w)
1250
def _set_size(self, column, cellrenderer, model, itr):
1251
fp = model.get_value(itr, FILEPATH)
1253
cellrenderer.set_property("text", tools.fmtsize(fp.getsize()))
1255
size = self._calc_size(model, itr)
1256
if model.get_path(itr) == (0,):
1257
size += sum(fp.getsize() for fp in self.required_files if
1259
if self.include_images:
1260
size += sum(fp.getsize() for n, fp in self.image_files)
1261
cellrenderer.set_property("text", tools.fmtsize(size))
1263
def _calc_size(self, model, parent):
1265
fp = model[parent][FILEPATH]
1267
itr = model.iter_children(parent)
1269
size += self._calc_size(model, itr)
1270
itr = model.iter_next(itr)
1271
elif model[parent][SELECTED]:
1272
size += fp.getsize()
1275
def _normalize_filename(self, filename):
1276
if filename[-4:] != ".vbp":
1277
return filename + ".vbp"
1280
def on_selected_cellrenderer_toggled(self, cellrenderer, path, model):
1281
itr = model.get_iter(path)
1282
model[itr][SELECTED] = not model[itr][SELECTED]
1283
self._select_children(model, itr, model[itr][SELECTED])
1284
parent = model.iter_parent(itr)
1286
child = model.iter_children(parent)
1288
if not model[child][SELECTED]:
1289
model[parent][SELECTED] = False
1291
child = model.iter_next(child)
1293
model[parent][SELECTED] = True
1294
parent = model.iter_parent(parent)
1296
def _select_children(self, model, parent, selected):
1297
itr = model.iter_children(parent)
1299
self._select_children(model, itr, selected)
1300
model[itr][SELECTED] = selected
1301
itr = model.iter_next(itr)
1303
def on_filechooser_response(self, dialog, response_id):
1304
if response_id == gtk.RESPONSE_OK:
1305
filename = dialog.get_filename()
1306
if filename is None:
1307
self.get_object("export_button").set_sensitive(False)
1308
elif os.path.exists(filename) and not os.path.isfile(filename):
1309
dialog.unselect_all()
1310
self.get_object("export_button").set_sensitive(False)
1312
filename = self._normalize_filename(filename)
1313
txt = filename.decode(sys.getfilesystemencoding()).encode(
1315
self.get_object("filename_entry").set_text(txt)
1316
self.get_object("export_button").set_sensitive(True)
1319
def on_open_button_clicked(self, button):
1320
chooser = gtk.FileChooserDialog(title=_("Export project"),
1321
action=gtk.FILE_CHOOSER_ACTION_SAVE,
1322
buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
1323
gtk.STOCK_SAVE, gtk.RESPONSE_OK))
1324
vbp = gtk.FileFilter()
1325
vbp.add_pattern("*.vbp")
1326
chooser.set_do_overwrite_confirmation(True)
1327
chooser.set_filter(vbp)
1328
chooser.connect("response", self.on_filechooser_response)
1329
chooser.set_transient_for(self.window)
1332
def on_filename_entry_changed(self, entry):
1333
self.get_object("export_button").set_sensitive(bool(entry.get_text()))
1335
def on_include_images_checkbutton_toggled(self, checkbutton):
1336
self.include_images = checkbutton.get_active()
1337
model = self.get_object("treestore1")
1338
model.row_changed((0,), model.get_iter((0,)))
1340
def export(self, model, ancestor, filename):
1342
gather_selected(model, model.get_iter_first(), ancestor, files)
1343
for fp in self.required_files:
1345
files.append(os.path.join(*fp.segmentsFrom(ancestor)))
1347
if self.include_images:
1348
images = [(name, fp.path) for name, fp in self.image_files]
1349
return project.manager.export(filename, files, images)
1351
def on_ExportProjectDialog_response(self, dialog, response_id):
1352
if response_id == gtk.RESPONSE_OK:
1353
model = self.get_object("treestore1")
1354
ancestor = filepath.FilePath(settings.VIRTUALBRICKS_HOME)
1355
filename = self._normalize_filename(self.get_object(
1356
"filename_entry").get_text())
1357
self.progressbar.wait_for(self.export(model, ancestor, filename))
1361
def retrieve_data(widget, data):
1363
attr = widget.get_data(name)
1364
if attr is not None:
1365
lst.append((attr, widget))
1368
def accumulate_data(container, name):
1370
container.foreach(retrieve_data, (lst, name))
1374
def pass_through(function, *args, **kwds):
1376
function(*args, **kwds)
1381
def iter_model(model, *columns):
1382
itr = model.get_iter_root()
1384
columns = range(model.get_n_columns())
1386
yield model.get(itr, *columns)
1387
itr = model.iter_next(itr)
1390
def complain_on_error(result):
1391
out, err, code = result
1394
raise error.ProcessTerminated(code)
1399
def set_path(column, cell_renderer, model, iter, colid):
1400
path = model.get_value(iter, colid)
1401
cell_renderer.set_property("text", path.path if path else "")
1406
def __init__(self, freeze, unfreeze, parent):
1407
self.freeze = freeze
1408
self.unfreeze = unfreeze
1409
builder = gtk.Builder()
1410
res = graphics.get_filename("virtualbricks.gui", "data/userwait.ui")
1411
builder.add_from_file(res)
1412
self.progressbar = builder.get_object("progressbar")
1413
self.window = builder.get_object("UserWaitWindow")
1414
self.window.set_transient_for(parent)
1415
self.window.set_modal(True)
1417
def wait_for(self, something, *args):
1418
if isinstance(something, defer.Deferred):
1419
return self.wait_for_deferred(something)
1420
elif hasattr(something, "__call__"):
1421
return self.wait_for_action(something, *args)
1422
raise RuntimeError("Invalid argument")
1424
def wait_for_action(self, action, *args):
1425
done = defer.maybeDeferred(action, *args)
1426
return self.wait_for_deferred(done)
1428
def wait_for_deferred(self, deferred):
1429
deferred.addBoth(self.stop, self.start())
1434
self.window.show_all()
1435
lc = task.LoopingCall(self.progressbar.pulse)
1436
lc.start(0.2, False)
1439
def stop(self, passthru, lc):
1440
self.window.destroy()
1448
def __init__(self, dialog):
1449
self.freezer = Freezer(lambda: None, lambda: None, dialog)
1451
def wait_for(self, something, *args):
1452
return self.freezer.wait_for(something, *args)
1455
class _HumbleImport:
1457
def step_1(self, dialog, model, path, extract=project.manager.extract):
1458
archive_path = dialog.get_archive_path()
1459
if archive_path != dialog.archive_path:
1461
dialog.project.delete()
1462
dialog.archive_path = archive_path
1463
d = extract(filepath._secureEnoughString(), archive_path)
1464
d.addCallback(self.extract_cb, dialog)
1465
d.addCallback(self.fill_model_cb, dialog, model, path)
1466
d.addErrback(self.extract_eb, dialog)
1469
def extract_cb(self, project, dialog):
1470
logger.debug(project_extracted, path=project.path)
1471
dialog.project = project
1472
dialog.images = dict((name, section["path"]) for (_, name), section in
1473
project.get_descriptor().get_images())
1476
def extract_eb(self, fail, dialog):
1477
logger.failure(extract_err, fail)
1481
def fill_model_cb(self, project, dialog, model, vipath):
1483
for name in (fp.basename() for fp in project.imported_images()):
1484
if name in dialog.images:
1485
fp = vipath.child(os.path.basename(dialog.images[name]))
1487
fp = vipath.child(name)
1488
fp2 = filepath.FilePath(fp.path)
1491
fp2 = fp.siblingExtension(".{0}".format(c))
1493
model.append((name, fp2, True))
1496
def step_2(self, dialog, store1, store2):
1497
"""Step 2: map images."""
1499
imgs = dict((name, path) for name, path, save in
1500
iter_model(store1) if save)
1502
for name in dialog.images:
1503
store2.append((name, imgs.get(name)))
1504
if len(store2) == 0 or all(p for (p,) in iter_model(store2, 1)):
1505
dialog.set_page_complete()
1507
def step_3(self, dialog):
1508
w = dialog.get_object
1509
w("projectname_label").set_text(dialog.get_project_name())
1510
path_label = w("projectpath_label")
1511
path = dialog.project.filepath.sibling(dialog.get_project_name()).path
1512
path_label.set_text(path)
1513
path_label.set_tooltip_text(path)
1514
w("open_label").set_text(str(dialog.get_open()))
1515
w("overwrite_label").set_text(str(dialog.get_overwrite()))
1516
iimgs = (name for name, s in iter_model(w("liststore1"), 0, 2) if s)
1517
w("imported_label").set_text("\n".join(iimgs))
1518
store = w("liststore2")
1520
vbox.foreach(vbox.remove)
1521
for i, (name, dest) in enumerate(iter_model(store)):
1522
nlabel = gtk.Label(name + ":")
1523
nlabel.set_alignment(0.0, 0.5)
1524
dlabel = gtk.Label(dest.path)
1525
dlabel.set_tooltip_text(dest.path)
1526
dlabel.set_alignment(0.0, 0.5)
1527
dlabel.set_ellipsize(pango.ELLIPSIZE_MIDDLE)
1528
box = gtk.HBox(spacing=5)
1529
box.pack_start(nlabel, False, True, 0)
1530
box.pack_start(dlabel, True, True, 0)
1531
vbox.pack_start(box, False, True, 3)
1534
def apply(self, project, name, factory, overwrite, open, store1, store2):
1535
entry = project.get_descriptor()
1536
imgs = self.get_images(project, entry, store1, store2)
1537
deferred = self.rebase_all(project, imgs, entry)
1538
deferred.addCallback(self.check_rebase)
1539
deferred.addCallback(lambda a: project.rename(name, overwrite))
1541
deferred.addCallback(pass_through(project.restore, factory))
1542
deferred.addErrback(pass_through(project.delete))
1543
deferred.addErrback(logger.failure_eb, error_on_import_project)
1546
def get_images(self, project, entry, store1, store2):
1547
imagesfp = project.filepath.child(".images")
1548
imgs = self.save_images(store1, imagesfp)
1549
self.remap_images(entry, store2, imgs)
1550
with project.dot_project().open("w") as fp:
1554
def save_images(self, model, source):
1556
for name, destination, save in iter_model(model):
1558
fp = source.child(name)
1560
fp.moveTo(destination)
1561
except OSError as e:
1562
if e.errno == errno.ENOENT:
1563
logger.error(image_not_exists, source=fp.path,
1564
destination=destination.path)
1569
saved[name] = destination
1572
def remap_images(self, entry, store, saved):
1573
for name, destination in saved.iteritems():
1574
entry.remap_image(name, destination.path)
1575
for name, path in iter_model(store):
1576
entry.remap_image(name, path.path)
1579
def rebase_all(self, project, images, entry):
1581
for name, path in images.iteritems():
1582
for vmname, dev in entry.device_for_image(name):
1583
cow_name = "{0}_{1}.cow".format(vmname, dev)
1584
cow = project.filepath.child(cow_name)
1586
logger.debug(log_rebase, cow=cow.path, basefile=path.path)
1587
lst.append(self.rebase(path.path, cow.path))
1588
return defer.DeferredList(lst)
1590
def rebase(self, backing_file, cow, run=utils.getProcessOutputAndValue):
1591
args = ["rebase", "-u", "-b", backing_file, cow]
1592
d = run("qemu-img", args, os.environ)
1593
return d.addCallback(complain_on_error)
1595
def check_rebase(self, result):
1596
for success, status in result:
1598
logger.error(rebase_error, log_failure=status)
1601
class ImportDialog(Window):
1603
resource = "data/importdialog.ui"
1604
NAME, PATH, SELECTED = range(3)
1608
humble = _HumbleImport()
1610
def __init__(self, factory):
1611
Window.__init__(self)
1612
self.factory = factory
1615
def assistant(self):
1616
return self.builder.get_object("ImportDialog")
1618
def show(self, parent=None):
1619
col1 = self.get_object("pathcolumn1")
1620
cell1 = self.get_object("cellrenderertext2")
1621
col1.set_cell_data_func(cell1, set_path, 1)
1622
col2 = self.get_object("pathcolumn2")
1623
cell2 = self.get_object("cellrenderertext4")
1624
col2.set_cell_data_func(cell2, set_path, 1)
1625
view1 = self.get_object("treeview1")
1626
view1.connect("button_press_event", self.on_button_press_event, col1,
1627
self.get_save_filechooserdialog)
1628
view2 = self.get_object("treeview2")
1629
view2.connect("button_press_event", self.on_button_press_event, col2,
1630
self.get_map_filechooserdialog)
1631
Window.show(self, parent)
1634
self.assistant.destroy()
1636
# assistant method helpers
1638
def set_page_complete(self, page=None, complete=True):
1640
page = self.assistant.get_nth_page(
1641
self.assistant.get_current_page())
1642
self.assistant.set_page_complete(page, complete)
1646
def get_project_name(self):
1647
return self.get_object("prjname_entry").get_text()
1649
def set_project_name(self, name):
1650
self.get_object("prjname_entry").set_text(name)
1652
def get_archive_path(self):
1653
return self.get_object("filechooserbutton").get_filename()
1656
return self.get_object("opencheckbutton").get_active()
1658
def get_overwrite(self):
1659
return self.get_object("overwritecheckbutton").get_active()
1661
def get_filechooserdialog(self, model, path, title, action, stock_id):
1662
chooser = gtk.FileChooserDialog(title, self.window, action,
1663
(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
1664
stock_id, gtk.RESPONSE_OK))
1665
chooser.set_modal(True)
1666
chooser.set_select_multiple(False)
1667
chooser.set_transient_for(self.window)
1668
chooser.set_destroy_with_parent(True)
1669
chooser.set_position(gtk.WIN_POS_CENTER)
1670
chooser.set_do_overwrite_confirmation(True)
1671
chooser.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
1672
chooser.connect("response", self.on_filechooserdialog_response, model,
1676
def get_save_filechooserdialog(self, model, path):
1677
return self.get_filechooserdialog(model, path, _("Save image as..."),
1678
gtk.FILE_CHOOSER_ACTION_SAVE,
1681
def get_map_filechooserdialog(self, model, path):
1682
return self.get_filechooserdialog(model, path, _("Map image as..."),
1683
gtk.FILE_CHOOSER_ACTION_OPEN,
1688
def on_liststore2_row_changed(self, model, path, iter):
1689
self.assistant.set_page_complete(self.assistant.get_nth_page(3),
1690
all(path for name, path in iter_model(model)))
1692
def on_ImportDialog_prepare(self, assistant, page):
1693
page_num = assistant.get_current_page()
1697
ws = settings.get("workspace")
1698
deferred = self.humble.step_1(self, self.get_object("liststore1"),
1699
filepath.FilePath(ws).child("vimages"))
1701
ProgressBar(self.assistant).wait_for(deferred)
1703
self.humble.step_2(self, self.get_object("liststore1"),
1704
self.get_object("liststore2"))
1706
self.humble.step_3(self)
1708
logger.error(invalid_step_assitant, num=page_num)
1711
def on_ImportDialog_cancel(self, assistant):
1713
logger.info(removing_temporary_project, path=self.project.path)
1714
self.project.delete()
1718
def on_ImportDialog_apply(self, assistant):
1719
deferred = self.humble.apply(self.project, self.get_project_name(),
1720
self.factory, self.get_overwrite(),
1722
self.get_object("liststore1"),
1723
self.get_object("liststore2"))
1724
ProgressBar(self.assistant).wait_for(deferred)
1725
deferred.addBoth(pass_through(assistant.destroy))
1728
def on_filechooserbutton_file_set(self, filechooser):
1729
filename = filechooser.get_filename()
1730
name = os.path.splitext(os.path.basename(filename))[0]
1731
if not self.get_project_name():
1732
self.set_project_name(name)
1735
def on_prjname_entry_changed(self, entry):
1736
self.set_import_sensitive(self.get_archive_path(), entry.get_text(),
1737
self.get_object("overwritecheckbutton"))
1740
def on_overwritecheckbutton_toggled(self, checkbutton):
1741
self.set_import_sensitive(self.get_archive_path(),
1742
self.get_object("prjname_entry").get_text(),
1746
def set_import_sensitive(self, filename, name, overwrite_btn):
1747
page = self.get_object("intro_page")
1748
label = self.get_object("warn_label")
1749
if name in set(project.manager):
1750
overwrite_btn.set_visible(True)
1751
overwrite = overwrite_btn.get_active()
1752
label.set_visible(not overwrite)
1753
self.set_page_complete(page, overwrite)
1755
overwrite_btn.set_active(False)
1756
overwrite_btn.set_visible(False)
1757
label.set_visible(False)
1758
if filename and name:
1759
self.set_page_complete(page, True)
1761
self.set_page_complete(page, False)
1763
def on_cellrenderertoggle1_toggled(self, renderer, path):
1764
model = self.get_object("liststore1")
1765
active = renderer.get_active()
1766
model.set(model.get_iter(path), self.SELECTED, not active)
1769
def on_button_press_event(self, treeview, event, column, dialog_factory):
1770
if event.button == 1:
1773
pthinfo = treeview.get_path_at_pos(x, y)
1774
if pthinfo is not None and pthinfo[1] is column:
1775
path, col = pthinfo[:2]
1776
treeview.grab_focus()
1777
treeview.set_cursor(path, col, 0)
1778
model = treeview.get_model()
1779
chooser = dialog_factory(model, path)
1780
itr = model.get_iter(path)
1781
filename = model.get_value(itr, self.PATH)
1782
if filename is not None:
1783
if not chooser.set_filename(filename.path):
1784
chooser.set_current_name(filename.basename())
1788
def on_filechooserdialog_response(self, dialog, response_id, model, path):
1789
if response_id == gtk.RESPONSE_OK:
1790
filename = dialog.get_filename()
1791
if filename is not None:
1792
model.set_value(model.get_iter(path), self.PATH,
1793
filepath.FilePath(filename))
1798
class SaveAsDialog(Window):
1800
resource = "data/saveas.ui"
1801
home = filepath.FilePath(settings.DEFAULT_HOME)
1803
def __init__(self, factory, projects):
1804
Window.__init__(self)
1805
self.factory = factory
1806
self.model = model = self.get_object("liststore1")
1807
for prj in projects:
1808
model.append((prj, ))
1810
def get_project_name(self):
1811
return self.get_object("name_entry").get_text()
1813
def set_invalid(self, invalid):
1814
self.get_object("ok_button").set_sensitive(not invalid)
1816
def on_name_entry_changed(self, entry):
1817
name = entry.get_text()
1819
self.home.child(name)
1820
except filepath.InsecurePath:
1821
self.set_invalid(True)
1824
itr = model.get_iter_root()
1826
if model.get_value(itr, 0) == name:
1827
self.set_invalid(True)
1829
itr = model.iter_next(itr)
1831
self.set_invalid(False)
1834
def on_response(self, dialog, response_id):
1835
if response_id == gtk.RESPONSE_OK:
1836
project.current.save_as(self.get_project_name(), self.factory)