Work on native gui: list views for objects; set version to 0.2.2
This commit is contained in:
+10
-53
@@ -2,14 +2,11 @@
|
||||
|
||||
"""
|
||||
Spezial:
|
||||
Notebook mit Vessel, User, Lists, Company
|
||||
Notebook mit Vessel, User, Lists, Settings
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import gi
|
||||
gi.require_version("Gtk", "3.0")
|
||||
gi.require_version('Rsvg', '2.0')
|
||||
from gi.repository import GLib, Gtk, Gdk, Rsvg
|
||||
|
||||
from .view import View
|
||||
@@ -28,22 +25,6 @@ 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)
|
||||
@@ -118,6 +99,9 @@ class BaseView(View):
|
||||
treeview.add_column(self.tree['ddlists'], _('Records'), 2)
|
||||
self.tree['ddlists'].set_model(self.lst_lists)
|
||||
|
||||
# Settings date format selection list
|
||||
# self.context.datefmt_map
|
||||
|
||||
# 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, ))
|
||||
@@ -186,9 +170,7 @@ class BaseView(View):
|
||||
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.remarks = gtkutils.get_text_contents(self.text['vessel_remarks'])
|
||||
vessel.save()
|
||||
self.stack['vessel'].set_visible_child(self.box['vessel'])
|
||||
|
||||
@@ -198,20 +180,11 @@ class BaseView(View):
|
||||
def on_but_vessel_delete_clicked(self, widget):
|
||||
pass
|
||||
|
||||
def on_but_comp_new_clicked(self, widget):
|
||||
print("New company")
|
||||
|
||||
def on_but_comp_edit_clicked(self, widget):
|
||||
print("Edit company")
|
||||
|
||||
def on_but_comp_detail_clicked(self, widget):
|
||||
print("Company details")
|
||||
|
||||
def on_but_comp_save_clicked(self, widget):
|
||||
print("Save company")
|
||||
|
||||
def on_but_comp_cancel_clicked(self, widget):
|
||||
pass
|
||||
def on_but_settings_save_clicked(self, widget):
|
||||
print("Save settings")
|
||||
#self.entry['sys_currency']
|
||||
#self.spin['sys_max_width']
|
||||
#self.spin['sys_max_height']
|
||||
|
||||
def display_vessel(self, vessel):
|
||||
self.label['vesselname'].set_text(vessel.vesselname)
|
||||
@@ -242,22 +215,6 @@ class BaseView(View):
|
||||
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)
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# 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
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# SPDX-License-Identifier: WTFPL
|
||||
|
||||
import os
|
||||
import gi
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk
|
||||
|
||||
from .view import View
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
# 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 company
|
||||
|
||||
class CompaniesView(View):
|
||||
|
||||
def __init__(self, context):
|
||||
super().__init__(context, _("Companies"), "companies.ui")
|
||||
|
||||
self.comp = company.Company(context.db) # current record
|
||||
self.newrecord = False
|
||||
|
||||
# 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, -2)
|
||||
|
||||
# companied
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
# 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):
|
||||
self.topwidget.set_visible_child(self.box['comp_edit'])
|
||||
|
||||
def on_but_detail_clicked(self, widget):
|
||||
self.topwidget.set_visible_child(self.box['comp_detail'])
|
||||
|
||||
# buttons on detail page
|
||||
# edit2 uses edit callback
|
||||
def on_but_close_clicked(self, widget):
|
||||
self.topwidget.set_visible_child(self.box['companies'])
|
||||
|
||||
def on_but_delete_clicked(self, widget):
|
||||
self.topwidget.set_visible_child(self.box['companies'])
|
||||
|
||||
# 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['companies'])
|
||||
@@ -1,8 +1,6 @@
|
||||
# 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
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# 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
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# SPDX-License-Identifier: WTFPL
|
||||
|
||||
import os
|
||||
import gi
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk
|
||||
|
||||
from .view import View
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# 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
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# SPDX-License-Identifier: WTFPL
|
||||
|
||||
import os
|
||||
import gi
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk
|
||||
|
||||
from .view import View
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# SPDX-License-Identifier: WTFPL
|
||||
|
||||
import os
|
||||
import gi
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk
|
||||
|
||||
from .view import View
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# SPDX-License-Identifier: WTFPL
|
||||
|
||||
import os
|
||||
import gi
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk
|
||||
|
||||
from .view import View
|
||||
|
||||
+93
-3
@@ -1,10 +1,9 @@
|
||||
# SPDX-License-Identifier: WTFPL
|
||||
|
||||
import os
|
||||
import gi
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk
|
||||
import re
|
||||
from gi.repository import Gtk, Rsvg
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from yms import gtkutils, combobox, treeview
|
||||
|
||||
@@ -21,6 +20,7 @@ class StatusView:
|
||||
gtkutils.init_named_controls(self, builder)
|
||||
|
||||
# Generic information
|
||||
self.label['version'].set_text("YMS version {}".format(context.__version__))
|
||||
self.label['dbinfo'].set_text("Database: {} on {}".format(context.cfg['db'], context.cfg['host']))
|
||||
|
||||
# Load table status info
|
||||
@@ -42,6 +42,96 @@ class StatusView:
|
||||
contents = re.sub(r'(^\s*pass\s*=\s*).*$', r'\1********', contents, flags=re.MULTILINE)
|
||||
self.text ['config'].get_buffer().set_text(contents)
|
||||
|
||||
# data for svg deck plan
|
||||
self.svg = None
|
||||
self.svg_width = 0
|
||||
self.svg_height = 0
|
||||
self.svg_scale = 1.0
|
||||
self.svg_x = 0.0
|
||||
self.svg_y = 0.0
|
||||
self.svg_centerline_y = 0.0
|
||||
self.load_svg()
|
||||
|
||||
def load_svg(self):
|
||||
if not self.context.vessel.shapefile:
|
||||
print("No Shapefile defined for current vessel")
|
||||
return
|
||||
shapefile = os.path.join(self.context.cfg['shapedir'], self.context.vessel.shapefile)
|
||||
if not (os.path.isfile(shapefile) or os.access(shapefile, os.R_OK)):
|
||||
print(f"Shapefile '{shapefile}' not found or not readable")
|
||||
return
|
||||
try:
|
||||
self.svg = Rsvg.Handle.new_from_file(shapefile)
|
||||
success, width, height = self.svg.get_intrinsic_size_in_pixels()
|
||||
if not success:
|
||||
raise RuntimeError("SVG has no pixelsize")
|
||||
self.svg_width = width
|
||||
self.svg_height = height
|
||||
print(f"SVG: {self.svg_width} x {self.svg_height}")
|
||||
self.area['status'].queue_draw()
|
||||
except Exception as e:
|
||||
print("Error trying to load svg deck plan:", e)
|
||||
return
|
||||
# try to detect centerline
|
||||
self.svg_centerline_y = None
|
||||
try:
|
||||
tree = ET.parse(shapefile)
|
||||
except Exception as e:
|
||||
print("Error reading centerline from svg:", e)
|
||||
self.svg_centerline_y = self.svg_height / 2
|
||||
return
|
||||
root = tree.getroot()
|
||||
found = False
|
||||
for element in root.iter():
|
||||
if element.get("id") == "centerline":
|
||||
found = True
|
||||
print("\n--- centerline gefunden ---")
|
||||
print("Tag:", element.tag)
|
||||
print("Attribute:", element.attrib)
|
||||
y1 = element.get("y1")
|
||||
y2 = element.get("y2")
|
||||
if y1 is not None and y2 is not None:
|
||||
y1 = float(y1)
|
||||
y2 = float(y2)
|
||||
if not math.isclose(y1, y2, abs_tol=0.001):
|
||||
raise ValueError(f"centerline not horizontal: y1={y1}, y2={y2}")
|
||||
# calc arithmetic mean as fallback
|
||||
self.centerline_y = (y1 + y2) / 2
|
||||
else:
|
||||
self.centerline_y = y1
|
||||
print(f"centerline: SVG Y = {self.centerline_y}")
|
||||
return
|
||||
if not found:
|
||||
print("No centerline with id='centerline' found!")
|
||||
|
||||
def on_drw_status_draw(self, area, cr):
|
||||
cr.set_source_rgb(0.92, 0.97, 1.0)
|
||||
cr.paint()
|
||||
|
||||
allocation = area.get_allocation()
|
||||
scale_x = allocation.width / self.svg_width
|
||||
scale_y = allocation.height / self.svg_height
|
||||
self.svg_scale = min(scale_x, scale_y)
|
||||
|
||||
width = self.svg_width * self.svg_scale
|
||||
height = self.svg_height * self.svg_scale
|
||||
|
||||
self.svg_x = (allocation.width - width) / 2
|
||||
self.svg_y = (allocation.height - height) / 2
|
||||
|
||||
cr.save()
|
||||
cr.translate(self.svg_x, self.svg_y)
|
||||
cr.scale(self.svg_scale, self.svg_scale)
|
||||
viewport = Rsvg.Rectangle()
|
||||
viewport.x = 0
|
||||
viewport.y = 0
|
||||
viewport.width = self.svg_width
|
||||
viewport.height = self.svg_height
|
||||
self.svg.render_document(cr, viewport)
|
||||
cr.restore()
|
||||
|
||||
return False
|
||||
|
||||
def get_table_counts(self):
|
||||
# Detect all tables in database
|
||||
sql= ("SELECT table_name "
|
||||
|
||||
+65
-16
@@ -1,8 +1,6 @@
|
||||
# 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
|
||||
@@ -15,19 +13,13 @@ class StorageView(View):
|
||||
def __init__(self, context):
|
||||
super().__init__(context, _("Storage"), "storage.ui")
|
||||
|
||||
self.context = context
|
||||
|
||||
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)
|
||||
self.load_list()
|
||||
|
||||
treeview.add_column(self.tree['storage'], _('ID'), 0)
|
||||
treeview.add_column(self.tree['storage'], _('Name'), 1)
|
||||
@@ -35,18 +27,34 @@ 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)
|
||||
#combodict = self.context.lookup.dropdown(Dropdown.STORAGE_TYPE)
|
||||
#combobox.load_from_dict(self.combo['type'], combodict)
|
||||
|
||||
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)
|
||||
|
||||
def load_list(self):
|
||||
def add_row(self):
|
||||
pass
|
||||
|
||||
def refresh_row(self):
|
||||
pass
|
||||
|
||||
def load_list(self):
|
||||
self.lst_storage.clear()
|
||||
sql = (
|
||||
"SELECT sid, sname, CONCAT(x, ',', y, ',', z) AS position, remarks "
|
||||
"FROM storage "
|
||||
"WHERE vid=%s "
|
||||
"ORDER BY sname"
|
||||
)
|
||||
self.db.cur.execute(sql, (self.context.vessel.vid,))
|
||||
for row in self.db.cur.fetchall():
|
||||
self.lst_storage.append(row)
|
||||
|
||||
def display_record(self):
|
||||
self.label['name'].set_text(self.storage.sname)
|
||||
self.label['remarks'].set_text(self.storage.remarks or '')
|
||||
@@ -56,12 +64,36 @@ class StorageView(View):
|
||||
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.spin['wx'].set_value(self.storage.wx)
|
||||
self.spin['wy'].set_value(self.storage.wy)
|
||||
self.spin['wz'].set_value(self.storage.wz)
|
||||
self.spin['angle'].set_value(self.storage.angle)
|
||||
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)
|
||||
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
|
||||
self.label['title_edit'].set_text("Add new Storage")
|
||||
self.clear_record()
|
||||
self.storage.vid = self.context.vessel.vid
|
||||
self.topwidget.set_visible_child(self.box['stor_edit'])
|
||||
|
||||
def on_but_edit_clicked(self, widget):
|
||||
@@ -91,12 +123,29 @@ class StorageView(View):
|
||||
|
||||
# buttons on edit page
|
||||
def on_but_save_clicked(self, widget):
|
||||
self.newrecord = False
|
||||
# check mandatory fields
|
||||
sname = self.entry['sname'].get_text().strip()
|
||||
if not sname:
|
||||
# TODO error marker
|
||||
return
|
||||
# here be dragons
|
||||
# get fields from ui form
|
||||
self.storage.sname = sname
|
||||
self.storage.stype = combobox.get_list_value(self.combo['type'])
|
||||
self.storage.x = self.spin['x'].get_value()
|
||||
self.storage.y = self.spin['y'].get_value()
|
||||
self.storage.z = self.spin['z'].get_value()
|
||||
self.storage.wx = self.spin['wx'].get_value()
|
||||
self.storage.wy = self.spin['wy'].get_value()
|
||||
self.storage.wz = self.spin['wz'].get_value()
|
||||
self.storage.angle = self.spin['angle'].get_value()
|
||||
self.storage.capacity = self.spin['capacity'].get_value()
|
||||
self.storage.capaunit = combobox.get_list_value(self.combo['unit'])
|
||||
self.storage.remarks = gtkutils.get_text_contents(self.text['remarks'])
|
||||
self.storage.save()
|
||||
if self.newrecord:
|
||||
self.load_list()
|
||||
self.newrecord = False
|
||||
self.topwidget.set_visible_child(self.box['storage'])
|
||||
|
||||
def on_but_cancel_clicked(self, widget):
|
||||
self.topwidget.set_visible_child(self.box['storage'])
|
||||
|
||||
@@ -7,8 +7,6 @@ SPDX-License-Identifier: WTFPL
|
||||
"""
|
||||
import os
|
||||
import locale
|
||||
import gi
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import GLib, Gtk, Gdk
|
||||
from yms import gtkutils
|
||||
|
||||
|
||||
Reference in New Issue
Block a user