Work on native gui. Display records and add missing tasks and measurements.

This commit is contained in:
2026-09-30 16:18:44 +02:00
parent c3109b9d2a
commit 131af7d9e7
45 changed files with 6043 additions and 1966 deletions
+167 -8
View File
@@ -7,23 +7,35 @@ Notebook mit Vessel, User, Lists, Settings
"""
import os
import pyudev
from gi.repository import GLib, Gtk, Gdk, Rsvg
from datetime import datetime
import subprocess
import locale
from .view import View
from yms import gtkutils, combobox, treeview
from yms.lookup import Dropdown
from yms.model import user
class BaseView(View):
def __init__(self, context):
super().__init__(context, _("Base Data"), "base.ui")
#self.title = _("Base Data")
#builder = Gtk.Builder()
#builder.set_translation_domain(context.textdomain)
#builder.add_from_file(os.path.join(context.ui_path, "base.ui"))
#builder.connect_signals(self)
#self.topwidget = builder.get_object("topobject")
#gtkutils.init_named_controls(self, builder)
self.context = context
self.user = user.User(context.db) # current user record
self.newuser = False
self.backupdevice = None # USB-Stick detected only on demand
# Settings
self.sys_currency = context.db.load_setting(4)[0] or '€'
self.entry['sys_currency'].set_text(self.sys_currency)
self.sys_max_width = context.db.load_setting(20)[1] or 1024
self.spin['sys_max_width'].set_value(self.sys_max_width)
self.sys_max_height = context.db.load_setting(21)[1] or 768
self.spin['sys_max_height'].set_value(self.sys_max_height)
# combos
roles = {'captain': 'Captain', 'helmsman': 'Helmsman', 'sailor': 'Sailor'}
@@ -31,6 +43,14 @@ class BaseView(View):
langs = {'de': 'Deutsch', 'en': 'English'}
combobox.load_from_dict(self.combo['user_lang'], langs)
today = datetime.now()
datedict = {
key: f"{prefix} - {today.strftime(fmt)}"
for key, (fmt, prefix) in context.datefmt_map.items()
}
self.datefmt = context.db.load_setting(2)[0] or 'Y-m-d'
combobox.load_from_dict(self.combo['datefmt'], datedict, self.datefmt)
# shipyard
self.db.cur.execute("SELECT compid, compname FROM company WHERE comptype=3 ORDER BY compname")
shipyards = dict(self.db.cur.fetchall())
@@ -129,6 +149,132 @@ class BaseView(View):
storages = dict(self.db.cur.fetchall())
combobox.refresh_dict(self.combo['storage'], {-1: _("─── none ───")} | storages)
def find_usb_sticks(self):
result = []
for name in os.listdir("/sys/block"):
device = "/sys/block/" + name
removable = device + "/removable"
if not os.path.exists(removable):
continue
with open(removable) as f:
if f.read().strip() != "1":
continue
device_path = os.path.realpath(device + "/device")
if "/usb" in device_path.lower():
result.append(name)
return result
def is_mounted(self, device):
with open("/proc/mounts") as f:
for line in f:
mounted_device = line.split()[0]
if mounted_device == device:
return True
return False
def on_but_usbdevice_clicked(self, widget):
self.backupdevice = None
devlist = self.find_usb_sticks()
if len(devlist) == 0:
self.label['usb_device'].set_text('n/a')
return
if len(devlist) != 1:
print(devlist)
print("Multiple devices not supported yet")
self.label['usb_device'].set_text('multiple')
return
usbdev = devlist[0]
self.label['usb_device'].set_text(f"/dev/{usbdev}")
"""
serial number via python3-pyudev:
import pyudev
Settings
7 - usb backup device serial
8 - usb backup partition uuid
9 - last backup timestamp
"""
# first get stick hardware data
udevctx = pyudev.Context()
device = pyudev.Devices.from_sys_path(udevctx, os.path.join("/sys/class/block", usbdev))
serial = device.get("ID_SERIAL_SHORT")
vendor = device.get("ID_VENDOR")
model = device.get("ID_MODEL")
self.label['usb_serial'].set_text(serial or 'n/a')
self.label['usb_vendor'].set_text(vendor or 'n/a')
self.label['usb_model'].set_text(model or 'n/a')
# TODO second get partition, filesystem type and label
# there must be only one ext4 partition on disk
partitions = [
child for child in device.children
if child.device_type == "partition"
]
partition = partitions[0]
print(f"Partition={partition}")
if len(partitions) != 1:
print("error: more than one partition!")
return
partuuid = partition.properties.get("ID_PART_ENTRY_UUID")
fstype = partition.get("ID_FS_TYPE")
plabel = partition.get("ID_FS_LABEL")
self.label['usb_partition'].set_text(plabel)
self.label['usb_uuid'].set_text(partuuid)
self.label['usb_fstype'].set_text(fstype)
if fstype != "ext4":
print(f"error: invalid fileystem type {fstype}, ext4 expected")
return
self.backupdevice = f"/dev/{usbdev}1" # partition!
# check if device is mounted
if not self.is_mounted(self.backupdevice):
print("device is not mounted. trying to mount now")
pass
# For backup there must be an directory names ymsbackup which contains
# backup description and backup sets
# Desription and identification file backup.json?
# if plabel != 'BACKUP' or not os.path.isdir('ymsbackup')
mountpoint = os.path.join("/media", os.getlogin(), "BACKUP")
if not os.path.isdir(mountpoint):
print(f"Device is not mounted at {mountpoint}")
def on_but_usbinit_clicked(self, widget):
if self.backupdevice is None:
return
# UUID of devive -> settings
# check if backups already exist
answer = gtkutils.questionbox(
_("Initialize USB-Stick\n"
"All data on that device will be lost!\n"
"Are you really sure?"
), title="YMS")
if answer == False:
return
if self.label['usb_fstype'].get_text() != 'ext4':
print("formatting {self.backupdevice} with ext4")
#try:
# subprocess.run(["sudo", "mkfs.ext4", "-L", "BACKUP", self.backupdevice], check=True)
#except subprocess.CalledProcessError as e:
# print("formatting failed: ", e)
myself = os.getlogin()
mountpoint = os.path.join("/media", myself, "backup")
basedir = os.path.join(mountpoint, 'ymsbackup')
print(basedir)
# mkdir basedir
# chown (os.getlogin(), 'yms')
# chmod 770
else:
#
pass
def on_cmb_vessel_changed(self, widget):
self.context.vessel.load(combobox.get_list_value(widget))
sql = ("UPDATE settings SET valint=%s WHERE userid=0 AND sno=1")
@@ -189,7 +335,20 @@ class BaseView(View):
def display_vessel(self, vessel):
self.label['vesselname'].set_text(vessel.vesselname)
self.label['model'].set_text(vessel.model or '')
self.label['year_built'].set_text(self.format_int(vessel.year_built, default='n/a'))
self.label['shipyard'].set_text(str(vessel.shipyard))
self.label['year_built'].set_text(self.format_int(vessel.year_built, False, default='n/a'))
self.label['loa'].set_text(self.format_float(vessel.loa, 2, suffix="m"))
self.label['lwl'].set_text(self.format_float(vessel.lwl, 2, suffix="m"))
self.label['beam'].set_text(self.format_float(vessel.beam, 2, suffix="m"))
self.label['draught'].set_text(self.format_float(vessel.draught, 2, suffix="m"))
self.label['draught_min'].set_text(self.format_float(vessel.draught_min, 2, suffix="m"))
self.label['displacement'].set_text(self.format_int(vessel.displacement, 2, suffix="kg"))
self.label['ballast'].set_text(self.format_int(vessel.ballast, 2, suffix="kg"))
self.label['belt_bow'].set_text(self.format_float(vessel.beltpos_bow, 2, suffix="m"))
self.label['belt_aft'].set_text(self.format_float(vessel.beltpos_aft, 2, suffix="m"))
self.label['hull_shape'].set_text(vessel.shapefile or '')
self.label['storage_def'].set_text(str(vessel.sid_default))
self.label['remarks'].set_text(vessel.remarks or '')
def edit_vessel(self, vessel):
self.entry['vesselname'].set_text(vessel.vesselname)
+39 -3
View File
@@ -5,12 +5,14 @@ from gi.repository import GLib, Gtk, Gdk
from .view import View
from yms import gtkutils, combobox, treeview
from yms.lookup import Dropdown
from yms.model import box
class BoxesView(View):
def __init__(self, context):
super().__init__(context, _("Box"), "boxes.ui")
super().__init__(context, _("Boxes"), "boxes.ui")
self.context = context
# box already used for controls so other name here
self.sbox = box.Box(context.db) # current record
@@ -33,12 +35,33 @@ class BoxesView(View):
treeview.add_column(self.tree['box'], _('Remarks'), 3)
self.tree['box'].set_model(self.lst_box)
self.dd_boxtype = self.context.lookup.dropdown(Dropdown.BOX_TYPE)
combobox.load_from_dict(self.combo['type'], self.dd_boxtype)
def load_list(self):
pass
def clear_record(self):
self.entry['label'].set_text('')
self.entry['content'].set_text('')
self.spin['wx'].set_value(0)
self.spin['wy'].set_value(0)
self.spin['wz'].set_value(0)
self.text['remarks'].get_buffer().set_text('')
def display_record(self):
self.label['label'].set_text(self.sbox.label)
# storage sid
self.label['content'].set_text(self.sbox.content or '')
self.label['type'].set_text(self.dd_boxtype[self.sbox.boxtype])
self.label['color'].set_text(self.sbox.color or '')
if self.sbox.color:
self.label['color'].set_markup(f'#{self.sbox.color} <span foreground="#{self.sbox.color}">●</span>')
else:
self.label['color'].set_text('')
self.label['weight'].set_text(self.format_float(self.sbox.weight, 2, suffix='kg'))
self.label['weight_net'].set_text(self.format_float(self.sbox.weight_net, 2, suffix='kg'))
self.label['price'].set_text(self.format_float(self.sbox.price, 2, suffix='€'))
self.label['remarks'].set_text(self.sbox.remarks or '')
def edit_record(self):
@@ -64,14 +87,27 @@ class BoxesView(View):
self.topwidget.set_visible_child(self.box['box_edit'])
def on_but_detail_clicked(self, widget):
sid = treeview.get_value(self.tree['box'], 0)
self.sbox.load(sid)
boxid = treeview.get_value(self.tree['box'], 0)
if not boxid:
return
self.sbox.load(boxid)
self.display_record()
self.topwidget.set_visible_child(self.box['box_detail'])
self.button['close'].grab_focus()
def on_tvw_box_row_activated(self, widget, path, column):
boxid = treeview.get_value(widget, 0)
self.sbox.load(boxid)
self.display_record()
self.topwidget.set_visible_child(self.box['box_detail'])
self.button['close'].grab_focus()
# buttons on detail page
# edit2 uses edit callback
def on_but_close_clicked(self, widget):
boxid = treeview.get_value(self.tree['box'], 0)
if not boxid:
return
self.topwidget.set_visible_child(self.box['box'])
def on_but_delete_clicked(self, widget):
+35 -1
View File
@@ -5,6 +5,7 @@ from gi.repository import Gtk
from .view import View
from yms import gtkutils, combobox, treeview
from yms.lookup import Dropdown
from yms.model import cable
class CablesView(View):
@@ -36,6 +37,9 @@ class CablesView(View):
treeview.add_column(self.tree['cables'], _('Condition'), 2)
self.tree['cables'].set_model(self.lst_cables)
self.dd_type = self.context.lookup.dropdown(Dropdown.CABLE_TYPE)
self.dd_tech = self.context.lookup.dropdown(Dropdown.CABLE_TECHNAME)
# buttons on list page
def on_but_new_clicked(self, widget):
self.topwidget.set_visible_child(self.box['cable_edit'])
@@ -44,8 +48,20 @@ class CablesView(View):
self.topwidget.set_visible_child(self.box['cable_edit'])
def on_but_detail_clicked(self, widget):
cableid = treeview.get_value(self.tree['cables'], 0)
if not cableid:
return
self.cable.load(cableid)
self.display_record()
self.topwidget.set_visible_child(self.box['cable_detail'])
self.button['close'].grab_focus()
def on_tvw_cables_row_activated(self, widget, path, column):
cableid = treeview.get_value(widget, 0)
self.cable.load(cableid)
self.display_record()
self.topwidget.set_visible_child(self.box['cable_detail'])
# buttons on detail page
# edit2 uses edit callback
def on_but_close_clicked(self, widget):
@@ -62,7 +78,25 @@ class CablesView(View):
self.topwidget.set_visible_child(self.box['cables'])
def display_record(self):
pass
self.label['name'].set_text(self.cable.cablename)
self.label['type'].set_text(self.dd_type[self.cable.cabletype])
if self.cable.techname:
self.label['techname'].set_text(self.dd_tech[self.cable.techname])
else:
self.label['techname'].set_text('')
self.label['length'].set_text(self.format_int(self.cable.length))
self.label['conductors'].set_text(self.format_int(self.cable.conductors))
self.label['diameter'].set_text(self.format_float(self.cable.diameter, 1))
self.label['xsection'].set_text(self.format_float(self.cable.xsection, 1))
self.label['weight'].set_text(self.format_float(self.cable.weight))
if self.cable.color:
self.label['color'].set_markup(f'#{self.cable.color} <span foreground="#{self.cable.color}">●</span>')
else:
self.label['color'].set_text('')
self.label['supplier'].set_text(str(self.cable.supplier))
self.label['manufacturer'].set_text(str(self.cable.manufacturer))
self.label['condition'].set_text(self.cable.cablecond)
self.label['remarks'].set_text(self.cable.remarks or '')
def edit_record(self):
pass
+71 -16
View File
@@ -5,12 +5,14 @@ from gi.repository import Gtk
from .view import View
from yms import gtkutils, combobox, treeview
from yms.lookup import Dropdown
from yms.model import company
class CompaniesView(View):
def __init__(self, context):
super().__init__(context, _("Companies"), "companies.ui")
self.context = context
self.comp = company.Company(context.db) # current record
self.newrecord = False
@@ -20,7 +22,13 @@ class CompaniesView(View):
self.comptype = dict(self.db.cur.fetchall())
combobox.load_from_dict(self.combo['flt_type'], {-2: _("─── all ───")} | self.comptype, -2)
# companied
self.dd_comptype = self.context.lookup.dropdown(Dropdown.COMPANY_TYPE)
combobox.load_from_dict(self.combo['comptype'], self.dd_comptype)
combobox.load_from_dict(self.combo['comptype2'], self.dd_comptype)
self.dd_flags = context.lookup.enum('company.flags')
# companies
self.lst_companies = Gtk.ListStore(int, str, str, str)
self.db.cur.execute("SELECT compid, compname, comptype, remarks FROM company ORDER BY compname")
for row in self.db.cur.fetchall():
@@ -31,30 +39,77 @@ class CompaniesView(View):
treeview.add_column(self.tree['companies'], _('Remarks'), 3)
self.tree['companies'].set_model(self.lst_companies)
def display_company(self, company):
self.entry['compname'].set_text(company.compname)
# Type
# Type2
self.entry['shortname'].set_text(company.shortname)
self.entry['street'].set_text(company.street)
self.entry['zip'].set_text(company.zip)
self.entry['city'].set_text(company.city)
self.entry['country'].set_text(company.country)
self.entry['contact'].set_text(company.contact)
self.entry['phone'].set_text(company.phone)
self.entry['email'].set_text(company.email)
self.entry['web'].set_text(company.web)
self.entry['customerno'].set_text(company.customerno)
self.entry['contractno'].set_text(company.contractno)
def clear_record(self):
self.entry['name'].set_text('')
self.entry['shortname'].set_text('')
self.entry['street'].set_text('')
self.entry['zip'].set_text('')
self.entry['city'].set_text('')
self.entry['country'].set_text('')
self.entry['contact'].set_text('')
self.entry['phone'].set_text('')
self.entry['email'].set_text('')
self.entry['web'].set_text('')
self.entry['customerno'].set_text('')
self.entry['contractno'].set_text('')
combobox.activate_row(self.combo['comptype'], -1)
combobox.activate_row(self.combo['comptype2'], -1)
def display_record(self):
self.label['name'].set_text(self.comp.compname)
self.label['shortname'].set_text(self.comp.shortname or '')
self.label['type'].set_text(self.dd_comptype.get(self.comp.comptype, ''))
self.label['type2'].set_text(self.dd_comptype.get(self.comp.comptype2, ''))
self.label['street'].set_text(self.comp.street or '')
self.label['zip'].set_text(self.comp.zip or '')
self.label['city'].set_text(self.comp.city or '')
self.label['country'].set_text(self.comp.country or '')
self.label['phone'].set_text(self.comp.phone or '')
self.label['email'].set_text(self.comp.email or '')
self.label['web'].set_text(self.comp.web or '')
self.label['customerno'].set_text(self.comp.customerno or '')
self.label['contractno'].set_text(self.comp.contractno or '')
self.label['flags'].set_text(self.comp.flags or '')
self.label['remarks'].set_text(self.comp.remarks or '')
def edit_record(self):
self.entry['compname'].set_text(self.comp.compname)
# Type self.dd_comptype.get(self.comp.comptype, -1)
# Type2 self.dd_comptype.get(self.comp.comptype2, -1)
self.entry['shortname'].set_text(self.comp.shortname or '')
self.entry['street'].set_text(self.comp.street or '')
self.entry['zip'].set_text(self.comp.zip or '')
self.entry['city'].set_text(self.comp.city or '')
self.entry['country'].set_text(self.comp.country or '')
self.entry['contact'].set_text(self.comp.contact or '')
self.entry['phone'].set_text(self.comp.phone or '')
self.entry['email'].set_text(self.comp.email or '')
self.entry['web'].set_text(self.comp.web or '')
self.entry['customerno'].set_text(self.comp.customerno or '')
self.entry['contractno'].set_text(self.comp.contractno or '')
# buttons on list page
def on_but_new_clicked(self, widget):
self.topwidget.set_visible_child(self.box['comp_edit'])
def on_but_edit_clicked(self, widget):
compid = treeview.get_value(self.tree['companies'], 0)
if not compid:
return
self.topwidget.set_visible_child(self.box['comp_edit'])
def on_but_detail_clicked(self, widget):
compid = treeview.get_value(self.tree['companies'], 0)
if not compid:
return
self.comp.load(compid)
self.display_record()
self.topwidget.set_visible_child(self.box['comp_detail'])
def on_tvw_companies_row_activated(self, widget, path, column):
compid = treeview.get_value(widget, 0)
self.comp.load(compid)
self.display_record()
self.topwidget.set_visible_child(self.box['comp_detail'])
# buttons on detail page
+75 -2
View File
@@ -1,7 +1,8 @@
# SPDX-License-Identifier: WTFPL
import os
from gi.repository import GLib, Gtk, Gdk
from gi.repository import GLib, Gtk, Gdk, GdkPixbuf, Rsvg
import fitz
from .view import View
from yms import gtkutils, combobox, treeview
@@ -11,6 +12,7 @@ class DocumentsView(View):
def __init__(self, context):
super().__init__(context, _("Documents"), "documents.ui")
self.context = context
self.doc = document.Document(context.db) # current record
self.newrecord = False
@@ -41,7 +43,18 @@ class DocumentsView(View):
self.topwidget.set_visible_child(self.box['doc_edit'])
def on_but_detail_clicked(self, widget):
docid = treeview.get_value(self.tree['documents'], 0)
self.doc.load(docid)
self.display_record()
self.topwidget.set_visible_child(self.box['doc_detail'])
self.button['close'].grab_focus()
def on_tvw_documents_row_activated(self, widget, path, column):
docid = treeview.get_value(widget, 0)
self.doc.load(docid)
self.display_record()
self.topwidget.set_visible_child(self.box['doc_detail'])
self.button['close'].grab_focus()
# buttons on detail page
# edit2 uses edit callback
@@ -58,8 +71,68 @@ class DocumentsView(View):
def on_but_cancel_clicked(self, widget):
self.topwidget.set_visible_child(self.box['documents'])
def pdf_to_pixbuf(self, filename, max_width=400, max_height=400):
doc = fitz.open(filename)
page = doc[0]
rect = page.rect
scale = min(max_width / rect.width, max_height / rect.height)
matrix = fitz.Matrix(scale, scale)
pix = page.get_pixmap(matrix=matrix, alpha=False)
pixbuf = GdkPixbuf.Pixbuf.new_from_data(
pix.samples,
GdkPixbuf.Colorspace.RGB,
pix.alpha,
8,
pix.width,
pix.height,
pix.stride,
None,
None
)
return pixbuf
def display_record(self):
pass
print(self.doc)
self.label['title'].set_text(self.doc.title or '')
self.label['filename'].set_text(self.doc.filename)
# self.label['extents'] -> see below
self.label['mimetype'].set_text(self.doc.mimetype)
self.label['filesize'].set_text(self.format_int(self.doc.docsize, suffix="Byte"))
self.label['date'].set_text(self.format_date(self.doc.docdate))
self.label['doctype'].set_text(self.doc.doctype)
self.label['roleaccess'].set_text(self.doc.roleaccess)
self.label['doctype'].set_text(self.doc.remarks or '')
# image preview
if self.doc.doctype == 'picture':
filename = f"pic-{self.doc.pk_value:06d}.{self.doc.extension}"
imgpath = os.path.join(self.context.cfg['docpath'], filename)
info = GdkPixbuf.Pixbuf.get_file_info(imgpath)
if info:
imgformat, imgwidth, imgheight = info
self.label['extents'].set_text(f"{imgwidth}x{imgheight} Pixel")
if imgwidth > 400 or imgheight > 400:
print("loading scaled")
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(imgpath, 400, 400, True)
else:
print("loading")
pixbuf = GdkPixbuf.Pixbuf.new_from_file(imgpath)
else:
print("cannot get image info")
self.image['preview'].set_from_pixbuf(pixbuf)
elif self.doc.doctype == 'drawing':
filename = f"drw-{self.doc.pk_value:06d}.{self.doc.extension}"
imgpath = os.path.join(self.context.cfg['docpath'], filename)
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(imgpath, 400, 400, True)
self.image['preview'].set_from_pixbuf(pixbuf)
elif self.doc.mimetype == "application/pdf":
filename = f"doc-{self.doc.pk_value:06d}.{self.doc.extension}"
imgpath = os.path.join(self.context.cfg['docpath'], filename)
print(imgpath)
pixbuf = self.pdf_to_pixbuf(imgpath)
self.image['preview'].set_from_pixbuf(pixbuf)
else:
self.image['preview'].clear()
def edit_record(self):
pass
+22 -1
View File
@@ -5,12 +5,14 @@ from gi.repository import GLib, Gtk, Gdk
from .view import View
from yms import gtkutils, combobox, treeview
from yms.lookup import Dropdown
from yms.model import equipment
class EquipmentView(View):
def __init__(self, context):
super().__init__(context, _("Equipment"), "equipment.ui")
self.context = context
self.equip = equipment.Equipment(context.db) # current record
self.newrecord = False
@@ -36,11 +38,19 @@ class EquipmentView(View):
treeview.add_column(self.tree['equipment'], _('Remarks'), 6)
self.tree['equipment'].set_model(self.lst_equipment)
self.dd_category = self.context.lookup.dropdown(Dropdown.EQUIPMENT_CATEGORY)
#combobox.load_from_dict(self.combo['unit'], self.dd_unit)
# buttons on list page
def on_but_new_clicked(self, widget):
self.newrecord = True
self.label['title_editor'].set_text(_("Add new Equipment"))
self.clear_record()
self.equip.vid = self.context.vessel.vid
self.topwidget.set_visible_child(self.box['equip_edit'])
def on_but_edit_clicked(self, widget):
self.label['title_edit'].set_text(_("Edit Equipment"))
self.topwidget.set_visible_child(self.box['equip_edit'])
def on_but_detail_clicked(self, widget):
@@ -48,6 +58,7 @@ class EquipmentView(View):
self.equip.load(eid)
self.display_record()
self.topwidget.set_visible_child(self.box['equip_detail'])
self.button['close'].grab_focus()
def on_tvw_equipment_row_activated(self, widget, path, column):
eid = treeview.get_value(widget, 0)
@@ -72,7 +83,17 @@ class EquipmentView(View):
def display_record(self):
print(self.equip)
#self.label['name'].set_text(self.equip.sname)
self.label['name'].set_text(self.equip.ename)
self.label['shortname'].set_text(self.equip.shortname or '')
#lookup self.label['manufacturer'].set_text(self.equip.manufacturer)
self.label['model'].set_text(self.equip.model or '')
self.label['serial'].set_text(self.equip.serial or '')
self.label['weight'].set_text(self.format_float(self.equip.weight, 2, suffix='kg'))
self.label['price'].set_text(self.format_float(self.equip.price, 2, suffix='€'))
self.label['date_purch'].set_text(self.equip.purchdate or '')
#lookup self.label['supplier'].set_text(self.equip.supplier)
self.label['category'].set_text(self.dd_category[self.equip.ecat])
self.label['flags'].set_text(self.equip.flags or '')
self.label['remarks'].set_text(self.equip.remarks or '')
def edit_record(self):
+24 -1
View File
@@ -5,6 +5,7 @@ from gi.repository import Gtk
from .view import View
from yms import gtkutils, combobox, treeview
from yms.lookup import Dropdown
from yms.model import fuse
class FusesView(View):
@@ -38,6 +39,8 @@ class FusesView(View):
treeview.add_column(self.tree['fuses'], _('Description'), 3)
self.tree['fuses'].set_model(self.lst_fuses)
self.dd_type = self.context.lookup.dropdown(Dropdown.FUSE_TYPE)
# buttons on list page
def on_but_new_clicked(self, widget):
self.topwidget.set_visible_child(self.box['fuse_edit'])
@@ -46,7 +49,20 @@ class FusesView(View):
self.topwidget.set_visible_child(self.box['fuse_edit'])
def on_but_detail_clicked(self, widget):
fuseid = treeview.get_value(self.tree['fuses'], 0)
if not fuseid:
return
self.fuse.load(fuseid)
self.display_record()
self.topwidget.set_visible_child(self.box['fuse_detail'])
self.button['close'].grab_focus()
def on_tvw_fuses_row_activated(self, widget, path, column):
fuseid = treeview.get_value(widget, 0)
self.fuse.load(fuseid)
self.display_record()
self.topwidget.set_visible_child(self.box['fuse_detail'])
self.button['close'].grab_focus()
# buttons on detail page
# edit2 uses edit callback
@@ -64,7 +80,14 @@ class FusesView(View):
self.topwidget.set_visible_child(self.box['fuses'])
def display_record(self):
pass
self.label['fnumber'].set_text(f"F{self.fuse.fnumber}")
self.label['type'].set_text(self.dd_type[self.fuse.ftype])
self.label['current'].set_text(self.format_float(self.fuse.current, 2, suffix="A"))
self.label['cable'].set_text(str(self.fuse.cableid))
self.label['equipment'].set_text(str(self.fuse.eid))
self.label['location'].set_text(str(self.fuse.location))
self.label['description'].set_text(str(self.fuse.description or ''))
self.label['remarks'].set_text(str(self.fuse.remarks or ''))
def edit_record(self):
pass
+8
View File
@@ -5,6 +5,7 @@ from gi.repository import GLib, Gtk, Gdk
from .view import View
from yms import gtkutils, combobox, treeview
from yms.lookup import Dropdown
from yms.model import inventory
class InventoryView(View):
@@ -39,6 +40,8 @@ class InventoryView(View):
treeview.add_column(self.tree['inventory'], _('Remarks'), 5)
self.tree['inventory'].set_model(self.lst_inventory)
self.dd_category = self.context.lookup.dropdown(Dropdown.INVENTORY_CATEGORY)
# buttons on list page
def on_but_new_clicked(self, widget):
self.topwidget.set_visible_child(self.box['inv_edit'])
@@ -51,6 +54,7 @@ class InventoryView(View):
self.inv.load(invid)
self.display_record()
self.topwidget.set_visible_child(self.box['inv_detail'])
self.button['close'].grab_focus()
def on_tvw_inventory_row_activated(self, widget, path, column):
invid = treeview.get_value(widget, 0)
@@ -85,6 +89,10 @@ class InventoryView(View):
self.label['price'].set_text(self.format_float(self.inv.price, suffix='€'))
self.label['purchdate'].set_text(self.format_date(self.inv.purchdate))
self.label['condition'].set_text(self.inv.invcond)
if self.inv.icat is not None:
self.label['category'].set_text(self.dd_category[self.inv.icat])
else:
self.label['category'].set_text('')
self.label['remarks'].set_text(self.inv.remarks or '')
def edit_record(self):
+24 -2
View File
@@ -40,7 +40,20 @@ class MaintenanceView(View):
self.topwidget.set_visible_child(self.box['maint_edit'])
def on_but_detail_clicked(self, widget):
self.topwidget.set_visible_child(self.box['maintv_detail'])
maintid = treeview.get_value(self.tree['maintenance'], 0)
if not maintid:
return
self.maint.load(maintid)
self.display_record()
self.topwidget.set_visible_child(self.box['maint_detail'])
self.button['close'].grab_focus()
def on_tvw_maintenance_row_activated(self, widget, path, column):
maintid = treeview.get_value(widget, 0)
self.maint.load(maintid)
self.display_record()
self.topwidget.set_visible_child(self.box['maint_detail'])
self.button['close'].grab_focus()
# buttons on detail page
# edit2 uses edit callback
@@ -58,7 +71,16 @@ class MaintenanceView(View):
self.topwidget.set_visible_child(self.box['maintenance'])
def display_record(self):
pass
self.label['activities'].set_text(self.maint.activities)
self.label['equipment'].set_text(str(self.maint.eid))
self.label['series'].set_text(str(self.maint.series))
self.label['interval'].set_text(self.format_int(self.maint.interval_hours))
self.label['last'].set_text(self.format_int(self.maint.last_hours))
self.label['plandate'].set_text(self.format_date(self.maint.plan_date))
self.label['completion'].set_text(self.format_date(self.maint.completion_date))
self.label['status'].set_text(self.maint.maintstate)
self.label['remarks'].set_text(self.maint.remarks or '')
def edit_record(self):
pass
+102
View File
@@ -0,0 +1,102 @@
# SPDX-License-Identifier: WTFPL
import os
from gi.repository import Gtk
from .view import View
from yms import gtkutils, combobox, treeview
from yms.lookup import Dropdown
from yms.model import measurement
class MeasurementView(View):
def __init__(self, context):
super().__init__(context, _("Measurements"), "measurement.ui")
self.measure = measurement.Measurement(context.db) # current record
self.newrecord = False
# measurement units
self.dd_unit = self.context.lookup.dropdown(Dropdown.UNIT)
self.lst_measurement = Gtk.ListStore(int, str, str, str, str, str)
sql = (
"SELECT m.mid, m.mname, m.nval, m.val1, m.val2, m.val3, m.unit, "
"m.accuracy, m.note, e.ename "
"FROM measurement AS m LEFT OUTER JOIN equipment AS e USING (eid) "
"WHERE m.vid=%s "
"ORDER BY m.mid"
)
self.db.dcur.execute(sql, (context.vessel.vid,))
for row in self.db.dcur.fetchall():
if row['nval'] == 1:
value = "{} {}".format(row['val1'], row['unit'])
elif row['nval'] == 2:
value = "{}x{} {}".format(row['val1'], row['val2'], row['unit'])
elif row['nval'] == 3:
value = "{}x{}x{} {}".format(row['val1'], row['val2'], row['val3'], row['unit'])
else:
#invalid
value = "#invalid"
data = (
row['mid'],
row['mname'],
value,
row['accuracy'],
row['ename'],
row['note'] or ''
)
self.lst_measurement.append(data)
treeview.add_column(self.tree['measurement'], _('ID'), 0)
treeview.add_column(self.tree['measurement'], _('Measurement'), 1)
treeview.add_column(self.tree['measurement'], _('Value'), 2)
treeview.add_column(self.tree['measurement'], _('Accuracy'), 3)
treeview.add_column(self.tree['measurement'], _('Equipment'), 4)
treeview.add_column(self.tree['measurement'], _('Note'), 5)
self.tree['measurement'].set_model(self.lst_measurement)
# buttons on list page
def on_but_new_clicked(self, widget):
self.topwidget.set_visible_child(self.box['measure_edit'])
def on_but_edit_clicked(self, widget):
self.topwidget.set_visible_child(self.box['measure_edit'])
def on_but_detail_clicked(self, widget):
mid = treeview.get_value(self.tree['measurement'], 0)
if not mid:
return
self.measure.load(mid)
self.display_record()
self.topwidget.set_visible_child(self.box['measure_detail'])
self.button['close'].grab_focus()
def on_tvw_measurement_row_activated(self, widget, path, column):
mid = treeview.get_value(widget, 0)
self.measure.load(mid)
self.display_record()
self.topwidget.set_visible_child(self.box['measure_detail'])
self.button['close'].grab_focus()
# buttons on detail page
# edit2 uses edit callback
def on_but_close_clicked(self, widget):
self.topwidget.set_visible_child(self.box['measurement'])
def on_but_delete_clicked(self, widget):
self.topwidget.set_visible_child(self.box['measurement'])
# buttons on edit page
def on_but_save_clicked(self, widget):
pass
def on_but_cancel_clicked(self, widget):
self.topwidget.set_visible_child(self.box['measurement'])
def display_record(self):
self.label['name'].set_text(self.measure.mname)
self.label['note'].set_text(self.measure.note or '')
def edit_record(self):
pass
+25 -1
View File
@@ -11,6 +11,7 @@ class ProjectsView(View):
def __init__(self, context):
super().__init__(context, _("Projects"), "projects.ui")
self.context = context
self.project = project.Project(context.db) # current record
self.newrecord = False
@@ -42,6 +43,9 @@ class ProjectsView(View):
treeview.add_column(self.tree['projects'], _('Remarks'), 5)
self.tree['projects'].set_model(self.lst_projects)
self.dd_user = context.lookup.user()
self.dd_state = self.context.lookup.enum('project.projstate')
# buttons on list page
def on_but_new_clicked(self, widget):
self.topwidget.set_visible_child(self.box['proj_edit'])
@@ -50,7 +54,20 @@ class ProjectsView(View):
self.topwidget.set_visible_child(self.box['proj_edit'])
def on_but_detail_clicked(self, widget):
projid = treeview.get_value(self.tree['projects'], 0)
if not projid:
return
self.project.load(projid)
self.display_record()
self.topwidget.set_visible_child(self.box['proj_detail'])
self.button['close'].grab_focus()
def on_tvw_projects_row_activated(self, widget, path, column):
projid = treeview.get_value(widget, 0)
self.project.load(projid)
self.display_record()
self.topwidget.set_visible_child(self.box['proj_detail'])
self.button['close'].grab_focus()
# buttons on detail page
# edit2 uses edit callback
@@ -68,7 +85,14 @@ class ProjectsView(View):
self.topwidget.set_visible_child(self.box['projects'])
def display_record(self):
pass
self.label['name'].set_text(self.project.projname)
self.label['responsible'].set_text(self.dd_user[self.project.responsible])
self.label['date_start'].set_text(self.format_date(self.project.startdate))
self.label['duration'].set_text(self.format_int(self.project.duration, suffix="Days"))
self.label['costs_plan'].set_text(self.format_float(self.project.costs_plan, 2, suffix="€"))
self.label['costs_final'].set_text(self.format_float(self.project.costs_final, 2, suffix="€"))
self.label['status'].set_text(self.project.projstate)
self.label['remarks'].set_text(self.project.remarks or '')
def edit_record(self):
pass
+30 -1
View File
@@ -11,6 +11,7 @@ class ProvisionsView(View):
def __init__(self, context):
super().__init__(context, _("Provisions"), "provisions.ui")
self.context = context
self.prov = provision.Provision(context.db) # current record
self.newrecord = False
@@ -21,7 +22,7 @@ class ProvisionsView(View):
sql = (
"SELECT p.provid, p.provname, p.number, p.unit, p.storedate, p.shelflife "
"FROM provisions AS p LEFT OUTER JOIN storage AS s USING (sid) "
"WHERE s.vid=%s"
"WHERE s.vid=%s OR vid IS NULL"
)
self.db.dcur.execute(sql, (context.vessel.vid,))
for row in self.db.dcur.fetchall():
@@ -55,7 +56,18 @@ class ProvisionsView(View):
self.topwidget.set_visible_child(self.box['prov_edit'])
def on_but_detail_clicked(self, widget):
provid = treeview.get_value(self.tree['provisions'], 0)
self.prov.load(provid)
self.display_record()
self.topwidget.set_visible_child(self.box['prov_detail'])
self.button['close'].grab_focus()
def on_tvw_provisions_row_activated(self, widget, path, column):
provid = treeview.get_value(widget, 0)
self.prov.load(provid)
self.display_record()
self.topwidget.set_visible_child(self.box['prov_detail'])
self.button['close'].grab_focus()
# buttons on detail page
# edit2 uses edit callback
@@ -71,3 +83,20 @@ class ProvisionsView(View):
def on_but_cancel_clicked(self, widget):
self.topwidget.set_visible_child(self.box['provisions'])
def display_record(self):
print(self.prov)
self.label['name'].set_text(self.prov.provname)
self.label['category'].set_text(str(self.prov.provcat))
self.label['storage'].set_text(str(self.prov.sid))
self.label['box'].set_text(str(self.prov.boxid))
self.label['number'].set_text(str(self.prov.number))
self.label['unit'].set_text(str(self.prov.unit))
self.label['target'].set_text(str(self.prov.target))
self.label['weight'].set_text(self.format_float(self.prov.weight, 2, suffix='kg'))
self.label['weight_net'].set_text(self.format_float(self.prov.weight_net, 2, suffix='kg'))
self.label['price'].set_text(self.format_float(self.prov.price, 2, suffix='€'))
self.label['remarks'].set_text(self.prov.remarks or '')
def edit_record(self):
pass
+1 -1
View File
@@ -11,7 +11,7 @@ class StatusView:
def __init__(self, context):
self.context = context
self.title = _("Status")
self._title = _("Status")
builder = Gtk.Builder()
builder.set_translation_domain(context.textdomain)
builder.add_from_file(os.path.join(context.ui_path, "status.ui"))
+40 -25
View File
@@ -5,14 +5,13 @@ from gi.repository import GLib, Gtk, Gdk
from .view import View
from yms import gtkutils, combobox, treeview
from yms.model import storage
from yms.lookup import Dropdown
from yms.model import storage
class StorageView(View):
def __init__(self, context):
super().__init__(context, _("Storage"), "storage.ui")
self.context = context
self.storage = storage.Storage(context.db) # current record
@@ -27,15 +26,11 @@ class StorageView(View):
treeview.add_column(self.tree['storage'], _('Remarks'), 3)
self.tree['storage'].set_model(self.lst_storage)
#combodict = self.context.lookup.dropdown(Dropdown.STORAGE_TYPE)
#combobox.load_from_dict(self.combo['type'], combodict)
self.dd_stype = self.context.lookup.dropdown(Dropdown.STORAGE_TYPE)
combobox.load_from_dict(self.combo['type'], self.dd_stype)
combodict = self.context.lookup.dropdown(Dropdown.STORAGE_TYPE)
print(combodict)
combobox.load_from_dict(self.combo['type'], combodict)
combodict = self.context.lookup.enum('storage.capaunit')
combobox.load_from_dict(self.combo['unit'], combodict)
self.dd_unit = self.context.lookup.enum('storage.capaunit')
combobox.load_from_dict(self.combo['unit'], self.dd_unit)
def add_row(self):
pass
@@ -55,8 +50,32 @@ class StorageView(View):
for row in self.db.cur.fetchall():
self.lst_storage.append(row)
def clear_record(self):
self.storage.clear()
self.entry['sname'].set_text('')
self.spin['x'].set_value(0)
self.spin['y'].set_value(0)
self.spin['z'].set_value(0)
self.spin['wx'].set_value(0)
self.spin['wy'].set_value(0)
self.spin['wz'].set_value(0)
self.spin['angle'].set_value(0)
self.spin['capacity'].set_value(0)
combobox.activate_row(self.combo['type'], -1)
combobox.activate_row(self.combo['unit'], -1)
self.text['remarks'].get_buffer().set_text('')
def display_record(self):
self.label['name'].set_text(self.storage.sname)
self.label['type'].set_text(self.dd_stype[self.storage.stype])
self.label['position'].set_text(f"({self.storage.x}, {self.storage.y}, {self.storage.z})")
self.label['dimension'].set_text(f"({self.storage.wx}, {self.storage.wy}, {self.storage.wz})")
self.label['angle'].set_text(f"{self.storage.angle}°")
self.label['capacity'].set_text(f"{self.storage.capacity} {self.storage.capaunit}")
if self.storage.color:
self.label['color'].set_markup(f'#{self.storage.color} <span foreground="#{self.storage.color}">●</span>')
else:
self.label['color'].set_text('')
self.label['remarks'].set_text(self.storage.remarks or '')
def edit_record(self):
@@ -71,23 +90,9 @@ class StorageView(View):
self.spin['capacity'].set_value(self.storage.capacity)
combobox.activate_row(self.combo['type'], self.storage.stype)
combobox.activate_row(self.combo['unit'], self.storage.capaunit)
# flags
self.text['remarks'].get_buffer().set_text(self.storage.remarks or '')
def clear_record(self):
self.storage.clear()
self.entry['sname'].set_text('')
self.spin['x'].set_value(0)
self.spin['y'].set_value(0)
self.spin['z'].set_value(0)
self.spin['wx'].set_value(0)
self.spin['wy'].set_value(0)
self.spin['wz'].set_value(0)
self.spin['angle'].set_value(0)
self.spin['capacity'].set_value(0)
combobox.activate_row(self.combo['type'], -1)
combobox.activate_row(self.combo['unit'], .1)
self.text['remarks'].get_buffer().set_text('')
# buttons on list page
def on_but_new_clicked(self, widget):
self.newrecord = True
@@ -108,9 +113,19 @@ class StorageView(View):
def on_but_detail_clicked(self, widget):
sid = treeview.get_value(self.tree['storage'], 0)
if not sid:
return
self.storage.load(sid)
self.display_record()
self.topwidget.set_visible_child(self.box['stor_detail'])
self.button['close'].grab_focus()
def on_tvw_storage_row_activated(self, widget, path, column):
sid = treeview.get_value(widget, 0)
self.storage.load(sid)
self.display_record()
self.topwidget.set_visible_child(self.box['stor_detail'])
self.button['close'].grab_focus()
# buttons on detail page
# edit2 uses edit callback
+89
View File
@@ -0,0 +1,89 @@
# SPDX-License-Identifier: WTFPL
import os
from gi.repository import Gtk
from .view import View
from yms import gtkutils, combobox, treeview
from yms.model import task
class TasksView(View):
def __init__(self, context):
super().__init__(context, _("Tasks"), "tasks.ui")
self.context = context
self.task = task.Task(context.db) # current record
self.newrecord = False
self.lst_tasks = Gtk.ListStore(int, str, str, str, str)
sql = (
"SELECT t.taskid, t.taskname, t.priority, t.taskstate, "
"u.displayname AS responsible "
"FROM task AS t JOIN user AS u ON (t.responsible=u.userid)"
"WHERE t.vid=%s "
"ORDER BY t.taskid"
)
self.db.dcur.execute(sql, (context.vessel.vid,))
for row in self.db.dcur.fetchall():
data = (
row['taskid'],
row['taskname'],
row['priority'],
row['taskstate'],
row['responsible']
)
self.lst_tasks.append(data)
treeview.add_column(self.tree['tasks'], _('ID'), 0)
treeview.add_column(self.tree['tasks'], _('Name'), 1)
treeview.add_column(self.tree['tasks'], _('Priority'), 2)
treeview.add_column(self.tree['tasks'], _('Status'), 3)
treeview.add_column(self.tree['tasks'], _('Responsible'), 4)
self.tree['tasks'].set_model(self.lst_tasks)
# buttons on list page
def on_but_new_clicked(self, widget):
self.topwidget.set_visible_child(self.box['task_edit'])
def on_but_edit_clicked(self, widget):
self.topwidget.set_visible_child(self.box['task_edit'])
def on_but_detail_clicked(self, widget):
taskid = treeview.get_value(self.tree['tasks'], 0)
if not taskid:
return
self.task.load(taskid)
self.display_record()
self.topwidget.set_visible_child(self.box['task_detail'])
self.button['close'].grab_focus()
def on_tvw_tasks_row_activated(self, widget, path, column):
taskid = treeview.get_value(widget, 0)
self.task.load(taskid)
self.display_record()
self.topwidget.set_visible_child(self.box['task_detail'])
# buttons on detail page
# edit2 uses edit callback
def on_but_close_clicked(self, widget):
self.topwidget.set_visible_child(self.box['tasks'])
def on_but_delete_clicked(self, widget):
self.topwidget.set_visible_child(self.box['tasks'])
# buttons on edit page
def on_but_save_clicked(self, widget):
pass
def on_but_cancel_clicked(self, widget):
self.topwidget.set_visible_child(self.box['tasks'])
def display_record(self):
self.label['name'].set_text(self.task.taskname)
self.label['responsible'].set_text('')
self.label['status'].set_text(self.task.taskstate)
self.label['remarks'].set_text(self.task.remarks or '')
def edit_record(self):
pass
+1 -1
View File
@@ -17,7 +17,7 @@ class View:
self.db = context.db
self.vessel = context.vessel
self.user = context.user
self.title = title
self._title = title
builder = Gtk.Builder()
builder.set_translation_domain(context.textdomain)
builder.add_from_file(os.path.join(context.ui_path, ui_file))