From d72147c01273597ef5fd8ee0ea14e03c46956bcf Mon Sep 17 00:00:00 2001 From: Thomas Hooge Date: Sat, 12 Sep 2026 19:36:03 +0200 Subject: [PATCH] Native gui: implement data lists for all modules --- yms/combobox.py | 4 +- yms/model/dbrecord.py | 14 +- yms/model/document.py | 2 +- yms/model/vessel.py | 22 +- yms/ui/base.ui | 177 +++++++--- yms/ui/documents.ui | 222 +++++++++++- yms/ui/equipment.ui | 248 ++++++++++++- yms/ui/inventory.ui | 44 ++- yms/ui/maintenance.ui | 231 +++++++++++- yms/ui/projects.ui | 219 ++++++++++++ yms/ui/provisions.ui | 15 +- yms/ui/status.ui | 16 +- yms/ui/storage.ui | 762 ++++++++++++++++++++++++++++++++++++++++ yms/view/base.py | 160 ++++++--- yms/view/documents.py | 58 ++- yms/view/equipment.py | 57 ++- yms/view/inventory.py | 64 +++- yms/view/maintenance.py | 57 ++- yms/view/projects.py | 67 +++- yms/view/provisions.py | 72 +++- yms/view/status.py | 3 + yms/view/storage.py | 88 +++++ yms/view/view.py | 8 +- ymsgui.py | 27 +- 24 files changed, 2439 insertions(+), 198 deletions(-) create mode 100644 yms/ui/storage.ui create mode 100644 yms/view/storage.py diff --git a/yms/combobox.py b/yms/combobox.py index 1bcd7cf..b705f1e 100644 --- a/yms/combobox.py +++ b/yms/combobox.py @@ -33,7 +33,7 @@ def refresh_dict(combobox, dictionary, keep_selection=True): model = combobox.get_model() selected = get_value(combobox) model.clear() - for item in dictionary.iteritems(): + for item in dictionary.items(): model.append(item) if keep_selection: activate_row(combobox, selected) @@ -70,7 +70,7 @@ def get_value(combobox, decode=False): if active < 0: return None else: - if type(model) == gtk.TreeStore: + if type(model) == Gtk.TreeStore: it = combobox.get_active_iter() val = model.get_value(it, 0) if decode: diff --git a/yms/model/dbrecord.py b/yms/model/dbrecord.py index 2a24c7e..5f750e5 100644 --- a/yms/model/dbrecord.py +++ b/yms/model/dbrecord.py @@ -18,6 +18,7 @@ class DbRecord: raise TypeError("DbRecord subclass must define 'fields'") self.db = db + self.cur = db.cur self.dcur = db.dcur self.conn = db.conn self.last_update = None @@ -32,9 +33,10 @@ class DbRecord: self.clear() def clear(self): + self.data = {} # for old/new checks for field in self.fields: setattr(self, field, None) - self.data = {} # for old/new checks + self.data[field] = None def load(self, record_id=None): if record_id is not None: @@ -47,6 +49,8 @@ class DbRecord: self.dcur.execute(sql, (self.pk_value,)) self.data = self.dcur.fetchone() except Exception as e: + print(e) + print(sql) self.db.error = e self.clear() return False @@ -83,6 +87,9 @@ class DbRecord: try: self.dcur.execute(sql, values) except Exception as e: + print(e) + print(sql) + print(values) self.db.error = e return False for field in self.fields: @@ -106,6 +113,9 @@ class DbRecord: try: self.dcur.execute(sql, values) except Exception as e: + print(e) + print(sql) + print(values) self.db.error = e return False self.pk_value = self.dcur.lastrowid @@ -120,6 +130,8 @@ class DbRecord: try: self.dcur.execute(sql, (record_id,)) except Exception as e: + print(e) + print(sql) self.db.error = e return False if self.dcur.rowcount != 1: diff --git a/yms/model/document.py b/yms/model/document.py index 126153b..a3b39bb 100644 --- a/yms/model/document.py +++ b/yms/model/document.py @@ -10,6 +10,6 @@ class Document(DbRecord): 'hash', 'docsize', 'doctime', 'docdate', 'title', 'pages', 'remarks', 'roleaccess') - def __init__(self, db, dicid=None): + def __init__(self, db, docid=None): super().__init__(db, docid) self.title = _("Document({})") diff --git a/yms/model/vessel.py b/yms/model/vessel.py index eeda83b..11add82 100644 --- a/yms/model/vessel.py +++ b/yms/model/vessel.py @@ -8,8 +8,28 @@ class Vessel(DbRecord): pk_field = "vid" fields = ('vid', 'vtype', 'vesselname', 'model', 'shipyard', 'loa', 'lwl', 'beam', 'draught', 'draught_min', 'displacement', 'ballast', - 'beltpos_aft', 'beltpos_bow', 'shapefile', 'sid_default', 'remarks') + 'beltpos_aft', 'beltpos_bow', 'shapefile', 'sid_default', 'year_built', + 'remarks') def __init__(self, db, vid=None): super().__init__(db, vid) self.title = _("Vessel({})") + + def create(self): + sql = ( + "SELECT MIN(v1.vid+1) AS newid " + "FROM vessel AS v1 LEFT JOIN vessel AS v2 ON v2.vid=v1.vid+1 " + "WHERE v1.vid>=0 AND v2.vid IS NULL" + ) + self.dcur.execute(sql) + row = self.cur.fetchone() + if row is None: + # vessel table empty: create first vessel + self.pk_value = 1 + else: + # create additional vessel + self.pk_value = row['newid'] + self.vesselname = f"Vessel #{self.pk_value}" + self.vtype = 1 # monohull + self._insert() + self.conn.commit() diff --git a/yms/ui/base.ui b/yms/ui/base.ui index 54734be..8501b00 100644 --- a/yms/ui/base.ui +++ b/yms/ui/base.ui @@ -2,6 +2,46 @@ + + 20000 + 100 + 1000 + + + 10 + 0.10 + 1 + + + 50000 + 100 + 1000 + + + 5 + 0.10 + 1 + + + 5 + 0.10 + 1 + + + 100 + 0.10 + 1 + + + 100 + 0.10 + 1 + + + 2100 + 1 + 10 + True False @@ -31,6 +71,8 @@ True False + 4 + 4 @@ -40,12 +82,10 @@ - + True False - 4 - 4 4 4 4 @@ -104,7 +144,7 @@ 0 - 2 + 3 @@ -115,7 +155,7 @@ 0 - 3 + 4 @@ -126,7 +166,7 @@ 0 - 4 + 5 @@ -137,7 +177,7 @@ 0 - 5 + 6 @@ -148,24 +188,14 @@ 0 - 6 + 7 True True - 2 - - - 1 - 2 - - - - - True - True + adj_loa 2 @@ -174,9 +204,10 @@ - + True True + adj_lwl 2 @@ -185,9 +216,10 @@ - + True True + adj_beam 2 @@ -196,9 +228,10 @@ - + True True + adj_draught 2 @@ -206,6 +239,18 @@ 6 + + + True + True + adj_draught_min + 2 + + + 1 + 7 + + True @@ -214,7 +259,7 @@ 0 - 8 + 9 @@ -225,27 +270,29 @@ 0 - 9 + 10 True True + adj_displacement 1 - 8 + 9 True True + adj_ballast 1 - 9 + 10 @@ -256,25 +303,7 @@ 0 - 11 - - - - - True - True - True - natural - natural - word - 1 - 1 - 1 - 1 - - - 1 - 11 + 12 @@ -284,7 +313,7 @@ 1 - 10 + 11 @@ -295,7 +324,7 @@ 0 - 10 + 11 @@ -306,7 +335,7 @@ 0 - 7 + 8 @@ -316,7 +345,57 @@ 1 - 7 + 8 + + + + + True + True + in + + + True + True + True + natural + natural + word + 1 + 1 + 1 + 1 + + + + + + + 1 + 12 + + + + + True + False + Year built + + + 0 + 2 + + + + + True + True + 0 + adj_year_built + + + 1 + 2 diff --git a/yms/ui/documents.ui b/yms/ui/documents.ui index ace064b..c44956e 100644 --- a/yms/ui/documents.ui +++ b/yms/ui/documents.ui @@ -165,11 +165,12 @@ False end - + New True True True + True @@ -178,11 +179,12 @@ - + Edit True True True + True @@ -191,11 +193,12 @@ - - Delete + + Details True True True + True @@ -216,5 +219,216 @@ page0 + + + True + False + vertical + + + True + False + label + + + False + True + 0 + + + + + + True + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + True + 1 + + + + + True + False + end + + + Delete + True + True + True + + + + True + True + 0 + + + + + Edit + True + True + True + + + + True + True + 1 + + + + + Close + True + True + True + + + + True + True + 2 + + + + + False + True + 2 + + + + + page1 + page1 + 1 + + + + + True + False + vertical + + + + + + + True + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + True + 1 + + + + + True + False + end + + + Save + True + True + True + + + + True + True + 1 + + + + + Cancel + True + True + True + + + + True + True + 2 + + + + + False + True + 2 + + + + + page2 + page2 + 2 + + diff --git a/yms/ui/equipment.ui b/yms/ui/equipment.ui index 7d7fc3c..edaf6fe 100644 --- a/yms/ui/equipment.ui +++ b/yms/ui/equipment.ui @@ -2,7 +2,7 @@ - + True False 8 @@ -281,6 +281,7 @@ True True True + True @@ -311,6 +312,9 @@ True False Equipment details + + + False @@ -319,7 +323,7 @@ - + True False @@ -327,7 +331,7 @@ True False - label + Name 0 @@ -338,7 +342,7 @@ True False - label + Short name 0 @@ -349,13 +353,227 @@ True False - label + Manufacturer 0 2 + + + True + False + Model + + + 0 + 3 + + + + + True + False + Serial no. + + + 0 + 4 + + + + + True + False + Weight + + + 0 + 5 + + + + + True + False + Price + + + 0 + 6 + + + + + True + False + Date purchase + + + 0 + 7 + + + + + True + False + Supplier + + + 0 + 8 + + + + + True + False + Category + + + 0 + 9 + + + + + True + False + Remarks + + + 0 + 10 + + + + + True + False + Placeholder + + + 1 + 0 + + + + + True + False + + + 1 + 1 + + + + + True + False + + + 1 + 2 + + + + + True + False + + + 1 + 3 + + + + + True + False + + + 1 + 4 + + + + + True + False + + + 1 + 5 + + + + + True + False + + + 1 + 6 + + + + + True + False + + + 1 + 7 + + + + + True + False + + + 1 + 8 + + + + + True + False + + + 1 + 9 + + + + + True + False + + + 1 + 10 + + + + + + + + + + + + + + + + + @@ -407,6 +625,7 @@ True True True + True @@ -447,6 +666,21 @@ True False vertical + + + True + False + Edit Equipment + + + + + + False + True + 0 + + @@ -687,7 +921,7 @@ False True - 0 + 1 @@ -728,7 +962,7 @@ False True end - 1 + 2 diff --git a/yms/ui/inventory.ui b/yms/ui/inventory.ui index 2b7db1c..8cd6560 100644 --- a/yms/ui/inventory.ui +++ b/yms/ui/inventory.ui @@ -2,6 +2,21 @@ + + 1000 + 1 + 10 + + + 10000 + 10 + 100 + + + 1000 + 1 + 10 + True False @@ -166,7 +181,7 @@ 2 end - + New True True @@ -179,7 +194,7 @@ - + Edit True True @@ -192,7 +207,7 @@ - + Details True True @@ -517,8 +532,8 @@ False end - - button + + Delete True True True @@ -527,14 +542,16 @@ True True 0 + True - - button + + Edit True True True + True @@ -543,11 +560,12 @@ - - button + + Close True True True + True @@ -787,6 +805,7 @@ True True + adj_number 1 @@ -797,6 +816,7 @@ True True + adj_weight 2 @@ -808,6 +828,7 @@ True True + adj_price 2 @@ -861,11 +882,12 @@ False end - + Save True True True + True @@ -874,7 +896,7 @@ - + Cancel True True diff --git a/yms/ui/maintenance.ui b/yms/ui/maintenance.ui index 17ce13d..db09424 100644 --- a/yms/ui/maintenance.ui +++ b/yms/ui/maintenance.ui @@ -144,11 +144,12 @@ False end - + New True True True + True @@ -157,11 +158,12 @@ - + Edit True True True + True @@ -170,11 +172,12 @@ - - Delete + + Details True True True + True @@ -195,5 +198,225 @@ page0 + + + True + False + vertical + + + True + False + label + + + False + True + 0 + + + + + + True + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + True + 1 + + + + + True + False + end + + + Delete + True + True + True + + + + True + True + 0 + + + + + Edit + True + True + True + + + + True + True + 1 + + + + + Close + True + True + True + + + + True + True + 2 + + + + + False + True + 2 + + + + + page1 + page1 + 1 + + + + + True + False + vertical + + + True + False + label + + + False + True + 0 + + + + + + True + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + 1 + + + + + True + False + end + + + Save + True + True + True + + + + True + True + 1 + + + + + Cancel + True + True + True + + + + True + True + 2 + + + + + False + True + 2 + + + + + page2 + page2 + 2 + + diff --git a/yms/ui/projects.ui b/yms/ui/projects.ui index 8bc2260..93f5fef 100644 --- a/yms/ui/projects.ui +++ b/yms/ui/projects.ui @@ -216,5 +216,224 @@ page0 + + + True + False + vertical + + + True + False + label + + + False + True + 0 + + + + + + True + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + True + 1 + + + + + True + False + end + + + Delete + True + True + True + + + True + True + 0 + True + + + + + Edit + True + True + True + + + True + True + 1 + + + + + Close + True + True + True + + + True + True + 2 + + + + + False + True + 2 + + + + + page1 + page1 + 1 + + + + + True + False + vertical + + + True + False + label + + + False + True + 0 + + + + + + True + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + True + 1 + + + + + True + False + end + + + + + + Save + True + True + True + + + True + True + 1 + + + + + Cancel + True + True + True + + + True + True + 2 + + + + + False + True + 2 + + + + + page2 + page2 + 2 + + diff --git a/yms/ui/provisions.ui b/yms/ui/provisions.ui index 12fbcb5..f1b36b6 100644 --- a/yms/ui/provisions.ui +++ b/yms/ui/provisions.ui @@ -151,11 +151,12 @@ False end - + New True True True + True @@ -164,11 +165,12 @@ - + Edit True True True + True @@ -177,11 +179,12 @@ - - Delete + + Details True True True + True @@ -452,6 +455,7 @@ True True True + True @@ -465,6 +469,7 @@ True True True + True @@ -745,7 +750,7 @@ - + Edit True True diff --git a/yms/ui/status.ui b/yms/ui/status.ui index 0f256e2..2a1bf56 100644 --- a/yms/ui/status.ui +++ b/yms/ui/status.ui @@ -42,6 +42,17 @@ True False vertical + + + True + False + + + False + True + 0 + + True @@ -57,15 +68,12 @@ thread in "Segeln Forum" True True - 0 + 1 - - - diff --git a/yms/ui/storage.ui b/yms/ui/storage.ui new file mode 100644 index 0000000..39c19a7 --- /dev/null +++ b/yms/ui/storage.ui @@ -0,0 +1,762 @@ + + + + + + 90 + 1 + 10 + + + 100 + 1 + 10 + + + 99999 + 10 + 100 + + + 99999 + 10 + 100 + + + 99999 + 10 + 100 + + + 9999 + 10 + 100 + + + 9999 + 10 + 100 + + + 9999 + 10 + 100 + + + True + False + 8 + + + True + False + vertical + + + True + True + + + + True + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + False + Filter Storage + + + + + False + True + 0 + + + + + True + True + in + + + True + True + + + + + + + + True + True + 1 + + + + + True + False + end + + + New + True + True + True + + + + True + True + 0 + + + + + Edit + True + True + True + + + + True + True + 1 + + + + + Details + True + True + True + + + + True + True + 2 + + + + + False + True + 2 + + + + + page0 + page0 + + + + + True + False + vertical + + + True + False + Storage Detais + + + + + + False + True + 0 + + + + + + True + False + + + True + False + Name + + + 0 + 0 + + + + + True + False + Placeholder + + + 1 + 0 + + + + + True + False + Remarks + + + 0 + 1 + + + + + True + False + + + 1 + 1 + + + + + + + + + + + + + + + + + + + + True + True + 1 + + + + + True + False + end + + + Delete + True + True + True + + + + True + True + 0 + True + + + + + Edit + True + True + True + + + + True + True + 1 + + + + + Close + True + True + True + + + + True + True + 2 + + + + + False + True + 2 + + + + + page1 + page1 + 1 + + + + + True + False + vertical + + + True + False + Edit Storage + + + + + + False + True + 0 + + + + + + True + False + + + True + False + Name + + + 0 + 0 + + + + + True + False + Typ + + + 0 + 1 + + + + + True + False + Position, mm + + + 0 + 2 + + + + + True + False + 4 + 4 + X + + + 1 + 2 + + + + + True + False + 4 + 4 + Y + + + 3 + 2 + + + + + True + False + 4 + 4 + Z + + + 5 + 2 + + + + + True + True + 5 + 5 + adj_pos_x + True + + + 2 + 2 + + + + + True + True + 5 + 5 + adj_pos_y + True + + + 4 + 2 + + + + + True + True + 5 + 5 + adj_pos_z + True + + + 6 + 2 + + + + + True + True + + + 1 + 0 + 6 + + + + + True + False + + + 1 + 1 + 6 + + + + + True + False + Width, mm + + + 0 + 3 + + + + + True + False + 4 + 4 + WX + + + 1 + 3 + + + + + True + False + 4 + 4 + WY + + + 3 + 3 + + + + + True + False + 4 + 4 + WZ + + + 5 + 3 + + + + + True + True + 4 + 4 + 0 + adj_width_x + True + + + 2 + 3 + + + + + True + True + 4 + 4 + 0 + adj_width_y + True + + + 4 + 3 + + + + + True + True + 4 + 4 + 0 + adj_width_z + True + + + 6 + 3 + + + + + True + False + Angle + + + 0 + 4 + + + + + True + True + adj_angle + + + 2 + 4 + 2 + + + + + True + False + Capacity + + + 0 + 5 + + + + + True + True + adj_capacity + + + 2 + 5 + 2 + + + + + True + False + Remarks + + + 0 + 6 + + + + + True + True + in + + + True + True + + + + + 1 + 6 + 6 + + + + + True + False + + + 5 + 5 + 2 + + + + + True + False + Unit + + + 4 + 5 + + + + + + + + + + + + + + + + + + + + True + True + 1 + + + + + True + False + end + + + Save + True + True + True + + + + True + True + 0 + + + + + Cancel + True + True + True + + + + True + True + 2 + + + + + False + True + 2 + + + + + page2 + page2 + 2 + + + + diff --git a/yms/view/base.py b/yms/view/base.py index 08e8a9d..52b1eef 100644 --- a/yms/view/base.py +++ b/yms/view/base.py @@ -27,6 +27,33 @@ class BaseView(View): #self.topwidget = builder.get_object("topobject") #gtkutils.init_named_controls(self, builder) + # company types + self.db.cur.execute("SELECT ddval, ddtext FROM dropdown WHERE ddid=2 ORDER BY ddval") + self.comptype = dict(self.db.cur.fetchall()) + combobox.load_from_dict(self.combo['flt_type'], {-2: _("─── all ───")} | self.comptype, -1) + + # 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(): + self.lst_companies.append((row[0], row[1], self.comptype[row[2]], row[3])) + treeview.add_column(self.tree['companies'], _('ID'), 0) + treeview.add_column(self.tree['companies'], _('Name'), 1) + treeview.add_column(self.tree['companies'], _('Type'), 2) + treeview.add_column(self.tree['companies'], _('Remarks'), 3) + self.tree['companies'].set_model(self.lst_companies) + + # combos + roles = {'captain': 'Captain', 'helmsman': 'Helmsman', 'sailor': 'Sailor'} + combobox.load_from_dict(self.combo['user_role'], roles) + langs = {'de': 'Deutsch', 'en': 'English'} + combobox.load_from_dict(self.combo['user_lang'], langs) + + # shipyard + self.db.cur.execute("SELECT compid, compname FROM company WHERE comptype=3 ORDER BY compname") + shipyards = dict(self.db.cur.fetchall()) + combobox.load_from_dict(self.combo['shipyard'], {-1: _("─── none ───")} | shipyards) + # get current vessel data self.db.cur.execute("SELECT valint FROM settings WHERE userid=0 AND sno=1") row = self.db.cur.fetchone() @@ -38,11 +65,20 @@ class BaseView(View): else: self.context.vessel.vid = row[0] + # default storage for current vessel + sql = "SELECT sid, sname FROM storage WHERE stype=0 AND vid=%s ORDER BY sname" + self.db.cur.execute(sql, (self.context.vessel.vid,)) + storages = dict(self.db.cur.fetchall()) + combobox.load_from_dict(self.combo['storage'], {-1: _("─── none ───")} | storages) + # get list of vessels vessellist = {} self.db.dcur.execute("SELECT vid, vesselname, model FROM vessel ORDER BY vid") for row in self.db.dcur.fetchall(): - vessellist[row['vid']] = row['vesselname'] + " - " + row['model'] + vessellist[row['vid']] = ( + row['vesselname'] if row['model'] is None + else row['vesselname'] + " - " + row['model'] + ) combobox.load_from_dict(self.combo['vessel'], vessellist, self.context.vessel.vid) # vessel load triggered from combobox init @@ -73,39 +109,6 @@ class BaseView(View): treeview.add_column(self.tree['ddlists'], _('Records'), 2) self.tree['ddlists'].set_model(self.lst_lists) - # company types - self.db.cur.execute("SELECT ddval, ddtext FROM dropdown WHERE ddid=2 ORDER BY ddval") - self.comptype = dict(self.db.cur.fetchall()) - combobox.load_from_dict(self.combo['flt_type'], {-1: _("─── all ───")} | self.comptype, -1) - - # 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(): - self.lst_companies.append((row[0], row[1], self.comptype[row[2]], row[3])) - treeview.add_column(self.tree['companies'], _('ID'), 0) - treeview.add_column(self.tree['companies'], _('Name'), 1) - treeview.add_column(self.tree['companies'], _('Type'), 2) - treeview.add_column(self.tree['companies'], _('Remarks'), 3) - self.tree['companies'].set_model(self.lst_companies) - - # combos - roles = {'captain': 'Captain', 'helmsman': 'Helmsman', 'sailor': 'Sailor'} - combobox.load_from_dict(self.combo['user_role'], roles) - langs = {'de': 'Deutsch', 'en': 'English'} - combobox.load_from_dict(self.combo['user_lang'], langs) - - # shipyard - self.db.cur.execute("SELECT compid, compname FROM company WHERE comptype=3 ORDER BY compname") - shipyards = dict(self.db.cur.fetchall()) - combobox.load_from_dict(self.combo['shipyard'], shipyards) - - # default storage - self.lst_storage_dfl = Gtk.ListStore(int, str) - self.db.cur.execute("SELECT sid, sname FROM storage WHERE stype=0 ORDER BY sname") - storages = dict(self.db.cur.fetchall()) - combobox.load_from_dict(self.combo['storage'], storages) - # load shape of vessel if available if self.context.vessel.vid > 0: self.db.cur.execute("SELECT shapefile FROM vessel WHERE vid=%s", (self.context.vessel.vid, )) @@ -125,23 +128,50 @@ class BaseView(View): # WIP generic remarks handling self.text['vessel_remarks'].set_size_request(200, 70) + def load_dropdowns(self): + # non static dropdown (re-)load feature + # default storage for current vessel + sql = "SELECT sid, sname FROM storage WHERE stype=0 AND vid=%s ORDER BY sname" + self.db.cur.execute(sql, (self.context.vessel.vid,)) + storages = dict(self.db.cur.fetchall()) + combobox.refresh_dict(self.combo['storage'], {-1: _("─── none ───")} | storages) + def on_cmb_vessel_changed(self, widget): self.context.vessel.load(combobox.get_list_value(widget)) - print(self.context.vessel) sql = ("UPDATE settings SET valint=%s WHERE userid=0 AND sno=1") self.db.cur.execute(sql, (self.context.vessel.vid,)) self.db.conn.commit() + # Refresh dependent data + self.load_dropdowns() # Show data - self.entry['vesselname'].set_text(self.context.vessel.vesselname) - self.entry['model'].set_text(self.context.vessel.model) - self.text['vessel_remarks'].get_buffer().set_text(self.context.vessel.remarks or '') - self.spin['loa'].set_value(9.80) + self.display_vessel(self.context.vessel) def on_but_vessel_add_clicked(self, widget): - print("Add vessel") + answer = gtkutils.questionbox( + _("Add new vessel.\n" + "Are you sure?" + ), title="YMS") + if answer == False: + return + self.context.vessel.create() def on_but_vessel_save_clicked(self, widget): print("Save vessel") + vessel = self.context.vessel + vessel.vesselname = self.entry['vesselname'].get_text() + vessel.model = self.entry['model'].get_text() + vessel.year_built = self.spin['year_built'].get_value_as_int() + vessel.loa = self.spin['loa'].get_value() + vessel.lwl = self.spin['lwl'].get_value() + vessel.beam = self.spin['beam'].get_value() + vessel.draught = self.spin['draught'].get_value() + vessel.draught_min = self.spin['draught_min'].get_value() + vessel.displacement = self.spin['displacement'].get_value_as_int() + vessel.ballast = self.spin['ballast'].get_value_as_int() + + txtbuf = self.text['vessel_remarks'].get_buffer() + vessel.remarks = txtbuf.get_text(txtbuf.get_start_iter(), txtbuf.get_end_iter(), True) + vessel.save() def on_but_comp_new_clicked(self, widget): print("New company") @@ -158,20 +188,52 @@ class BaseView(View): def on_but_comp_cancel_clicked(self, widget): pass - def user_display(self): - self.entry['user_login'].set_text(self.context.user.login) - self.entry['user_displayname'].set_text(self.context.user.displayname) - combobox.activate_row(self.combo['user_role'], self.context.user.role) - combobox.activate_row(self.combo['user_lang'], self.context.user.language) - self.check['user_locked'].set_active('locked' in self.context.user.flags) - self.check['user_deleted'].set_active('deleted' in self.context.user.flags) + def display_vessel(self, vessel): + print("Display vessel") + self.entry['vesselname'].set_text(vessel.vesselname) + self.entry['model'].set_text(vessel.model or '') + self.spin['year_built'].set_value(vessel.year_built or 0) + self.spin['loa'].set_value(vessel.loa or 0) + self.spin['lwl'].set_value(vessel.lwl or 0) + self.spin['beam'].set_value(vessel.beam or 0) + self.spin['draught'].set_value(vessel.draught or 0) + self.spin['draught_min'].set_value(vessel.draught_min or 0) + self.spin['displacement'].set_value(vessel.displacement or 0) + self.spin['ballast'].set_value(vessel.ballast or 0) + self.text['vessel_remarks'].get_buffer().set_text(vessel.remarks or '') + combobox.activate_row(self.combo['shipyard'], vessel.shipyard or -1) + combobox.activate_row(self.combo['storage'], vessel.sid_default or -1) + + def display_user(self, user): + self.entry['user_login'].set_text(user.login) + self.entry['user_displayname'].set_text(user.displayname) + combobox.activate_row(self.combo['user_role'], user.role) + combobox.activate_row(self.combo['user_lang'], user.language) + self.check['user_locked'].set_active('locked' in user.flags) + self.check['user_deleted'].set_active('deleted' in user.flags) self.entry['user_pass'].set_text('') + 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 on_tvw_user_row_activated(self, widget, path, column): # load selected user self.context.user.user_id = treeview.get_value(widget, 0) self.context.user.load() - self.user_display() + self.display_user(self.context.user) def on_but_user_new_clicked(self, widget): # get first free user id and create a new record with name "user" @@ -193,7 +255,7 @@ class BaseView(View): # TODO Select some other user from new list selection self.context.user.user_id = treeview.get_value(self.tree['user']) self.context.user.load() - self.user_display() + self.display_user(self.context.user) def on_but_user_newpass_clicked(self, widget): self.entry['user_pass'].set_text(self.context.user.genpass()) diff --git a/yms/view/documents.py b/yms/view/documents.py index 7964bf9..55f7199 100644 --- a/yms/view/documents.py +++ b/yms/view/documents.py @@ -5,15 +5,57 @@ import gi gi.require_version("Gtk", "3.0") from gi.repository import GLib, Gtk, Gdk +from .view import View from yms import gtkutils, combobox, treeview +from yms.model import document -class DocumentsView: +class DocumentsView(View): def __init__(self, context): - self.title = _("Documents") - builder = Gtk.Builder() - builder.set_translation_domain(context.textdomain) - builder.add_from_file(os.path.join(context.ui_path, "documents.ui")) - builder.connect_signals(self) - self.topwidget = builder.get_object("topobject") - gtkutils.init_named_controls(self, builder) + super().__init__(context, _("Documents"), "documents.ui") + + self.doc = document.Document(context.db) # current record + self.newrecord = False + + self.lst_documents = Gtk.ListStore(int, str, str, str, int) + sql = ( + "SELECT d.docid, d.doctype, d.filename, d.title, COUNT(r.drid) AS refcount " + "FROM document AS d LEFT OUTER JOIN docref AS r USING (docid) " + "GROUP BY d.docid, d.doctype, d.filename, d.title " + "ORDER BY d.docid" + ) + self.db.cur.execute(sql) + for row in self.db.cur.fetchall(): + self.lst_documents.append(row) + + treeview.add_column(self.tree['documents'], _('ID'), 0) + treeview.add_column(self.tree['documents'], _('Type'), 1) + treeview.add_column(self.tree['documents'], _('Filename'), 2) + treeview.add_column(self.tree['documents'], _('Title'), 3) + treeview.add_column(self.tree['documents'], _('References'), 3) + self.tree['documents'].set_model(self.lst_documents) + + # buttons on list page + def on_but_new_clicked(self, widget): + self.topwidget.set_visible_child(self.box['doc_edit']) + + def on_but_edit_clicked(self, widget): + self.topwidget.set_visible_child(self.box['doc_edit']) + + def on_but_detail_clicked(self, widget): + self.topwidget.set_visible_child(self.box['doc_detail']) + + # buttons on detail page + # edit2 uses edit callback + def on_but_close_clicked(self, widget): + self.topwidget.set_visible_child(self.box['documents']) + + def on_but_delete_clicked(self, widget): + self.topwidget.set_visible_child(self.box['documents']) + + # 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['documents']) diff --git a/yms/view/equipment.py b/yms/view/equipment.py index 75130ad..78c69e2 100644 --- a/yms/view/equipment.py +++ b/yms/view/equipment.py @@ -5,39 +5,60 @@ import gi gi.require_version("Gtk", "3.0") from gi.repository import GLib, Gtk, Gdk +from .view import View from yms import gtkutils, combobox, treeview +from yms.model import equipment -class EquipmentView: +class EquipmentView(View): def __init__(self, context): - self.title = _("Equipment") - builder = Gtk.Builder() - builder.set_translation_domain(context.textdomain) - builder.add_from_file(os.path.join(context.ui_path, "equipment.ui")) - builder.connect_signals(self) - self.topwidget = builder.get_object("stk_equipment") - gtkutils.init_named_controls(self, builder) + super().__init__(context, _("Equipment"), "equipment.ui") + self.equip = equipment.Equipment(context.db) # current record + self.newrecord = False + + self.lst_equipment = Gtk.ListStore(int, str, str, str, str, str, str) + sql = ( + "SELECT e.eid, e.ename, c.compname, e.model, e.serial, " + "DATE_FORMAT(e.purchdate, '{}'), e.remarks " + "FROM equipment AS e LEFT OUTER JOIN company AS c ON (e.manufacturer=c.compid) " + "WHERE e.vid=%s " + "ORDER BY e.ename" + ).format("%%d.%%m.%%Y") # TODO format from settings via mapping + self.db.cur.execute(sql, (context.vessel.vid,)) + for row in self.db.cur.fetchall(): + self.lst_equipment.append(row) + + treeview.add_column(self.tree['equipment'], _('ID'), 0) + treeview.add_column(self.tree['equipment'], _('Name'), 1) + treeview.add_column(self.tree['equipment'], _('Manufacturer'), 2) + treeview.add_column(self.tree['equipment'], _('Model'), 3) + treeview.add_column(self.tree['equipment'], _('Serial'), 4) + treeview.add_column(self.tree['equipment'], _('Age'), 5) + treeview.add_column(self.tree['equipment'], _('Remarks'), 6) + self.tree['equipment'].set_model(self.lst_equipment) + + # buttons on list page def on_but_new_clicked(self, widget): self.topwidget.set_visible_child(self.box['equip_edit']) + def on_but_edit_clicked(self, widget): + self.topwidget.set_visible_child(self.box['equip_edit']) + def on_but_detail_clicked(self, widget): self.topwidget.set_visible_child(self.box['equip_detail']) - def on_but_edit_clicked(self, widget): - self.topwidget.set_visible_child(self.box['equip_edit']) - - def on_but_edit2_clicked(self, widget): - self.topwidget.set_visible_child(self.box['equip_edit']) - + # buttons on detail page + # edit2 uses edit callback def on_but_close_clicked(self, widget): - self.topwidget.set_visible_child(self.box['equip_detail']) - - def on_but_save_clicked(self, widget): - pass + self.topwidget.set_visible_child(self.box['equipment']) def on_but_delete_clicked(self, widget): self.topwidget.set_visible_child(self.box['equipment']) + # 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['equipment']) diff --git a/yms/view/inventory.py b/yms/view/inventory.py index efbfc3c..b925662 100644 --- a/yms/view/inventory.py +++ b/yms/view/inventory.py @@ -5,15 +5,63 @@ import gi gi.require_version("Gtk", "3.0") from gi.repository import GLib, Gtk, Gdk +from .view import View from yms import gtkutils, combobox, treeview +from yms.model import inventory -class InventoryView: +class InventoryView(View): def __init__(self, context): - self.title = _("Inventory") - builder = Gtk.Builder() - builder.set_translation_domain(context.textdomain) - builder.add_from_file(os.path.join(context.ui_path, "inventory.ui")) - builder.connect_signals(self) - self.topwidget = builder.get_object("topobject") - gtkutils.init_named_controls(self, builder) + super().__init__(context, _("Inventory"), "inventory.ui") + + self.inv = inventory.Inventory(context.db) # current record + self.newrecord = False + + # Inventory gets vessel assignment via + # - storage direct + # - or via box which is assigned to a storage + self.lst_inventory = Gtk.ListStore(int, str, str, int, str, str) + sql = ( + "SELECT i.invid, i.invname, s.sname AS container, i.number, i.invcond, i.remarks " + "FROM inventory AS i JOIN storage AS s ON (i.conttype='storage' AND i.sid=s.sid) " + "WHERE s.vid=%s " + "UNION SELECT i.invid, i.invname, b.label AS container, i.number, i.invcond, i.remarks " + "FROM inventory AS i JOIN box AS b ON (i.conttype='box' AND i.boxid=b.boxid) JOIN storage AS s ON (b.sid=s.sid) " + "WHERE s.vid=%s" + ) + self.db.cur.execute(sql, (context.vessel.vid, context.vessel.vid)) + for row in self.db.cur.fetchall(): + self.lst_inventory.append(row) + + treeview.add_column(self.tree['inventory'], _('ID'), 0) + treeview.add_column(self.tree['inventory'], _('Name'), 1) + treeview.add_column(self.tree['inventory'], _('Container'), 2) + treeview.add_column(self.tree['inventory'], _('Number'), 3) + treeview.add_column(self.tree['inventory'], _('Condition'), 4) + treeview.add_column(self.tree['inventory'], _('Remarks'), 5) + self.tree['inventory'].set_model(self.lst_inventory) + + # buttons on list page + def on_but_new_clicked(self, widget): + self.topwidget.set_visible_child(self.box['inv_edit']) + + def on_but_edit_clicked(self, widget): + self.topwidget.set_visible_child(self.box['inv_edit']) + + def on_but_detail_clicked(self, widget): + self.topwidget.set_visible_child(self.box['inv_detail']) + + # buttons on detail page + # edit2 uses edit callback + def on_but_close_clicked(self, widget): + self.topwidget.set_visible_child(self.box['inventory']) + + def on_but_delete_clicked(self, widget): + self.topwidget.set_visible_child(self.box['inventory']) + + # 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['inventory']) diff --git a/yms/view/maintenance.py b/yms/view/maintenance.py index ad9dada..5a0248f 100644 --- a/yms/view/maintenance.py +++ b/yms/view/maintenance.py @@ -5,15 +5,56 @@ import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk +from .view import View from yms import gtkutils, combobox, treeview +from yms.model import maintenance -class MaintenanceView: +class MaintenanceView(View): def __init__(self, context): - self.title = _("Maintenance") - builder = Gtk.Builder() - builder.set_translation_domain(context.textdomain) - builder.add_from_file(os.path.join(context.ui_path, "maintenance.ui")) - builder.connect_signals(self) - self.topwidget = builder.get_object("topobject") - gtkutils.init_named_controls(self, builder) + super().__init__(context, _("Maintenance"), "maintenance.ui") + + self.maint = maintenance.Maintenance(context.db) # current record + self.newrecord = False + + self.lst_maintenance = Gtk.ListStore(int, str, str, str) + sql = ( + "SELECT m.maintid, m.activities, e.ename, m.remarks " + "FROM maintenance AS m LEFT OUTER JOIN equipment AS e USING (eid) " + "WHERE m.vid=%s " + "ORDER BY m.maintid" + ) + self.db.cur.execute(sql, (context.vessel.vid,)) + for row in self.db.cur.fetchall(): + self.lst_maintenance.append(row) + + treeview.add_column(self.tree['maintenance'], _('ID'), 0) + treeview.add_column(self.tree['maintenance'], _('Activities'), 1) + treeview.add_column(self.tree['maintenance'], _('Equipment'), 2) + treeview.add_column(self.tree['maintenance'], _('Remarks'), 3) + self.tree['maintenance'].set_model(self.lst_maintenance) + + # buttons on list page + def on_but_new_clicked(self, widget): + self.topwidget.set_visible_child(self.box['maint_edit']) + + def on_but_edit_clicked(self, widget): + 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']) + + # buttons on detail page + # edit2 uses edit callback + def on_but_close_clicked(self, widget): + self.topwidget.set_visible_child(self.box['maintenance']) + + def on_but_delete_clicked(self, widget): + self.topwidget.set_visible_child(self.box['maintenance']) + + # 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['maintenance']) diff --git a/yms/view/projects.py b/yms/view/projects.py index 6ea755f..7a74798 100644 --- a/yms/view/projects.py +++ b/yms/view/projects.py @@ -5,15 +5,66 @@ import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk +from .view import View from yms import gtkutils, combobox, treeview +from yms.model import project -class ProjectsView: +class ProjectsView(View): def __init__(self, context): - self.title = _("Projects") - builder = Gtk.Builder() - builder.set_translation_domain(context.textdomain) - builder.add_from_file(os.path.join(context.ui_path, "projects.ui")) - builder.connect_signals(self) - self.topwidget = builder.get_object("topobject") - gtkutils.init_named_controls(self, builder) + super().__init__(context, _("Projects"), "projects.ui") + + self.project = project.Project(context.db) # current record + self.newrecord = False + + self.lst_projects = Gtk.ListStore(int, str, str, int, str, str) + sql = ( + "SELECT projid, projname, startdate, duration, projstate, remarks " + "FROM project " + "WHERE vid=%s " + "ORDER BY projid" + ) + self.db.dcur.execute(sql, (context.vessel.vid,)) + for row in self.db.dcur.fetchall(): + data = ( + row['projid'], + row['projname'], + self.format_date(row['startdate']), + row['duration'], + row['projstate'], + row['remarks'] + ) + self.lst_projects.append(data) + + treeview.add_column(self.tree['projects'], _('ID'), 0) + treeview.add_column(self.tree['projects'], _('Name'), 1) + treeview.add_column(self.tree['projects'], _('Start date'), 2) + treeview.add_column(self.tree['projects'], _('Duration'), 3) + treeview.add_column(self.tree['projects'], _('Status'), 4) + treeview.add_column(self.tree['projects'], _('Remarks'), 5) + self.tree['projects'].set_model(self.lst_projects) + + # buttons on list page + def on_but_new_clicked(self, widget): + self.topwidget.set_visible_child(self.box['proj_edit']) + + def on_but_edit_clicked(self, widget): + self.topwidget.set_visible_child(self.box['proj_edit']) + + def on_but_detail_clicked(self, widget): + self.topwidget.set_visible_child(self.box['proj_detail']) + + # buttons on detail page + # edit2 uses edit callback + def on_but_close_clicked(self, widget): + self.topwidget.set_visible_child(self.box['projects']) + + def on_but_delete_clicked(self, widget): + self.topwidget.set_visible_child(self.box['projects']) + + # 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['projects']) diff --git a/yms/view/provisions.py b/yms/view/provisions.py index 3a721e4..75169c4 100644 --- a/yms/view/provisions.py +++ b/yms/view/provisions.py @@ -5,15 +5,71 @@ import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk +from .view import View from yms import gtkutils, combobox, treeview +from yms.model import provision -class ProvisionsView: +class ProvisionsView(View): def __init__(self, context): - self.title = _("Provisions") - builder = Gtk.Builder() - builder.set_translation_domain(context.textdomain) - builder.add_from_file(os.path.join(context.ui_path, "provisions.ui")) - builder.connect_signals(self) - self.topwidget = builder.get_object("topobject") - gtkutils.init_named_controls(self, builder) + super().__init__(context, _("Provisions"), "provisions.ui") + + self.prov = provision.Provision(context.db) # current record + self.newrecord = False + + self.load_dropdown() + + self.lst_provisions = Gtk.ListStore(int, str, int, str, str, str) + 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" + ) + self.db.dcur.execute(sql, (context.vessel.vid,)) + for row in self.db.dcur.fetchall(): + data = ( + row['provid'], + row['provname'], + row['number'], + self.prov_unit[row['unit']], + self.format_date(row['storedate']), + self.format_date(row['shelflife']) + ) + self.lst_provisions.append(data) + + treeview.add_column(self.tree['provisions'], _('ID'), 0) + treeview.add_column(self.tree['provisions'], _('Description'), 1) + treeview.add_column(self.tree['provisions'], _('Number'), 2) + treeview.add_column(self.tree['provisions'], _('Unit'), 3) + treeview.add_column(self.tree['provisions'], _('Stored'), 4) + treeview.add_column(self.tree['provisions'], _('Best before'), 5) + self.tree['provisions'].set_model(self.lst_provisions) + + def load_dropdown(self): + self.db.cur.execute("SELECT ddval, ddtext FROM dropdown WHERE ddid=6 ORDER BY ddval") + self.prov_unit = dict(self.db.cur.fetchall()) + + # buttons on list page + def on_but_new_clicked(self, widget): + self.topwidget.set_visible_child(self.box['prov_edit']) + + def on_but_edit_clicked(self, widget): + self.topwidget.set_visible_child(self.box['prov_edit']) + + def on_but_detail_clicked(self, widget): + self.topwidget.set_visible_child(self.box['prov_detail']) + + # buttons on detail page + # edit2 uses edit callback + def on_but_close_clicked(self, widget): + self.topwidget.set_visible_child(self.box['provisions']) + + def on_but_delete_clicked(self, widget): + self.topwidget.set_visible_child(self.box['provisions']) + + # 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['provisions']) diff --git a/yms/view/status.py b/yms/view/status.py index 108bcd7..9e9dacd 100644 --- a/yms/view/status.py +++ b/yms/view/status.py @@ -20,6 +20,9 @@ class StatusView: self.topwidget = builder.get_object("topobject") gtkutils.init_named_controls(self, builder) + # Generic information + self.label['dbinfo'].set_text("Database: {}".format(context.cfg['db'])) + # Load table status info self.lst_tables = Gtk.ListStore(str, int) for row in self.get_table_counts(): diff --git a/yms/view/storage.py b/yms/view/storage.py new file mode 100644 index 0000000..a9639fa --- /dev/null +++ b/yms/view/storage.py @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: WTFPL + +import os +import gi +gi.require_version("Gtk", "3.0") +from gi.repository import GLib, Gtk, Gdk + +from .view import View +from yms import gtkutils, combobox, treeview +from yms.model import storage + +class StorageView(View): + + def __init__(self, context): + super().__init__(context, _("Storage"), "storage.ui") + + self.storage = storage.Storage(context.db) # current record + self.newrecord = False + + self.lst_storage = Gtk.ListStore(int, str, str, str) + sql = ( + "SELECT sid, sname, CONCAT(x, ',', y, ',', z) AS position, remarks " + "FROM storage " + "WHERE vid=%s " + "ORDER BY sname" + ) + self.db.cur.execute(sql, (context.vessel.vid,)) + for row in self.db.cur.fetchall(): + self.lst_storage.append(row) + + treeview.add_column(self.tree['storage'], _('ID'), 0) + treeview.add_column(self.tree['storage'], _('Name'), 1) + treeview.add_column(self.tree['storage'], _('Position'), 2) + treeview.add_column(self.tree['storage'], _('Remarks'), 3) + self.tree['storage'].set_model(self.lst_storage) + + + def load_list(self): + pass + + def display_record(self): + self.label['name'].set_text(self.storage.sname) + self.label['remarks'].set_text(self.storage.remarks or '') + + def edit_record(self): + self.entry['sname'].set_text(self.storage.sname) + self.spin['x'].set_value(self.storage.x) + self.spin['y'].set_value(self.storage.y) + self.spin['z'].set_value(self.storage.z) + self.text['remarks'].get_buffer().set_text(self.storage.remarks or '') + + # buttons on list page + def on_but_new_clicked(self, widget): + self.newrecord = True + self.label['title_edit'].set_text("Add new Storage") + self.topwidget.set_visible_child(self.box['stor_edit']) + + def on_but_edit_clicked(self, widget): + self.newrecord = False + self.label['title_edit'].set_text("Edit Storage") + sid = treeview.get_value(self.tree['storage'], 0) + self.storage.load(sid) + self.edit_record() + self.topwidget.set_visible_child(self.box['stor_edit']) + + def on_but_detail_clicked(self, widget): + sid = treeview.get_value(self.tree['storage'], 0) + self.storage.load(sid) + self.display_record() + self.topwidget.set_visible_child(self.box['stor_detail']) + + # buttons on detail page + # edit2 uses edit callback + def on_but_close_clicked(self, widget): + self.topwidget.set_visible_child(self.box['storage']) + + def on_but_delete_clicked(self, widget): + self.topwidget.set_visible_child(self.box['storage']) + self.newrecord = False + + # buttons on edit page + def on_but_save_clicked(self, widget): + print("save not implemented yet") + self.newrecord = False + + def on_but_cancel_clicked(self, widget): + self.topwidget.set_visible_child(self.box['storage']) + self.newrecord = False diff --git a/yms/view/view.py b/yms/view/view.py index 0b5637e..222e49c 100644 --- a/yms/view/view.py +++ b/yms/view/view.py @@ -8,10 +8,11 @@ SPDX-License-Identifier: WTFPL import os import gi gi.require_version("Gtk", "3.0") -from gi.repository import Gtk +from gi.repository import GLib, Gtk, Gdk from yms import gtkutils class View: + def __init__(self, context, title, ui_file): self.context = context self.db = context.db @@ -25,6 +26,11 @@ class View: self.topwidget = builder.get_object("topobject") gtkutils.init_named_controls(self, builder) + def format_date(self, dateval): + if dateval is None: + return '' + return dateval.strftime(self.context.datefmt) + def on_textview_keypress(self, widget, event): # Generic limit length function if event.state & Gdk.ModifierType.CONTROL_MASK: diff --git a/ymsgui.py b/ymsgui.py index 4b00bb3..6178c58 100755 --- a/ymsgui.py +++ b/ymsgui.py @@ -14,7 +14,7 @@ Configuration file located at ~/.config/ymsgui.conf: pass = topsecret [Documents] - basepath = /var/local/yms + basepath = /var/local/lib/yms [Data] shapedir = /usr/local/share/yms/shapes @@ -39,6 +39,7 @@ from yms.model import user from yms.model import vessel from yms.view.base import BaseView +from yms.view.storage import StorageView from yms.view.equipment import EquipmentView from yms.view.inventory import InventoryView from yms.view.provisions import ProvisionsView @@ -57,6 +58,15 @@ class AppContext: 'docpath': '/var/local/yms', 'shapedir': '/usr/local/share/yms/shapes' } + + # mapping between PHP and Python + datefmt_map = { + 'Y-m-d': '%Y.%m.%d', + 'Y/m/d': '%Y/%m/%d', + 'd.m.Y': '%d.%m.%Y', + 'd/m/Y': '%d/%m/%Y', + 'm-d-Y': '%m.%d.%Y' + } def __init__(self): self.db = None @@ -64,6 +74,7 @@ class AppContext: self.vessel = None self.ui_path = os.path.join(self.get_sharepath(), "yms", "ui") self.textdomain = "ymsgui" + self.datefmt = '%d.%m.%Y' def set_db(self, db): self.db = db @@ -71,6 +82,19 @@ class AppContext: def load(self): self.user = user.User(db, 0) self.vessel = vessel.Vessel(db) + # load date format from db settings + sql = "SELECT valstr FROM settings WHERE userid=0 AND sno=2" + self.db.cur.execute(sql) + row = self.db.cur.fetchone() + if row is not None: + try: + self.datefmt = self.datefmt_map[row[0]] + except KeyError: + # almost impossible case where db value is not in mapping + print("internal error: format mapping missinf") + else: + # perhaps create missing record here? + pass def get_sharepath(self): path = os.path.realpath(__file__) @@ -85,6 +109,7 @@ class Frontend: def __init__(self, context): self.modules = { "base": BaseView(context), + "storage": StorageView(context), "equipment": EquipmentView(context), "inventory": InventoryView(context), "provisions": ProvisionsView(context),