Fixes for webgui and more native gui development

This commit is contained in:
2026-09-16 19:07:10 +02:00
parent 9b45fd3700
commit 2fc74c0677
31 changed files with 2143 additions and 417 deletions
+6 -6
View File
@@ -62,10 +62,10 @@ Optional import some sample data
4. Initialize document storage 4. Initialize document storage
Customize path and access rights to your needs Customize path and access rights to your needs
mkdir /var/local/yms mkdir /var/local/lib/yms
mkdir /var/local/yms/thumb mkdir /var/local/lib/yms/thumb
chown -R www-data /var/local/yms chown -R www-data /var/local/lib/yms
chmod -R 750 /var/local/yms chmod -R 750 /var/local/lib/yms
To grant access for the local gui the directory has to be writeable by a special To grant access for the local gui the directory has to be writeable by a special
group (here as example 'yms'). The user which runs the local gui (here group (here as example 'yms'). The user which runs the local gui (here
@@ -75,8 +75,8 @@ group (here as example 'yms'). The user which runs the local gui (here
groupadd yms groupadd yms
usermod -aG yms www-data usermod -aG yms www-data
usermod -aG yms guiuser usermod -aG yms guiuser
chgrp yms /var/local/yms chgrp yms /var/local/lib/yms
chgrp yms /var/local/yms/thumb chgrp yms /var/local/lib/yms/thumb
chmod -R 770 /var/local/yms chmod -R 770 /var/local/yms
4. Setup local GUI 4. Setup local GUI
+2 -1
View File
@@ -222,6 +222,7 @@ CREATE TABLE equipment (
CREATE TABLE inventory ( CREATE TABLE inventory (
invid int(10) UNSIGNED NOT NULL AUTO_INCREMENT, invid int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
invname varchar(80) NOT NULL, invname varchar(80) NOT NULL,
icat tinyint(3) DEFAULT NULL,
conttype enum('storage','box') NOT NULL DEFAULT 'storage', conttype enum('storage','box') NOT NULL DEFAULT 'storage',
sid smallint(6) UNSIGNED DEFAULT NULL, sid smallint(6) UNSIGNED DEFAULT NULL,
boxid smallint(6) UNSIGNED DEFAULT NULL, boxid smallint(6) UNSIGNED DEFAULT NULL,
@@ -470,7 +471,7 @@ CREATE TABLE note (
annotation text NOT NULL, annotation text NOT NULL,
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by smallint(6) DEFAULT NULL, created_by smallint(6) DEFAULT NULL,
PRIMARY KEY (noteid) PRIMARY KEY (noteid),
FOREIGN KEY fk_note_user (created_by) FOREIGN KEY fk_note_user (created_by)
REFERENCES user(userid) REFERENCES user(userid)
ON DELETE RESTRICT ON DELETE RESTRICT
+3 -2
View File
@@ -14,7 +14,7 @@ INSERT INTO user (userid, login, pass, displayname, role) VALUES
INSERT INTO settings (userid, sno, valint, valstr) VALUES INSERT INTO settings (userid, sno, valint, valstr) VALUES
(0, 0, 1, NULL), -- Database schema version (0, 0, 1, NULL), -- Database schema version
(0, 1, 0, NULL), -- No vessel assignment to SYSTEM (0, 1, 0, NULL), -- No vessel assignment to SYSTEM
(1, 1, 0), NULL, -- No vessel assignment to user "captain" (1, 1, 0, NULL), -- No vessel assignment to user "captain"
(0, 20, 1280, NULL), -- Image width limit (0, 20, 1280, NULL), -- Image width limit
(0, 21, 1024, NULL), -- Image height limit (0, 21, 1024, NULL), -- Image height limit
(0, 4, NULL, '€'), -- Currency symbol (0, 4, NULL, '€'), -- Currency symbol
@@ -72,7 +72,8 @@ INSERT INTO dropdown (ddid, ddval, ddtext) VALUES
(0, 9, 'Kistentypen'), (0, 9, 'Kistentypen'),
(0, 10, 'Sicherungsblöcke'), -- fuse locations (0, 10, 'Sicherungsblöcke'), -- fuse locations
(0, 11, 'Kabeltypen'), (0, 11, 'Kabeltypen'),
(0, 12, 'Technische Kabel-Bezeichnung'); (0, 12, 'Technische Kabel-Bezeichnung'),
(0, 13, 'Inventarkategorien');
INSERT INTO dropdown (ddid, ddval, ddtext, flags) VALUES INSERT INTO dropdown (ddid, ddval, ddtext, flags) VALUES
(2, 1, 'Lieferant', 'fixed'), (2, 1, 'Lieferant', 'fixed'),
+3 -2
View File
@@ -14,7 +14,7 @@ INSERT INTO user (userid, login, pass, displayname, role) VALUES
INSERT INTO settings (userid, sno, valint, valstr) VALUES INSERT INTO settings (userid, sno, valint, valstr) VALUES
(0, 0, 1, NULL), -- Database schema version (0, 0, 1, NULL), -- Database schema version
(0, 1, 0, NULL), -- No vessel assignment to SYSTEM (0, 1, 0, NULL), -- No vessel assignment to SYSTEM
(1, 1, 0), NULL, -- No vessel assignment to user "captain" (1, 1, 0, NULL), -- No vessel assignment to user "captain"
(0, 20, 1280, NULL), -- Image width limit (0, 20, 1280, NULL), -- Image width limit
(0, 21, 1024, NULL), -- Image height limit (0, 21, 1024, NULL), -- Image height limit
(0, 4, NULL, '€'), -- Currency symbol (0, 4, NULL, '€'), -- Currency symbol
@@ -71,7 +71,8 @@ INSERT INTO dropdown (ddid, ddval, ddtext) VALUES
(0, 9, 'box types'), (0, 9, 'box types'),
(0, 10, 'fuse blocks'), (0, 10, 'fuse blocks'),
(0, 11, 'cable types'), (0, 11, 'cable types'),
(0, 12, 'cable desc. technical'); (0, 12, 'cable desc. technical'),
(0, 13, 'inventory category');
INSERT INTO dropdown (ddid, ddval, ddtext, flags) VALUES INSERT INTO dropdown (ddid, ddval, ddtext, flags) VALUES
(2, 1, 'Supplier', 'fixed'), (2, 1, 'Supplier', 'fixed'),
+10
View File
@@ -52,6 +52,16 @@ else
mariadb -e "GRANT SELECT, INSERT, UPDATE, DELETE ON \`${DB_NAME}\`.* TO '${DB_USER}'@'localhost'" mariadb -e "GRANT SELECT, INSERT, UPDATE, DELETE ON \`${DB_NAME}\`.* TO '${DB_USER}'@'localhost'"
fi fi
echo "Initializing document storage..."
if ! getent group yms >/dev/null; then
addgroup --system yms
fi
if ! id -nG www-data | tr ' ' '\n' | grep -qx yms; then
adduser www-data yms
fi
mkdir -p /var/lib/yms/thumb
chown -R www-data:yms /var/lib/yms
db_get yms/webgui db_get yms/webgui
if [ "$RET" = "true" ]; then if [ "$RET" = "true" ]; then
+13
View File
@@ -0,0 +1,13 @@
#!/bin/sh
set -e
. /usr/share/debconf/confmodule
case "$1" in
remove|purge)
db_input high yms/remove-info || true
db_go || true
;;
esac
exit 0
+9
View File
@@ -23,3 +23,12 @@ Description: Enable the YMS web interface?
by a web server. by a web server.
. .
Do you want to enable the web interface? Do you want to enable the web interface?
Template: yms/remove-info
Type: note
Description: YMS document storage was not removed
The YMS package has been removed, but the document storage
remains on the system.
.
The directory /var/lib/yms and its contents have not been
deleted.
+2 -3
View File
@@ -29,13 +29,13 @@ $g_mailto_webmaster = 'webmaster@example.com';
// localization // localization
$g_textdomain = 'yms'; $g_textdomain = 'yms';
$g_timezone = 'Europe/Berlin'; $g_timezone = 'Europe/Berlin';
$g_locale = 'de_DE.UTF-8'; $g_locale = 'en_GB.UTF-8';
// vessel base shapes directory // vessel base shapes directory
$g_shapedir = '/usr/local/share/yms/shapes'; $g_shapedir = '/usr/local/share/yms/shapes';
// documents and images // documents and images
$g_doc_basepath = '/var/local/yms'; $g_doc_basepath = '/var/local/lib/yms';
$g_doc_maxsize = 1024*1024*16; // 16 MB, please adjust php.ini accordingly! $g_doc_maxsize = 1024*1024*16; // 16 MB, please adjust php.ini accordingly!
$g_doc_typemap = array( $g_doc_typemap = array(
'generic' => 'doc', 'generic' => 'doc',
@@ -50,4 +50,3 @@ $g_storage_limit = 1024; // MB
$g_thumb_size = 120; $g_thumb_size = 120;
$g_rows_pp = 10; // pagination limit $g_rows_pp = 10; // pagination limit
+8 -5
View File
@@ -136,11 +136,14 @@ $g_currsym = $sth->fetchColumn();
// allowed date formats // allowed date formats
$g_opt_datefmt = array( $g_opt_datefmt = array(
'Y-m-d' => _('YYYY-MM-DD'), 'Y-m-d' => _('YYYY-MM-DD'), // ISO / international /technical
'Y/m/d' => _('YYYY/MM/DD'), 'd.m.Y' => _('DD.MM.YYYY'), // Germany / Central & Northern Europe
'd.m.Y' => _('DD.MM.YYYY'), 'd/m/Y' => _('DD/MM/YYYY'), // UK / France / Spain / Italy / Australia / NZ
'd/m/Y' => _('DD/MM/YYYY'), 'd-m-Y' => _('DD-MM-YYYY'), // Netherlands / Denmark / Belgium
'm-d-Y' => _('MM-DD-YYYY') 'd M Y' => _('DD Mon YYYY'), // nautical documents / logbooks / unambiguous
'm.d.Y' => _('MM.DD.YYYY'), // USA
'm/d/Y' => _('MM/DD/YYYY'), // USA
'Y/m/d' => _('YYYY/MM/DD') // Japan / China
); );
$user = User::GetInstance(); // There can be only one $user = User::GetInstance(); // There can be only one
+9 -2
View File
@@ -18,6 +18,7 @@ $opt_storage = db_get_opt_storage($user->vid);
$opt_box = db_get_opt_box($user->vid); $opt_box = db_get_opt_box($user->vid);
$opt_invcond = db_load_enum('inventory', 'invcond', true, true); $opt_invcond = db_load_enum('inventory', 'invcond', true, true);
$opt_equipment = db_get_opt_equip($user->vid, [-1 => _('― none ―')]); $opt_equipment = db_get_opt_equip($user->vid, [-1 => _('― none ―')]);
$opt_icat = db_get_options(13);
// ========== ACTIONS START =================================================== // ========== ACTIONS START ===================================================
@@ -95,6 +96,8 @@ switch ($submit = form_get_action()) {
$p[':price'] = gpc_get_currency($_POST, 'price'); $p[':price'] = gpc_get_currency($_POST, 'price');
$p[':purchdate'] = gpc_get_date($_POST, 'purchdate'); $p[':purchdate'] = gpc_get_date($_POST, 'purchdate');
$p[':invcond'] = gpc_get_string($_POST, 'invcond'); $p[':invcond'] = gpc_get_string($_POST, 'invcond');
$p[':icat'] = gpc_get_int($_POST, 'icat');
if ($p[':icat'] <= 0) $p[':icat'] = NULL;
$p[':remarks'] = gpc_get_string($_POST, 'remarks', 150); $p[':remarks'] = gpc_get_string($_POST, 'remarks', 150);
$p[':eid'] = gpc_get_int($_POST, 'eid'); $p[':eid'] = gpc_get_int($_POST, 'eid');
if ($p[':eid'] <= 0) $p[':eid'] = NULL; if ($p[':eid'] <= 0) $p[':eid'] = NULL;
@@ -343,7 +346,7 @@ elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record ===================================== // ========== VARIANT: view single record =====================================
$sql = "SELECT invname, conttype, sid, boxid, number, weight, price, purchdate," $sql = "SELECT invname, conttype, sid, boxid, number, weight, price, purchdate,"
. " invcond, remarks " . " invcond, icat, remarks "
. "FROM inventory " . "FROM inventory "
. "WHERE invid=?"; . "WHERE invid=?";
$sth = $pdo->prepare($sql); $sth = $pdo->prepare($sql);
@@ -397,6 +400,7 @@ echo "<tr><th>", _('Weight'), "</th><td>", format_float($inventory->weight, 2, '
echo "<tr><th>", _('Price'), "</th><td>", format_currency($inventory->price), "</td></tr>\n"; echo "<tr><th>", _('Price'), "</th><td>", format_currency($inventory->price), "</td></tr>\n";
echo "<tr><th>", _('Purchase date'), "</th><td>", format_date($inventory->purchdate), "</td></tr>\n"; echo "<tr><th>", _('Purchase date'), "</th><td>", format_date($inventory->purchdate), "</td></tr>\n";
echo "<tr><th>", _('Condition'), "</th><td>", $opt_invcond[$inventory->invcond], "</td></tr>\n"; echo "<tr><th>", _('Condition'), "</th><td>", $opt_invcond[$inventory->invcond], "</td></tr>\n";
echo "<tr><th>", _('Category'), "</th><td>", $opt_icat[$inventory->icat], "</td></tr>\n";
echo "<tr><th>", _('Remarks'), "</th><td>", h($inventory->remarks, br:true), "</td></tr>\n"; echo "<tr><th>", _('Remarks'), "</th><td>", h($inventory->remarks, br:true), "</td></tr>\n";
$tags = db_load_taglist('inv', $id); $tags = db_load_taglist('inv', $id);
@@ -462,7 +466,10 @@ foreach ($cond as $k => $v) {
?> ?>
</select> </select>
</div> </div>
<?php form_create_select('eid', _('Equipment'), $opt_equipment, $inventory->eid); ?> <?php
form_create_select('icat', _('Category'), $g_opt_none + $opt_icat, $inventory->icat);
form_create_select('eid', _('Equipment'), $opt_equipment, $inventory->eid);
?>
<div class="mb-3"> <div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label> <label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"><?=h($inventory->remarks, br:true)?></textarea> <textarea class="form-control" id="remarks" name="remarks" rows="3"><?=h($inventory->remarks, br:true)?></textarea>
+31
View File
@@ -0,0 +1,31 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024-2026 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************
*/
function signalk_get($server, $skpath) {
$url = "$server/signalk/v1/api/" . str_replace('.', '/', $skpath);
var_dump($url);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 3,
CURLOPT_TIMEOUT => 5,
]);
$json = curl_exec($ch);
if ($json === false) {
throw new RuntimeException('Signal K error: ' . curl_error($ch));
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
throw new RuntimeException('Signal K HTTP-error: ' . $httpCode);
}
return json_decode($json, true, 512, JSON_THROW_ON_ERROR);
}
+1
View File
@@ -291,6 +291,7 @@ if (count($res) > 0) {
echo "<td>", $row['provname'], "</td>"; echo "<td>", $row['provname'], "</td>";
echo "<td>", $row['number'], ' ', $opt_unit[$row['unit']], "</td>"; echo "<td>", $row['number'], ' ', $opt_unit[$row['unit']], "</td>";
echo "<td>", $row['storedate'], ' - ', $row['shelflife'], "</td>"; echo "<td>", $row['storedate'], ' - ', $row['shelflife'], "</td>";
echo '<td><a title="', _('View'), '" href="provisions.php?f=view&id=', $row['provid'], '"><i class="bi-eye"></i></a></td>';
echo "</tr>\n"; echo "</tr>\n";
} }
echo "</table>\n"; echo "</table>\n";
+2
View File
@@ -1,3 +1,5 @@
# SPDX-License-Identifier: WTFPL
from gi.repository import Gtk from gi.repository import Gtk
def load_from_dict(combobox, dictionary, selected=None, sort=False): def load_from_dict(combobox, dictionary, selected=None, sort=False):
+130
View File
@@ -0,0 +1,130 @@
# SPDX-License-Identifier: WTFPL
"""
Dropdowns and database enums
dropdowns can change
enums are static
"""
class Dropdown:
HULL_TYPE = 1
COMPANY_TYPE = 2
STORAGE_TYPE = 3
EQUIPMENT_CATEGORY = 4
PROVISION_CATEGORY = 5
PROVISION_UNIT = 6
FUSE_TYPE = 7
UNIT = 8
BOX_TYPE = 9
FUSE_BLOCK = 10
CABLE_TYPE = 11
CABLE_TECHNAME = 12
class Lookup:
def __init__(self, db):
self.db = db
self._enums = {}
self._dropdowns = {}
def load(self):
self._load_enums()
self._load_dropdowns()
def _load_enums(self):
"""
TODO translation via gettext needed
"""
db_enums = {
'user.role': ('user', 'role'),
'dropdown.flags': ('dropdown', 'flags'),
'vessel.vtype': ('vessel', 'vtype'),
'storage.capaunit': ('storage', 'capaunit'),
'tagref.objtype': ('tagref', 'objtype'),
'inventory.conttype': ('inventory', 'conttype'),
'inventory.invcond': ('inventory', 'invcond'),
'cable.cablecond': ('cable', 'cablecond'),
'measurement.accuracy': ('measurement', 'accuracy'),
'document.doctype': ('document', 'doctype'),
'document.roleaccess': ('document', 'roleaccess'),
'docref.reftype': ('docref', 'reftype'),
'maintenance.maintstate': ('maintenance', 'maintstate'),
'project.projstate': ('project', 'projstate'),
'task.priority': ('task', 'priority'),
'task.taskstate': ('task', 'taskstate'),
'note.notetype': ('note', 'notetype'),
'checklist.clstate': ('checklist', 'clstate'),
'checkitem.checkresult': ('checkitem', 'checkresult'),
'signalk.objtype': ('signalk', 'objtype'),
'signalk.datatype': ('signalk', 'datatype')
}
for key, (table, column) in db_enums.items():
self._enums[key] = self.db.load_enum(table, column)
def _load_dropdowns(self):
self._dropdowns.clear()
sql = (
"SELECT ddid, ddval, ddtext "
"FROM dropdown "
"WHERE ddid>0 "
"ORDER BY ddid, sort, ddval"
)
self.db.cur.execute(sql)
for ddid, ddval, ddtext in self.db.cur.fetchall():
if ddid not in self._dropdowns:
self._dropdowns[ddid] = {}
self._dropdowns[ddid][ddval] = ddtext
def enum(self, name):
return self._enums[name]
def dropdown(self, ddid):
return self._dropdowns[ddid]
def refresh(self):
# TODO ugly hack please improve
self._load_dropdowns()
class ListDefinition:
pass
"""
EQUIPMENT_LIST = ListDefinition(
name="equipment",
query=
"SELECT
e.eid,
e.ename,
c.name AS manufacturer,
e.model,
e.ecat,
e.weight
FROM equipment e
LEFT JOIN company c
ON c.cid = e.manufacturer"
,
columns=[
Column("ename", _("Name")),
Column("manufacturer", _("Manufacturer")),
Column(
"model",
_("Model")
),
Column(
"ecat",
_("Category"),
formatter=dropdown(Dropdown.EQUIPMENT_CATEGORY)
),
Column(
"weight",
_("Weight"),
formatter=weight()
),
]
)
"""
+1 -1
View File
@@ -7,7 +7,7 @@ class Box(DbRecord):
table = "box" table = "box"
pk_field = "boxid" pk_field = "boxid"
fields = ('boxid', 'sid', 'boxtype', 'parent', 'label', 'color', 'content', fields = ('boxid', 'sid', 'boxtype', 'parent', 'label', 'color', 'content',
'weight', 'remarks') 'wx', 'wy', 'wz', 'weight', 'weight_net', 'price', 'remarks')
def __init__(self, db, boxid=None): def __init__(self, db, boxid=None):
super().__init__(db, boxid) super().__init__(db, boxid)
+11 -1
View File
@@ -22,14 +22,24 @@ class Vessel(DbRecord):
"WHERE v1.vid>=0 AND v2.vid IS NULL" "WHERE v1.vid>=0 AND v2.vid IS NULL"
) )
self.dcur.execute(sql) self.dcur.execute(sql)
row = self.cur.fetchone() row = self.dcur.fetchone()
if row is None: if row is None:
# vessel table empty: create first vessel # vessel table empty: create first vessel
self.pk_value = 1 self.pk_value = 1
else: else:
# create additional vessel # create additional vessel
self.pk_value = row['newid'] self.pk_value = row['newid']
self.clear()
self.vid = self.pk_value
self.vesselname = f"Vessel #{self.pk_value}" self.vesselname = f"Vessel #{self.pk_value}"
self.vtype = 1 # monohull self.vtype = 1 # monohull
self._insert() self._insert()
self.conn.commit() self.conn.commit()
def save(self):
super().save()
self.conn.commit()
def delete(self):
# there must be no assiciated data!
pass
+2
View File
@@ -1,3 +1,5 @@
# SPDX-License-Identifier: WTFPL
from gi.repository import Gtk from gi.repository import Gtk
def add_column(treeview, label, index, xalign=None, col_fg=None, col_bg=None, visible=True): def add_column(treeview, label, index, xalign=None, col_fg=None, col_bg=None, visible=True):
+758 -367
View File
File diff suppressed because it is too large Load Diff
+844
View File
@@ -0,0 +1,844 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.40.0 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<object class="GtkAdjustment" id="adj_price">
<property name="upper">90</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
<object class="GtkAdjustment" id="adj_weight">
<property name="upper">100</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
<object class="GtkAdjustment" id="adj_weight_net">
<property name="upper">100</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
<object class="GtkAdjustment" id="adj_width_x">
<property name="upper">9999</property>
<property name="step-increment">10</property>
<property name="page-increment">100</property>
</object>
<object class="GtkAdjustment" id="adj_width_y">
<property name="upper">9999</property>
<property name="step-increment">10</property>
<property name="page-increment">100</property>
</object>
<object class="GtkAdjustment" id="adj_width_z">
<property name="upper">9999</property>
<property name="step-increment">10</property>
<property name="page-increment">100</property>
</object>
<object class="GtkStack" id="topobject">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">8</property>
<child>
<object class="GtkBox" id="box_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkExpander">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<!-- n-columns=3 n-rows=3 -->
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Filter Box</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkTreeView" id="tvw_box">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButtonBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="layout-style">end</property>
<child>
<object class="GtkButton" id="but_new">
<property name="label" translatable="yes">New</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<signal name="clicked" handler="on_but_new_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but_edit">
<property name="label" translatable="yes">Edit</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<signal name="clicked" handler="on_but_edit_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but_detail">
<property name="label" translatable="yes">Details</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<signal name="clicked" handler="on_but_detail_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="name">page0</property>
<property name="title" translatable="yes">page0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box_box_detail">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Box Detais</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<!-- n-columns=2 n-rows=8 -->
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Label</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="lbl_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Placeholder</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Remarks</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">7</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="lbl_remarks">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">7</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Content</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="lbl_content">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Type</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Color</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Weight</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">4</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="lbl_type">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="lbl_color">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="lbl_weight">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">4</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Weight net</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="lbl_weight_net">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Price</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">6</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="lbl_price">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">6</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButtonBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="layout-style">end</property>
<child>
<object class="GtkButton" id="but_delete">
<property name="label" translatable="yes">Delete</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<signal name="clicked" handler="on_but_delete_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
<property name="secondary">True</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but_edit2">
<property name="label" translatable="yes">Edit</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<signal name="clicked" handler="on_but_edit_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but_close">
<property name="label" translatable="yes">Close</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<signal name="clicked" handler="on_but_close_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="name">page1</property>
<property name="title" translatable="yes">page1</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box_box_edit">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="lbl_title_edit">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Edit Box</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<!-- n-columns=7 n-rows=9 -->
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Label</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Type</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="ent_label">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
<property name="width">6</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="cmb_type">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
<property name="width">6</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Dimensions (L x W x H)</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">4</property>
<property name="margin-end">4</property>
<property name="label" translatable="yes">x</property>
</object>
<packing>
<property name="left-attach">2</property>
<property name="top-attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">4</property>
<property name="margin-end">4</property>
<property name="label" translatable="yes">x</property>
</object>
<packing>
<property name="left-attach">4</property>
<property name="top-attach">3</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="spi_wx">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="max-length">4</property>
<property name="width-chars">4</property>
<property name="text" translatable="yes">0</property>
<property name="adjustment">adj_width_x</property>
<property name="numeric">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">3</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="spi_wy">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="max-length">4</property>
<property name="width-chars">4</property>
<property name="text" translatable="yes">0</property>
<property name="adjustment">adj_width_y</property>
<property name="numeric">True</property>
</object>
<packing>
<property name="left-attach">3</property>
<property name="top-attach">3</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="spi_wz">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="max-length">4</property>
<property name="width-chars">4</property>
<property name="text" translatable="yes">0</property>
<property name="adjustment">adj_width_z</property>
<property name="numeric">True</property>
</object>
<packing>
<property name="left-attach">5</property>
<property name="top-attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Price</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Weight</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">6</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Remarks</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">8</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkTextView" id="txt_remarks">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
</child>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">8</property>
<property name="width">6</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Weight net</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">7</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">4</property>
<property name="margin-end">4</property>
<property name="label" translatable="yes">mm</property>
</object>
<packing>
<property name="left-attach">6</property>
<property name="top-attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Content</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="ent_content">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
<property name="width">6</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="spi_weight_net">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="text" translatable="yes">0</property>
<property name="adjustment">adj_weight_net</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">7</property>
<property name="width">3</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="spi_weight">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="text" translatable="yes">0</property>
<property name="adjustment">adj_weight</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">6</property>
<property name="width">3</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="spi_price">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="text" translatable="yes">0</property>
<property name="adjustment">adj_price</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">5</property>
<property name="width">3</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Colour</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">4</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but_color">
<property name="label" translatable="yes">#FFFFFF</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="relief">half</property>
<signal name="clicked" handler="on_but_color_clicked" swapped="no"/>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">4</property>
<property name="width">3</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButtonBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="layout-style">end</property>
<child>
<object class="GtkButton" id="but_save">
<property name="label" translatable="yes">Save</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<signal name="clicked" handler="on_but_save_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but_cancel">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<signal name="clicked" handler="on_but_cancel_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="name">page2</property>
<property name="title" translatable="yes">page2</property>
<property name="position">2</property>
</packing>
</child>
</object>
</interface>
+103 -8
View File
@@ -205,7 +205,7 @@
</packing> </packing>
</child> </child>
<child> <child>
<!-- n-columns=3 n-rows=3 --> <!-- n-columns=2 n-rows=7 -->
<object class="GtkGrid"> <object class="GtkGrid">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can-focus">False</property> <property name="can-focus">False</property>
@@ -224,7 +224,7 @@
<object class="GtkLabel" id="lbl_name"> <object class="GtkLabel" id="lbl_name">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can-focus">False</property> <property name="can-focus">False</property>
<property name="label" translatable="yes">Placeholder</property> <property name="hexpand">True</property>
</object> </object>
<packing> <packing>
<property name="left-attach">1</property> <property name="left-attach">1</property>
@@ -239,7 +239,7 @@
</object> </object>
<packing> <packing>
<property name="left-attach">0</property> <property name="left-attach">0</property>
<property name="top-attach">1</property> <property name="top-attach">6</property>
</packing> </packing>
</child> </child>
<child> <child>
@@ -249,23 +249,118 @@
</object> </object>
<packing> <packing>
<property name="left-attach">1</property> <property name="left-attach">1</property>
<property name="top-attach">6</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Type</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property> <property name="top-attach">1</property>
</packing> </packing>
</child> </child>
<child> <child>
<placeholder/> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Position (x, y, z)</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</packing>
</child> </child>
<child> <child>
<placeholder/> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Dimension (x, y, z)</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">3</property>
</packing>
</child> </child>
<child> <child>
<placeholder/> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Angle</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">4</property>
</packing>
</child> </child>
<child> <child>
<placeholder/> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Capacity</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">5</property>
</packing>
</child> </child>
<child> <child>
<placeholder/> <object class="GtkLabel" id="lbl_type">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="lbl_position">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="lbl_dimension">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="lbl_angle">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">4</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="lbl_capacity">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">5</property>
</packing>
</child> </child>
</object> </object>
<packing> <packing>
+32 -3
View File
@@ -14,6 +14,7 @@ from gi.repository import GLib, Gtk, Gdk, Rsvg
from .view import View from .view import View
from yms import gtkutils, combobox, treeview from yms import gtkutils, combobox, treeview
from yms.lookup import Dropdown
class BaseView(View): class BaseView(View):
@@ -63,7 +64,15 @@ class BaseView(View):
self.db.cur.execute("INSERT INTO settings (userid, sno, valint) VALUES (0, 1, 0)") self.db.cur.execute("INSERT INTO settings (userid, sno, valint) VALUES (0, 1, 0)")
self.db.conn.commit() self.db.conn.commit()
else: else:
self.context.vessel.vid = row[0] # check if vessel from settings exist
self.db.cur.execute("SELECT count(*) FROM vessel WHERE vid=%s", (row[0],))
res = self.db.cur.fetchone()[0]
if res > 0:
self.context.vessel.vid = row[0]
else:
# TODO set vessel to first in list
self.context.vessel.vid = 0
self.context.vessel.vesselname = "Ghost"
# default storage for current vessel # default storage for current vessel
sql = "SELECT sid, sname FROM storage WHERE stype=0 AND vid=%s ORDER BY sname" sql = "SELECT sid, sname FROM storage WHERE stype=0 AND vid=%s ORDER BY sname"
@@ -75,7 +84,7 @@ class BaseView(View):
vessellist = {} vessellist = {}
self.db.dcur.execute("SELECT vid, vesselname, model FROM vessel ORDER BY vid") self.db.dcur.execute("SELECT vid, vesselname, model FROM vessel ORDER BY vid")
for row in self.db.dcur.fetchall(): for row in self.db.dcur.fetchall():
vessellist[row['vid']] = ( vessellist[row['vid']] = (
row['vesselname'] if row['model'] is None row['vesselname'] if row['model'] is None
else row['vesselname'] + " - " + row['model'] else row['vesselname'] + " - " + row['model']
) )
@@ -154,6 +163,15 @@ class BaseView(View):
if answer == False: if answer == False:
return return
self.context.vessel.create() self.context.vessel.create()
model = self.combo['vessel'].get_model()
model.append((self.context.vessel.vid, self.context.vessel.vesselname))
combobox.activate_row(self.combo['vessel'], self.context.vessel.vid)
self.edit_vessel(self.context.vessel)
self.stack['vessel'].set_visible_child(self.box['vessel_edit'])
def on_but_vessel_edit_clicked(self, widget):
self.edit_vessel(self.context.vessel)
self.stack['vessel'].set_visible_child(self.box['vessel_edit'])
def on_but_vessel_save_clicked(self, widget): def on_but_vessel_save_clicked(self, widget):
print("Save vessel") print("Save vessel")
@@ -172,6 +190,13 @@ class BaseView(View):
txtbuf = self.text['vessel_remarks'].get_buffer() txtbuf = self.text['vessel_remarks'].get_buffer()
vessel.remarks = txtbuf.get_text(txtbuf.get_start_iter(), txtbuf.get_end_iter(), True) vessel.remarks = txtbuf.get_text(txtbuf.get_start_iter(), txtbuf.get_end_iter(), True)
vessel.save() vessel.save()
self.stack['vessel'].set_visible_child(self.box['vessel'])
def on_but_vessel_cancel_clicked(self, widget):
self.stack['vessel'].set_visible_child(self.box['vessel'])
def on_but_vessel_delete_clicked(self, widget):
pass
def on_but_comp_new_clicked(self, widget): def on_but_comp_new_clicked(self, widget):
print("New company") print("New company")
@@ -189,7 +214,11 @@ class BaseView(View):
pass pass
def display_vessel(self, vessel): def display_vessel(self, vessel):
print("Display 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'))
def edit_vessel(self, vessel):
self.entry['vesselname'].set_text(vessel.vesselname) self.entry['vesselname'].set_text(vessel.vesselname)
self.entry['model'].set_text(vessel.model or '') self.entry['model'].set_text(vessel.model or '')
self.spin['year_built'].set_value(vessel.year_built or 0) self.spin['year_built'].set_value(vessel.year_built or 0)
+94
View File
@@ -0,0 +1,94 @@
# 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 box
class BoxesView(View):
def __init__(self, context):
super().__init__(context, _("Box"), "boxes.ui")
# box already used for controls so other name here
self.sbox = box.Box(context.db) # current record
self.newrecord = False
self.lst_box = Gtk.ListStore(int, str, str, str)
sql = (
"SELECT b.boxid, b.label, b.content, b.remarks "
"FROM box AS b JOIN storage AS s USING (sid) "
"WHERE s.vid=%s "
"ORDER BY b.label"
)
self.db.cur.execute(sql, (context.vessel.vid,))
for row in self.db.cur.fetchall():
self.lst_box.append(row)
treeview.add_column(self.tree['box'], _('ID'), 0)
treeview.add_column(self.tree['box'], _('Label'), 1)
treeview.add_column(self.tree['box'], _('Content'), 2)
treeview.add_column(self.tree['box'], _('Remarks'), 3)
self.tree['box'].set_model(self.lst_box)
def load_list(self):
pass
def display_record(self):
self.label['label'].set_text(self.sbox.label)
self.label['remarks'].set_text(self.sbox.remarks or '')
def edit_record(self):
self.entry['label'].set_text(self.sbox.label)
self.entry['content'].set_text(self.sbox.content or '')
self.spin['wx'].set_value(self.sbox.wx or 0)
self.spin['wy'].set_value(self.sbox.wy or 0)
self.spin['wz'].set_value(self.sbox.wz or 0)
self.text['remarks'].get_buffer().set_text(self.sbox.remarks or '')
# buttons on list page
def on_but_new_clicked(self, widget):
self.newrecord = True
self.label['title_edit'].set_text("Add new Box")
self.topwidget.set_visible_child(self.box['box_edit'])
def on_but_edit_clicked(self, widget):
self.newrecord = False
self.label['title_edit'].set_text("Edit Box")
sid = treeview.get_value(self.tree['box'], 0)
self.sbox.load(sid)
self.edit_record()
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)
self.display_record()
self.topwidget.set_visible_child(self.box['box_detail'])
# buttons on detail page
# edit2 uses edit callback
def on_but_close_clicked(self, widget):
self.topwidget.set_visible_child(self.box['box'])
def on_but_delete_clicked(self, widget):
self.topwidget.set_visible_child(self.box['box'])
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['box'])
self.newrecord = False
def on_but_color_clicked(self, widget):
pass
+6
View File
@@ -62,3 +62,9 @@ class CablesView(View):
def on_but_cancel_clicked(self, widget): def on_but_cancel_clicked(self, widget):
self.topwidget.set_visible_child(self.box['cables']) self.topwidget.set_visible_child(self.box['cables'])
def display_record(self):
pass
def edit_record(self):
pass
+6
View File
@@ -59,3 +59,9 @@ class DocumentsView(View):
def on_but_cancel_clicked(self, widget): def on_but_cancel_clicked(self, widget):
self.topwidget.set_visible_child(self.box['documents']) self.topwidget.set_visible_child(self.box['documents'])
def display_record(self):
pass
def edit_record(self):
pass
+6
View File
@@ -64,3 +64,9 @@ class FusesView(View):
def on_but_cancel_clicked(self, widget): def on_but_cancel_clicked(self, widget):
self.topwidget.set_visible_child(self.box['fuses']) self.topwidget.set_visible_child(self.box['fuses'])
def display_record(self):
pass
def edit_record(self):
pass
+6
View File
@@ -58,3 +58,9 @@ class MaintenanceView(View):
def on_but_cancel_clicked(self, widget): def on_but_cancel_clicked(self, widget):
self.topwidget.set_visible_child(self.box['maintenance']) self.topwidget.set_visible_child(self.box['maintenance'])
def display_record(self):
pass
def edit_record(self):
pass
+6
View File
@@ -68,3 +68,9 @@ class ProjectsView(View):
def on_but_cancel_clicked(self, widget): def on_but_cancel_clicked(self, widget):
self.topwidget.set_visible_child(self.box['projects']) self.topwidget.set_visible_child(self.box['projects'])
def display_record(self):
pass
def edit_record(self):
pass
+1 -1
View File
@@ -21,7 +21,7 @@ class StatusView:
gtkutils.init_named_controls(self, builder) gtkutils.init_named_controls(self, builder)
# Generic information # Generic information
self.label['dbinfo'].set_text("Database: {}".format(context.cfg['db'])) self.label['dbinfo'].set_text("Database: {} on {}".format(context.cfg['db'], context.cfg['host']))
# Load table status info # Load table status info
self.lst_tables = Gtk.ListStore(str, int) self.lst_tables = Gtk.ListStore(str, int)
+17 -2
View File
@@ -8,6 +8,7 @@ from gi.repository import GLib, Gtk, Gdk
from .view import View from .view import View
from yms import gtkutils, combobox, treeview from yms import gtkutils, combobox, treeview
from yms.model import storage from yms.model import storage
from yms.lookup import Dropdown
class StorageView(View): class StorageView(View):
@@ -34,6 +35,14 @@ class StorageView(View):
treeview.add_column(self.tree['storage'], _('Remarks'), 3) treeview.add_column(self.tree['storage'], _('Remarks'), 3)
self.tree['storage'].set_model(self.lst_storage) 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.enum('storage.capaunit')
combobox.load_from_dict(self.combo['unit'], combodict)
def load_list(self): def load_list(self):
pass pass
@@ -56,9 +65,11 @@ class StorageView(View):
self.topwidget.set_visible_child(self.box['stor_edit']) self.topwidget.set_visible_child(self.box['stor_edit'])
def on_but_edit_clicked(self, widget): def on_but_edit_clicked(self, widget):
sid = treeview.get_value(self.tree['storage'], 0)
if sid is None:
return
self.newrecord = False self.newrecord = False
self.label['title_edit'].set_text("Edit Storage") self.label['title_edit'].set_text("Edit Storage")
sid = treeview.get_value(self.tree['storage'], 0)
self.storage.load(sid) self.storage.load(sid)
self.edit_record() self.edit_record()
self.topwidget.set_visible_child(self.box['stor_edit']) self.topwidget.set_visible_child(self.box['stor_edit'])
@@ -80,8 +91,12 @@ class StorageView(View):
# buttons on edit page # buttons on edit page
def on_but_save_clicked(self, widget): def on_but_save_clicked(self, widget):
print("save not implemented yet")
self.newrecord = False self.newrecord = False
# check mandatory fields
sname = self.entry['sname'].get_text().strip()
if not sname:
return
# here be dragons
def on_but_cancel_clicked(self, widget): def on_but_cancel_clicked(self, widget):
self.topwidget.set_visible_child(self.box['storage']) self.topwidget.set_visible_child(self.box['storage'])
+6 -6
View File
@@ -27,25 +27,25 @@ class View:
self.topwidget = builder.get_object("topobject") self.topwidget = builder.get_object("topobject")
gtkutils.init_named_controls(self, builder) gtkutils.init_named_controls(self, builder)
def format_int(self, ival, separator=True, suffix=None): def format_int(self, ival, separator=True, suffix=None, default=''):
if ival is None: if ival is None:
return '' return default
formatted = locale.format_string("%d", ival, separator) formatted = locale.format_string("%d", ival, separator)
if suffix: if suffix:
formatted += f"\u00A0{suffix}" formatted += f"\u00A0{suffix}"
return formatted return formatted
def format_float(self, fval, digits=2, grouping=True, suffix=None): def format_float(self, fval, digits=2, grouping=True, suffix=None, default=''):
if fval is None: if fval is None:
return '' return default
formatted = locale.format_string(f"%.{digits}f", fval, grouping) formatted = locale.format_string(f"%.{digits}f", fval, grouping)
if suffix: if suffix:
formatted += f"\u00A0{suffix}" formatted += f"\u00A0{suffix}"
return formatted return formatted
def format_date(self, dval): def format_date(self, dval, default=''):
if dval is None: if dval is None:
return '' return default
return dval.strftime(self.context.datefmt) return dval.strftime(self.context.datefmt)
def on_textview_keypress(self, widget, event): def on_textview_keypress(self, widget, event):
+15 -7
View File
@@ -37,9 +37,11 @@ from yms import database
from yms import gtkutils, combobox, treeview from yms import gtkutils, combobox, treeview
from yms.model import user from yms.model import user
from yms.model import vessel from yms.model import vessel
from yms.lookup import Lookup
from yms.view.base import BaseView from yms.view.base import BaseView
from yms.view.storage import StorageView from yms.view.storage import StorageView
from yms.view.boxes import BoxesView
from yms.view.equipment import EquipmentView from yms.view.equipment import EquipmentView
from yms.view.inventory import InventoryView from yms.view.inventory import InventoryView
from yms.view.provisions import ProvisionsView from yms.view.provisions import ProvisionsView
@@ -57,17 +59,20 @@ class AppContext:
'host': 'localhost', 'host': 'localhost',
'db': 'yms', 'db': 'yms',
'user': 'yms', 'user': 'yms',
'docpath': '/var/local/yms', 'docpath': '/var/local/lib/yms',
'shapedir': '/usr/local/share/yms/shapes' 'shapedir': '/usr/local/share/yms/shapes'
} }
# mapping between PHP and Python # mapping between PHP and Python
datefmt_map = { datefmt_map = {
'Y-m-d': '%Y.%m.%d', 'Y-m-d': '%Y-%m-%d', # ISO / international / technical
'Y/m/d': '%Y/%m/%d', 'd.m.Y': '%d.%m.%Y', # Germany / Central & Northern Europe
'd.m.Y': '%d.%m.%Y', 'd/m/Y': '%d/%m/%Y', # UK / France / Spain / Italy / Australia / NZ
'd/m/Y': '%d/%m/%Y', 'd-m-Y': '%d-%m-%Y', # Netherlands / Denmark / Belgium
'm-d-Y': '%m.%d.%Y' 'd M Y': '%d %b %Y', # nautical documents / logbooks / unambiguous
'm.d.Y': '%m.%d.%Y', # USA
'm/d/Y': '%m/%d/%Y', # USA
'Y/m/d': '%Y/%m/%d' # Japan / China
} }
def __init__(self): def __init__(self):
@@ -80,6 +85,7 @@ class AppContext:
def set_db(self, db): def set_db(self, db):
self.db = db self.db = db
self.lookup = Lookup(db)
def load(self): def load(self):
self.user = user.User(db, 0) self.user = user.User(db, 0)
@@ -97,6 +103,7 @@ class AppContext:
else: else:
# perhaps create missing record here? # perhaps create missing record here?
pass pass
self.lookup.load()
def get_sharepath(self): def get_sharepath(self):
path = os.path.realpath(__file__) path = os.path.realpath(__file__)
@@ -113,6 +120,7 @@ class Frontend:
self.modules = { self.modules = {
"base": BaseView(context), "base": BaseView(context),
"storage": StorageView(context), "storage": StorageView(context),
"box": BoxesView(context),
"equipment": EquipmentView(context), "equipment": EquipmentView(context),
"inventory": InventoryView(context), "inventory": InventoryView(context),
"provisions": ProvisionsView(context), "provisions": ProvisionsView(context),
@@ -195,6 +203,7 @@ if __name__ == "__main__":
context.cfg['host'] = config.get('DB', 'host') context.cfg['host'] = config.get('DB', 'host')
context.cfg['db'] = config.get('DB', 'db') context.cfg['db'] = config.get('DB', 'db')
db = database.Database(context.cfg['host'], context.cfg['db']) db = database.Database(context.cfg['host'], context.cfg['db'])
context.set_db(db)
connected = False connected = False
if context.cfg['host'] == 'socket': if context.cfg['host'] == 'socket':
connected = db.connect_local() connected = db.connect_local()
@@ -203,7 +212,6 @@ if __name__ == "__main__":
context.cfg['pass'] = config.get('DB', 'pass') context.cfg['pass'] = config.get('DB', 'pass')
connected = db.connect(context.cfg['user'], context.cfg['pass']) connected = db.connect(context.cfg['user'], context.cfg['pass'])
if connected: if connected:
context.set_db(db)
context.load() context.load()
# check if shapedir exists # check if shapedir exists
context.cfg['shapedir'] = config.get('Data', 'shapedir') context.cfg['shapedir'] = config.get('Data', 'shapedir')