i18n and ini-file

added internationalization, clsTableWidget and INI-file settings and pyinstaller-scripts
This commit is contained in:
Paul S 2021-06-30 18:25:01 +02:00
parent 90afe07406
commit 48f8dc221a
20 changed files with 1230 additions and 333 deletions

258
src/clsTableWidget.py Normal file
View file

@ -0,0 +1,258 @@
#!/usr/bin/env python3
"""
project: clsTableWidget
file: clsTableWidget.py
summary: Implements my own TableWidget class
author: Paul Salajean (p.salajean[at]gmx.de)
license: GPL
version: 0.1
"""
# Standard library imports
import sys
import os
# Third party imports
from PySide2.QtWidgets import QApplication, QTableWidget, QAbstractItemView, QTableWidgetItem, QMenu, \
QMainWindow, QMessageBox
from PySide2.QtCore import Qt, QItemSelectionModel, QCoreApplication
from PySide2.QtGui import QIcon
# local globals
SCRIPT_PATH = os.path.abspath(os.path.dirname(__file__))
ICON_CLEAR = SCRIPT_PATH + "./img/icons8-clear-symbol-16.png"
ICON_COPY = SCRIPT_PATH + "./img/icons8-copy-16.png"
ICON_ERASER = SCRIPT_PATH + "/img/icons8-eraser-16.png"
ICON_INSERT = SCRIPT_PATH + "/img/icons8-insert-clip-16.png"
ICON_APPEND = SCRIPT_PATH + "/img/icons8-append-clip-16.png"
ICON_PASTE = SCRIPT_PATH + "/img/icons8-paste-16.png"
ICON_CUT = SCRIPT_PATH + "/img/icons8-scissors-16.png"
ICON_ADD_ROW = SCRIPT_PATH + "/img/icons8-add-row-16.png"
ICON_DEL = SCRIPT_PATH + "/img/icons8-delete-16.png"
# def resource_path(relative_path):
# """ Get absolute path to resource, works for dev and for PyInstaller """
# try:
# # PyInstaller creates a temp folder and stores path in _MEIPASS
# base_path = sys._MEIPASS
# print("base_path", base_path)
# except Exception:
# base_path = os.path.abspath(".")
# return os.path.join(base_path, relative_path)
class TableWidget(QTableWidget):
def __init__(self, parent=None):
super().__init__()
self.parent = parent
self.setParent(parent)
# self.setSelectionMode(QAbstractItemView.ContiguousSelection)
self.setSelectionMode(QAbstractItemView.SingleSelection)
self.setSelectionBehavior(QTableWidget.SelectItems)
#self.setSelectionBehavior(QTableWidget.SelectRows)
self.setAlternatingRowColors(True)
# Context-menu
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.on_context_menu)
# self.setEditTriggers(QAbstractItemView.DoubleClicked | QAbstractItemView.EditKeyPressed | QAbstractItemView.AnyKeyPressed)
self.headers = self.verticalHeader()
self.headers.setContextMenuPolicy(Qt.CustomContextMenu)
self.headers.customContextMenuRequested.connect(self.on_rowheadercontext_menu)
self.headers.setSelectionMode(QAbstractItemView.SingleSelection)
self.headers.sectionClicked.connect(self.select_row)
self.row_selected = False
def select_row(self, row):
self.setSelectionBehavior(QTableWidget.SelectRows)
self.selectRow(row)
self.setSelectionBehavior(QTableWidget.SelectItems)
self.row_selected = True
def on_context_menu(self, position):
menu = QMenu()
item_cut = menu.addAction(QIcon(ICON_CUT), QCoreApplication.translate("TableWidget", "Cut") + "\tCtrl+X")
item_copy = menu.addAction(QIcon(ICON_COPY), QCoreApplication.translate("TableWidget", "Copy") + "\tCtrl+C")
item_paste = menu.addAction(QIcon(ICON_PASTE), QCoreApplication.translate("TableWidget", "Paste") + "\tCtrl+V")
menu.addSeparator()
print(ICON_ERASER)
item_delete = menu.addAction(QIcon(ICON_ERASER), QCoreApplication.translate("TableWidget", "Delete") + "\tDel")
ac = menu.exec_(self.mapToGlobal(position))
if ac == item_cut:
self.item_cut()
elif ac == item_copy:
self.item_copy()
elif ac == item_paste:
self.item_paste()
elif ac == item_delete:
self.item_del()
def on_rowheadercontext_menu(self, position):
menu = QMenu()
row_cut = menu.addAction(QIcon(ICON_CUT), QCoreApplication.translate("TableWidget", "Cut row"))
row_copy = menu.addAction(QIcon(ICON_COPY), QCoreApplication.translate("TableWidget", "Copy row"))
row_paste = menu.addAction(QIcon(ICON_PASTE), QCoreApplication.translate("TableWidget", "Paste row"))
menu.addSeparator()
row_insert_before = menu.addAction(QIcon(ICON_INSERT), QCoreApplication.translate("TableWidget", "Insert row before"))
row_insert_after = menu.addAction(QIcon(ICON_APPEND), QCoreApplication.translate("TableWidget", "Insert row after"))
menu.addSeparator()
row_remove = menu.addAction(QIcon(ICON_DEL), QCoreApplication.translate("TableWidget", "Remove row"))
row_delete_items = menu.addAction(QIcon(ICON_ERASER), QCoreApplication.translate("TableWidget", "Delete items"))
ac = menu.exec_(self.mapToGlobal(position))
row = self.headers.logicalIndexAt(position)
if ac == row_cut:
self.item_cut()
elif ac == row_copy:
self.item_copy()
elif ac == row_paste:
self.item_paste()
elif ac == row_insert_before:
self.row_insert(row)
elif ac == row_insert_after:
self.row_insert(row+1)
elif ac == row_remove:
self.row_remove(row)
elif ac == row_delete_items:
self.row_delete_items()
def row_insert(self, row):
self.insertRow(row)
def has_data(self, row):
""" Check if target already contains data. """
# sel_idx = self.selectionModel().selectedIndexes()
for col in range(self.columnCount()):
item = self.item(row, col)
if item:
if len(item.text()) > 0:
return True
return False
def row_remove(self, row):
if self.has_data(row):
msg = QCoreApplication.translate("TableWidget", "Row Nr.") + " " + str(row+1) + " " + QCoreApplication.translate("TableWidget", "to be removed?")
reply = QMessageBox.question(self, QCoreApplication.translate("TableWidget", "Remove"), msg, \
QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
if reply == QMessageBox.No:
return False
self.removeRow(row)
return True
def row_delete_items(self):
self.item_del()
def keyPressEvent(self, event):
super().keyPressEvent(event)
modifiers = QApplication.keyboardModifiers()
key = event.key()
if modifiers == Qt.ControlModifier:
if key == Qt.Key_C:
self.item_copy()
elif key == Qt.Key_V:
self.item_paste()
elif key == Qt.Key_X:
self.item_cut()
elif key == Qt.Key_A:
self.setSelectionMode(QAbstractItemView.ContiguousSelection)
self.selectAll()
self.setSelectionMode(QAbstractItemView.SingleSelection)
if key == Qt.Key_Delete:
self.item_del()
elif key == Qt.Key_Escape:
self.clearSelection()
def item_paste(self):
cur_row = self.currentRow()
cur_col = self.currentColumn()
# ask_confirmation = True
if self.row_selected:
cur_col = 0
col = 0
if len(self.clipboard_data) == 1:
data = self.clipboard_data[0]
item = QTableWidgetItem(data)
self.setItem(cur_row, cur_col, item)
item.setSelected(True)
else:
for data in self.clipboard_data:
item = QTableWidgetItem(data)
# if item:
# if len(item.text()) >0:
# if ask_confirmation:
# msg = QCoreApplication.translate("TableWidget", "Zelle enthält bereits Daten. Überschreiben?")
# reply = QMessageBox.question(self, QCoreApplication.translate("TableWidget", "Überschreiben"), msg, \
# QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
# if reply == QMessageBox.No:
# return False
# ask_confirmation = False
self.setItem(cur_row, col, item)
item.setSelected(True)
col += 1
def item_cut(self):
self.item_copy()
sel_idx = self.selectedIndexes()
for idx in sel_idx:
item = self.itemFromIndex(idx)
try:
item.setData(Qt.DisplayRole, None)
except AttributeError:
pass
def item_copy(self):
sel_idx = self.selectedIndexes()
sel_rows = self.selectionModel().selectedRows()
if len(sel_idx) == 1:
self.row_selected = False
self.sel_ranges = self.selectedRanges()
self.clipboard_data = []
for idx in sel_idx:
self.clipboard_data.append(idx.data())
def item_del(self):
ask_cofirmation = True
sel_idx = self.selectionModel().selectedIndexes()
for idx in sel_idx:
row = idx.row()
col = idx.column()
item = self.item(row, col)
if item:
if self.has_data(row) and ask_cofirmation:
msg = QCoreApplication.translate("TableWidget", "Delete cell content?")
reply = QMessageBox.question(self, QCoreApplication.translate("TableWidget", "Delete"), msg, \
QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
if reply == QMessageBox.No:
return False
ask_cofirmation = False
item.setData(Qt.DisplayRole, None)

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

BIN
src/img/icons8-copy-16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 663 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 751 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 B

BIN
src/img/icons8-paste-16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 777 B

View file

@ -11,27 +11,34 @@ author: Paul Salajean (p.salajean[at]gmx.de)
import sys
import os
import csv
import configparser
# Third party imports
from PySide2.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QStatusBar, QAction, QFileDialog, \
QAbstractItemView, QMenu, QMessageBox
from PySide2.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QStatusBar, QFileDialog, \
QAbstractItemView, QMenu, QMessageBox, QHBoxLayout, QVBoxLayout, QAction, QActionGroup
from PySide2.QtGui import QIcon
from PySide2.QtCore import QFile, QSize, Qt
from PySide2.QtCore import QFile, QSize, Qt, QCoreApplication, QTranslator
from PySide2.QtUiTools import QUiLoader
import xlsxwriter
# Local imports
from utils import show_about, resource_path
# Local globals
APP_VERSION = "v0.3.1"
# my own classes imports
from clsTableWidget import TableWidget
APP_NAME = "Garagenraum-Rechner"
# Local globals
APP_VERSION = "v0.4"
DIR_APPDATA = os.getenv('LOCALAPPDATA')
APP_NAME = QCoreApplication.translate("main", "Garage Space Calculator")
APP_DISPNAME = "GarageCalc"
APP_AUTHOR = "Paul Salajean"
APP_DESCR = "Berechnet zur Verfügung stehenden Garagenraum"
APP_DESCR = QCoreApplication.translate("main", "Calculates available garage space")
APP_COPYRIGHT = "(c) Paul Salajean 2021"
APP_WEBSITE = "https://gitlab.com/ProfP303"
APP_DESKTOPFILENAME = "GarageCalc"
APP_DESKTOPFILENAME = APP_DISPNAME
APP_ICON = "./img/icons8-garage-32.ico"
@ -54,24 +61,93 @@ DEFAULT_GARAGE_LENGTH = "6"
DEFAULT_GARAGE_WIDTH = "2.5"
DEFAULT_GARAGE_HEIGHT = "2.5"
TBL_STUFF_COL_COUNT = 5
TBL_STUFF_ROW_COUNT = 50
TXT_UNSAVED_CHANGES = QCoreApplication.translate("main", "There are unsaved entries. Without saving, all changes are lost. Continue anyway?")
class MyMainWindow(QMainWindow):
def __init__(self):
def __init__(self, language):
super().__init__()
self.language = language
self.is_modified = False
self.opened_file = None
self.remembered_row = None
self.load_ui()
self.init_ui()
self.set_defaults()
self.create_menu(self.language)
self.connect_signals()
self.create_actions()
self.create_toolbar()
self.create_statusbar()
self.statusBar.showMessage(f"{APP_NAME} {APP_VERSION} by {APP_AUTHOR}", 5000)
global APP_NAME
APP_NAME = qApp.translate("main", "Garage Space Calculator")
self.statusBar.showMessage(f"{APP_NAME} {APP_VERSION} - {APP_AUTHOR}", 5000)
self.calc_voluminae()
self.ui.efWeight.setText(str("0"))
self.is_modified = False
self.opened_file = None
self.remembered_row = None
self.retranslateUi()
self.ui.tableStuff.setFocus()
def create_menu(self, language=None):
menuMain = self.menuBar()
self.menuSettings = menuMain.addMenu(QCoreApplication.translate("main", "&Settings"))
self.menuLanguage = self.menuSettings.addMenu(QCoreApplication.translate("main", "Language"))
ag = QActionGroup(self, exclusive=True)
a = ag.addAction(QAction('English', self.menuSettings, checkable=True))
self.menuLanguage.addAction(a)
a = ag.addAction(QAction('Deutsch', self.menuSettings, checkable=True))
self.menuLanguage.addAction(a)
a = ag.addAction(QAction('Magyar', self.menuSettings, checkable=True))
self.menuLanguage.addAction(a)
menuMain.triggered.connect(lambda: self.store_selected_language(self.menuLanguage))
if language:
[action.setChecked(True) for action in self.menuLanguage.actions() if action.text()==language]
def retranslateUi(self):
# menus
self.menuSettings.setTitle(QCoreApplication.translate("main", "&Settings"))
self.menuLanguage.setTitle(QCoreApplication.translate("main", "Language"))
# tables
self.ui.tableGarage.setVerticalHeaderLabels([QCoreApplication.translate("main","Garage")])
self.ui.tableGarage.setHorizontalHeaderLabels([
QCoreApplication.translate("main","Length") + " [m]",
QCoreApplication.translate("main","Width") + " [m]",
QCoreApplication.translate("main","Height") + " [m]"
])
self.ui.tableStuff.setHorizontalHeaderLabels([QCoreApplication.translate("main","Stuff"),
QCoreApplication.translate("main","Length") + " [m]",
QCoreApplication.translate("main","Width") + " [m]",
QCoreApplication.translate("main","Height") + " [m]",
QCoreApplication.translate("main","Weight") + " [m]"])
# labels
self.ui.gbGarage.setTitle(QCoreApplication.translate("main","Dimension of the garage"))
self.ui.gbStuff.setTitle(QCoreApplication.translate("main", "Dimensions of the objects to be stored"))
self.ui.gbResults.setTitle(QCoreApplication.translate("main", "Result"))
self.ui.lblVol_Garage.setText(QCoreApplication.translate("main","Volume of the garage") + ":")
self.ui.lblVol_Stuff.setText(QCoreApplication.translate("main","Volume of the items") + ":")
self.ui.lblVol_Free.setText(QCoreApplication.translate("main","Free space in the garage") + ":")
self.ui.lblWeight.setText(QCoreApplication.translate("main","Total weight") + ":")
# Tooltips
self.actionNew.setToolTip(QCoreApplication.translate("main","New (Ctrl+N)"))
self.actionOpen.setToolTip(QCoreApplication.translate("main","Open... (Ctrl+O)"))
self.actionSave.setToolTip(QCoreApplication.translate("main","Save (Ctrl+S)"))
self.actionExport.setToolTip(QCoreApplication.translate("main","Export to EXCEL..."))
self.actionAbout.setToolTip(QCoreApplication.translate("main","Information about the application"))
self.actionQuit.setToolTip(QCoreApplication.translate("main","Quit the application (Strg+Q)"))
def load_ui(self):
loader = QUiLoader()
@ -81,46 +157,49 @@ class MyMainWindow(QMainWindow):
self.ui = loader.load(ui_file, self)
ui_file.close()
# self.headers = self.ui.tableStuff.horizontalHeader()
self.headers = self.ui.tableStuff.verticalHeader()
self.headers.setContextMenuPolicy(Qt.CustomContextMenu)
self.headers.customContextMenuRequested.connect(self.show_rowheader_context_menu)
self.headers.setSelectionMode(QAbstractItemView.SingleSelection)
#self.ui.tableStuff = TableWidget(self.ui.gbStuff)
self.ui.tableStuff = TableWidget()
self.ui.tableStuff.setColumnCount(TBL_STUFF_COL_COUNT)
self.ui.tableStuff.setRowCount(TBL_STUFF_ROW_COUNT)
self.ui.tableStuff.move(10, 23)
self.ui.tableStuff.resize(541,268)
# create layout
#hBox = QHBoxLayout()
#hBox.addWidget(self.ui.tableStuff)
#self.ui.tableStuff.move(10, 23)
self.ui.tableStuff.setParent(self.ui.gbStuff)
#self.ui.gbStuff.setLayout(hBox)
def create_actions(self):
self.actionNew = QAction()
self.actionNew.setIcon(QIcon(resource_path(ICON_NEW)))
self.actionNew.triggered.connect(self.file_new)
self.actionNew.setShortcut("Ctrl+N")
self.actionNew.setToolTip("Neu (Strg+N)")
self.actionOpen = QAction()
self.actionOpen.setIcon(QIcon(resource_path(ICON_OPEN)))
self.actionOpen.triggered.connect(self.file_open)
self.actionOpen.setShortcut("Ctrl+O")
self.actionOpen.setToolTip("Öffnen... (Strg+O)")
self.actionSave = QAction()
self.actionSave.setIcon(QIcon(resource_path(ICON_SAVE)))
self.actionSave.triggered.connect(self.file_save)
self.actionSave.setShortcut("Ctrl+S")
self.actionSave.setToolTip("Speichern (Strg+S)")
self.actionExport = QAction()
self.actionExport.setIcon(QIcon(resource_path(ICON_EXPORT)))
self.actionExport.triggered.connect(self.file_export)
self.actionExport.setToolTip("Export nach EXCEL...")
self.actionAbout = QAction()
self.actionAbout.setIcon(QIcon(resource_path(ICON_ABOUT)))
self.actionAbout.triggered.connect(show_about)
self.actionAbout.setToolTip("Informationen über das Programm")
self.actionQuit = QAction()
self.actionQuit.setIcon(QIcon(resource_path(ICON_QUIT)))
self.actionQuit.triggered.connect(self.app_quit)
self.actionQuit.setShortcut("Ctrl+Q")
self.actionQuit.setToolTip("Programm beenden (Strg+Q)")
def create_toolbar(self):
# Main Toolbar (for all pages/views)
@ -159,115 +238,12 @@ class MyMainWindow(QMainWindow):
tblGarage.itemChanged.connect(self.on_garage_changed)
tblStuff.itemChanged.connect(self.on_stuff_changed)
def keyPressEvent(self, event):
tblStuff = self.ui.tableStuff
modifiers = QApplication.keyboardModifiers()
key = event.key()
if modifiers == Qt.ControlModifier:
# get selected row
sel_rows_idx = tblStuff.selectionModel().selectedRows()
row = sel_rows_idx[0].row() # there is onle on row because of singleton selection mode
if key == Qt.Key_C:
self.remembered_row = row
elif key == Qt.Key_V:
self.row_insert(tblStuff, self.remembered_row, row)
if key == Qt.Key_Delete:
self.row_remove(tblStuff)
def row_remove(self, table):
# get selected row
sel_rows_idx = table.selectionModel().selectedRows()
row = sel_rows_idx[0].row() # there is onle on row because of singleton selection mode
stuff = None
item_stuff = table.item(row, COL_STUFF)
if item_stuff:
stuff = item_stuff.text()
if stuff:
msg = f"Zeile Nr. {row+1} '{stuff}' entfernen?"
else:
msg = f"Zeile Nr. {row+1} entfernen?"
reply = QMessageBox.question(self, "Zeile entfernen", msg, \
QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
if reply == QMessageBox.Yes:
table.removeRow(row)
self.calc_voluminae()
def row_insert(self, table, source_row, target_row):
# check if empty
item_stuff = table.item(target_row, COL_STUFF)
item_length = table.item(target_row, COL_LENGTH)
item_width = table.item(target_row, COL_WIDTH)
item_height = table.item(target_row, COL_HEIGHT)
item_weight = table.item(target_row, COL_WEIGHT)
if item_stuff or item_length or item_width or item_height or item_weight:
msg = "Es sind bereits Werte in dieser Zeile vorhanden. Trotzdem fortfahren?"
reply = QMessageBox.question(self, "Zeile einfügen", msg, \
QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
if reply == QMessageBox.No:
return False
item_stuff = table.item(source_row, COL_STUFF)
item_length = table.item(source_row, COL_LENGTH)
item_width = table.item(source_row, COL_WIDTH)
item_height = table.item(source_row, COL_HEIGHT)
item_weight = table.item(source_row, COL_WEIGHT)
if item_stuff:
table.setItem(target_row, COL_STUFF, QTableWidgetItem(item_stuff.text()))
if item_length:
table.setItem(target_row, COL_LENGTH, QTableWidgetItem(item_length.text()))
if item_width:
table.setItem(target_row, COL_WIDTH, QTableWidgetItem(item_width.text()))
if item_height:
table.setItem(target_row, COL_HEIGHT, QTableWidgetItem(item_height.text()))
if item_weight:
table.setItem(target_row, COL_WEIGHT, QTableWidgetItem(item_weight.text()))
def show_rowheader_context_menu(self, position):
tblStuff = self.ui.tableStuff
row = self.headers.logicalIndexAt(position)
menu = QMenu()
row_add = menu.addAction("Zeile hinzufügen")
row_remove = menu.addAction("Zeile entfernen (Entf.-Taste)")
menu.addSeparator()
row_copy = menu.addAction("Zeile kopieren (Strg+C)")
row_insert = menu.addAction("Zeile einfügen (Strg+V)")
ac = menu.exec_(tblStuff.mapToGlobal(position))
if ac == row_remove:
# tblStuff.removeRow(row)
# self.calc_voluminae()
self.row_remove(tblStuff)
elif ac == row_add:
tblStuff.insertRow(row)
elif ac == row_copy:
self.remembered_row = row
elif ac == row_insert:
self.row_insert(tblStuff, self.remembered_row, row)
def init_ui(self):
tblGarage = self.ui.tableGarage
tblStuff = self.ui.tableStuff
# clear garage
# tblGarage.clear()
tblGarage.setRowCount(0)
tblGarage.setRowCount(1)
tblGarage.setVerticalHeaderLabels(["Garage"])
# clear stuff
# tblStuff.clear()
@ -291,8 +267,8 @@ class MyMainWindow(QMainWindow):
def app_quit(self):
if self.is_modified:
msg = "Es existieen ungespeicherte Einträge. Ohne Speichern sind alle Änderungen verloren. Trotzdem fortfahren?"
reply = QMessageBox.question(self, "Beenden", msg, \
msg = QCoreApplication.translate("main", TXT_UNSAVED_CHANGES)
reply = QMessageBox.question(self, QCoreApplication.translate("main", "Quit"), msg, \
QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
if reply == QMessageBox.No:
return False
@ -300,8 +276,8 @@ class MyMainWindow(QMainWindow):
def file_new(self):
if self.is_modified:
msg = "Es wurden bereits Einträge manuell geändert. Ohne Speichern sind alle Änderungen verloren. Trotzdem fortfahren?"
reply = QMessageBox.question(self, "Neu", msg, \
msg = QCoreApplication.translate("main", TXT_UNSAVED_CHANGES)
reply = QMessageBox.question(self, QCoreApplication.translate("main", "New"), msg, \
QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
if reply == QMessageBox.No:
return False
@ -317,8 +293,12 @@ class MyMainWindow(QMainWindow):
if not self.opened_file: # if not file already open
options = QFileDialog.Options()
fileName, _ = QFileDialog.getSaveFileName(None, "Speichern", None,
"CSV-Datei (*.csv);;Alle Dateien (*)",
txt_title = QCoreApplication.translate("main", "Save")
txt_file = QCoreApplication.translate("main", "CSV-file")
txt_all_files = QCoreApplication.translate("main", "All files")
fileName, _ = QFileDialog.getSaveFileName(None, txt_title, None,
txt_file + " (*.csv);;" + txt_all_files + " (*)",
options=options)
if fileName: # if not file already open
@ -360,7 +340,7 @@ class MyMainWindow(QMainWindow):
garage_height = 0.0
if garage_length or garage_width or garage_height:
writer.writerow(["Garage", garage_length, garage_width, garage_height])
writer.writerow([QCoreApplication.translate("main","Garage"), garage_length, garage_width, garage_height])
# loop over table Stuff
for row in range(tblStuff.rowCount()):
@ -412,12 +392,13 @@ class MyMainWindow(QMainWindow):
self.is_modified = False
if is_file_saved:
self.statusBar.showMessage(f"Datei {fileName} gespeichert.", 2000)
msg = QCoreApplication.translate("main", "file") + " '" + fileName + "' " + QCoreApplication.translate("main", "saved")
self.statusBar.showMessage(msg, 2000)
def file_open(self):
if self.is_modified:
msg = "Es wurden bereits Einträge manuell geändert. Ohne Speichern sind alle Änderungen verloren. Trotzdem fortfahren?"
reply = QMessageBox.question(self, "Fortfahren?", msg, \
msg = QCoreApplication.translate("main", TXT_UNSAVED_CHANGES)
reply = QMessageBox.question(self, QCoreApplication.translate("main", "Open"), msg, \
QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
if reply == QMessageBox.No:
return False
@ -427,11 +408,12 @@ class MyMainWindow(QMainWindow):
options = QFileDialog.Options()
sTxtFilesAll = "Alle Dateien"
sTxtFiles = "CSV-Datei"
txt_title = QCoreApplication.translate("main", "Open")
txt_file = QCoreApplication.translate("main", "CSV-file")
txt_all_files = QCoreApplication.translate("main", "All files")
fileName, _ = QFileDialog.getOpenFileName(self, "Öffnen", None,
sTxtFiles + " (*.csv);;" + sTxtFilesAll + " (*)",
fileName, _ = QFileDialog.getOpenFileName(self, txt_title, None,
txt_file + " (*.csv);;" + txt_all_files + " (*)",
options=options)
if fileName:
self.init_ui()
@ -487,138 +469,140 @@ class MyMainWindow(QMainWindow):
tblGarage = self.ui.tableGarage
tblStuff = self.ui.tableStuff
options = QFileDialog.Options()
file_name, _ = QFileDialog.getSaveFileName(None, "Exportieren", None, "Excel-Datei (*.xlsx);;Alle Dateien (*)", options=options)
txt_title = QCoreApplication.translate("main", "Export")
txt_file = QCoreApplication.translate("main", "EXCEL-file")
txt_all_files = QCoreApplication.translate("main", "All files")
file_name, _ = QFileDialog.getSaveFileName(None, txt_title, None, txt_file + " (*.xlsx);;" + txt_all_files + " (*)", options=options)
if file_name:
try:
import xlsxwriter
except ModuleNotFoundError:
print(f"[{__file__}] Module 'xlsxwriter' not found!")
else:
print(f"Exporting into file -> {file_name}")
print(f"Exporting into file -> {file_name}")
workbook = xlsxwriter.Workbook(file_name)
worksheet = workbook.add_worksheet()
workbook = xlsxwriter.Workbook(file_name)
worksheet = workbook.add_worksheet()
# write col header
start_row = 0
worksheet.write(start_row, 0, "Dimension der Garage")
# write col header
start_row = 0
worksheet.write(start_row, 0, QCoreApplication.translate("main", "Dimension of the garage"))
start_row = 1
worksheet.write(start_row, COL_LENGTH, "Länge [m]")
worksheet.write(start_row, COL_WIDTH, "Breite [m]")
worksheet.write(start_row, COL_HEIGHT, "Höhe [m]")
worksheet.set_column(0, 0, 25)
worksheet.set_column(1, 3, 10)
start_row = 1
start_row = 2
# loop over table Garage
for row in range(tblGarage.rowCount()):
# get garage length
garage_length = tblGarage.item(0, 0).text()
worksheet.write(start_row, COL_LENGTH, QCoreApplication.translate("main","Length") + " [m]")
worksheet.write(start_row, COL_WIDTH, QCoreApplication.translate("main","Width") + " [m]")
worksheet.write(start_row, COL_HEIGHT, QCoreApplication.translate("main","Height") + " [m]")
worksheet.set_column(0, 0, 25)
worksheet.set_column(1, 3, 10)
start_row = 2
# loop over table Garage
for row in range(tblGarage.rowCount()):
# get garage length
garage_length = tblGarage.item(0, 0).text()
try:
garage_length = float(garage_length)
except ValueError:
garage_length = 0.0
# get garage width
garage_width = tblGarage.item(0, 1).text()
try:
garage_width = float(garage_width)
except ValueError:
garage_width = 0.0
# get garage height
garage_height = tblGarage.item(0, 2).text()
try:
garage_height = float(garage_height)
except ValueError:
garage_height = 0.0
worksheet.write(start_row + row, COL_LENGTH, garage_length)
worksheet.write(start_row + row, COL_WIDTH, garage_width)
worksheet.write(start_row + row, COL_HEIGHT, garage_height)
start_row = 4
worksheet.write(start_row, 0, QCoreApplication.translate("main", "Dimensions of the objects to be stored"))
start_row = 5
worksheet.write(start_row, COL_LENGTH, QCoreApplication.translate("main","Length") + " [m]")
worksheet.write(start_row, COL_WIDTH, QCoreApplication.translate("main","Width") + " [m]")
worksheet.write(start_row, COL_HEIGHT, QCoreApplication.translate("main","Height") + " [m]")
worksheet.write(start_row, COL_WEIGHT, QCoreApplication.translate("main","Weight") + " [kg]")
start_row = 6
# loop over table Stuff
row_idx = start_row
for row in range(tblStuff.rowCount()):
item_stuff = tblStuff.item(row, COL_STUFF)
item_length = tblStuff.item(row, COL_LENGTH)
item_width = tblStuff.item(row, COL_WIDTH)
item_height = tblStuff.item(row, COL_HEIGHT)
item_weight = tblStuff.item(row, COL_WEIGHT)
if item_stuff:
stuff_text = item_stuff.text()
if len(stuff_text)>0:
worksheet.write(start_row + row, COL_STUFF, stuff_text)
if item_length:
try:
garage_length = float(garage_length)
length = float(item_length.text())
if length:
worksheet.write(start_row + row, COL_LENGTH, length)
except ValueError:
garage_length = 0.0
pass
# get garage width
garage_width = tblGarage.item(0, 1).text()
if item_width:
try:
garage_width = float(garage_width)
width = float(item_width.text())
if width:
worksheet.write(start_row + row, COL_WIDTH, width)
except ValueError:
garage_width = 0.0
pass
# get garage height
garage_height = tblGarage.item(0, 2).text()
if item_height:
try:
garage_height = float(garage_height)
height = float(item_height.text())
if height:
worksheet.write(start_row + row, COL_HEIGHT, height)
except ValueError:
garage_height = 0.0
pass
worksheet.write(start_row + row, COL_LENGTH, garage_length)
worksheet.write(start_row + row, COL_WIDTH, garage_width)
worksheet.write(start_row + row, COL_HEIGHT, garage_height)
if item_weight:
try:
weight = float(item_weight.text())
if weight:
worksheet.write(start_row + row, COL_WEIGHT, weight)
except ValueError:
pass
start_row = 4
worksheet.write(start_row, 0, "Dimensionen der zu verstauenden Gegenstände")
if item_stuff or item_length or item_width or item_height or item_weight:
row_idx += 1
start_row = 5
worksheet.write(start_row, COL_LENGTH, "Länge [m]")
worksheet.write(start_row, COL_WIDTH, "Breite [m]")
worksheet.write(start_row, COL_HEIGHT, "Höhe [m]")
worksheet.write(start_row, COL_WEIGHT, "Gewicht [kg]")
row_idx += 1
# loop over Results
worksheet.write(row_idx, 0, QCoreApplication.translate("main","Result"))
start_row = 6
# loop over table Stuff
row_idx = start_row
for row in range(tblStuff.rowCount()):
item_stuff = tblStuff.item(row, COL_STUFF)
item_length = tblStuff.item(row, COL_LENGTH)
item_width = tblStuff.item(row, COL_WIDTH)
item_height = tblStuff.item(row, COL_HEIGHT)
item_weight = tblStuff.item(row, COL_WEIGHT)
row_idx += 1
worksheet.write(row_idx, 0, QCoreApplication.translate("main","Volume of the garage") + ":")
worksheet.write(row_idx, 1, float(self.ui.efVol_Garage.text()))
if item_stuff:
stuff_text = item_stuff.text()
if len(stuff_text)>0:
worksheet.write(start_row + row, COL_STUFF, stuff_text)
row_idx += 1
worksheet.write(row_idx, 0, QCoreApplication.translate("main","Volume of the items") + ":")
worksheet.write(row_idx, 1, float(self.ui.efVol_Stuff.text()))
if item_length:
try:
length = float(item_length.text())
if length:
worksheet.write(start_row + row, COL_LENGTH, length)
except ValueError:
pass
row_idx += 1
worksheet.write(row_idx, 0, QCoreApplication.translate("main","Free space in the garage") + ":")
worksheet.write(row_idx, 1, float(self.ui.efVol_Free.text()))
if item_width:
try:
width = float(item_width.text())
if width:
worksheet.write(start_row + row, COL_WIDTH, width)
except ValueError:
pass
row_idx += 1
worksheet.write(row_idx, 0, QCoreApplication.translate("main", "Total weight") + ":")
worksheet.write(row_idx, 1, float(self.ui.efWeight.text()))
if item_height:
try:
height = float(item_height.text())
if height:
worksheet.write(start_row + row, COL_HEIGHT, height)
except ValueError:
pass
if item_weight:
try:
weight = float(item_weight.text())
if weight:
worksheet.write(start_row + row, COL_WEIGHT, weight)
except ValueError:
pass
if item_stuff or item_length or item_width or item_height or item_weight:
row_idx += 1
row_idx += 1
# loop over Results
worksheet.write(row_idx, 0, "Ergebnis")
row_idx += 1
worksheet.write(row_idx, 0, "Volumen der Garage:")
worksheet.write(row_idx, 1, float(self.ui.efVol_Garage.text()))
row_idx += 1
worksheet.write(row_idx, 0, "Volumen der Gegenstände:")
worksheet.write(row_idx, 1, float(self.ui.efVol_Stuff.text()))
row_idx += 1
worksheet.write(row_idx, 0, "Freier Raum")
worksheet.write(row_idx, 1, float(self.ui.efVol_Free.text()))
row_idx += 1
worksheet.write(row_idx, 0, "Gesamtgewicht")
worksheet.write(row_idx, 1, float(self.ui.efWeight.text()))
workbook.close()
self.statusBar.showMessage(f"Erfolgreich nach EXCEL exportiert.", 5000)
workbook.close()
msg = QCoreApplication.translate("main", "Successfully exported to EXCEL") + " :-)"
self.statusBar.showMessage(msg, 5000)
def on_garage_changed(self):
self.is_modified = True
@ -670,8 +654,8 @@ class MyMainWindow(QMainWindow):
if not is_error:
garage_vol = round(float(garage_length) * float(garage_width) * float(garage_height), 2)
else:
garage_vol = 0.0
self.statusBar.showMessage("Fehler in der Garagen-Dimension. :-(", 5000)
msg = QCoreApplication.translate("main", "Error in the garage dimension") + " :-("
self.statusBar.showMessage(msg, 5000)
return garage_vol
@ -722,8 +706,9 @@ class MyMainWindow(QMainWindow):
stuff_vol = stuff_vol + vol
if is_error:
stuff_vol = 0.0
self.statusBar.showMessage("Fehler in den Dimensionen der zu verstauenden Gegenstände :-(", 5000)
# stuff_vol = 0.0
msg = QCoreApplication.translate("main", "Error in the dimensions of the objects to be stored") + " :-("
self.statusBar.showMessage(msg, 5000)
return stuff_vol
@ -732,11 +717,9 @@ class MyMainWindow(QMainWindow):
# get garage vol
garage_vol = self.get_garage_vol()
print("garage_vol", garage_vol)
# get stuff vol
stuff_vol = self.get_stuff_vol()
print("stuff_vol", stuff_vol)
# display results
self.ui.efVol_Garage.setText(f"{garage_vol:2.2f}")
@ -768,6 +751,36 @@ class MyMainWindow(QMainWindow):
self.ui.efWeight.setText(f"{weight_sum:2.2f}")
def store_selected_language(self, menu):
""" Stores selected menu labels to ini-file. """
# [print(action.text()) for action in menu.actions() if action.isChecked()]
print("Current dir:", os.getcwd())
language = "English"
for action in menu.actions():
if action.isChecked():
language = action.text()
config['DEFAULT']['language'] = language
if not os.path.exists(os.path.join(DIR_APPDATA, APP_DISPNAME)):
os.makedirs(os.path.join(DIR_APPDATA, APP_DISPNAME))
with open(os.path.join(DIR_APPDATA, APP_DISPNAME, APP_DISPNAME + '.ini'), 'w') as configfile: # save
config.write(configfile)
if language == "Deutsch":
print("Loading german language file.")
translator.load(resource_path('./i18n/de_DE'))
elif language == "Magyar":
print("Loading hungarian langauge file.")
translator.load(resource_path('./i18n/hu_HU'))
else:
#qApp.removeTranslator(translator)
translator.load("dummy")
print(f"Unknown language setting '{language}' -> defaulting to english language.")
self.retranslateUi()
if __name__ == "__main__":
qApp = QApplication([])
@ -781,8 +794,38 @@ if __name__ == "__main__":
qApp.setWindowIcon(QIcon(APP_ICON))
qApp.setDesktopFileName(APP_DESKTOPFILENAME)
winMain = MyMainWindow()
winMain.setFixedWidth(600)
winMain.setFixedHeight(620)
config = configparser.ConfigParser()
language = "Deutsch"
if os.path.exists(os.path.join(DIR_APPDATA, APP_DISPNAME, APP_DISPNAME + '.ini')):
config.read(os.path.join(DIR_APPDATA, APP_DISPNAME, APP_DISPNAME + '.ini'))
language = config['DEFAULT']['language']
else:
config['DEFAULT']['language'] = language
if not os.path.exists(os.path.join(DIR_APPDATA, APP_DISPNAME)):
os.makedirs(os.path.join(DIR_APPDATA, APP_DISPNAME))
with open(os.path.join(DIR_APPDATA, APP_DISPNAME, APP_DISPNAME + '.ini'), 'w') as configfile: # save
config.write(configfile)
translator = QTranslator()
print("Current dir:", os.getcwd())
if language == "Deutsch":
print("Loading german language file.")
translator.load(resource_path('./i18n/de_DE'))
elif language == "Magyar":
print("Loading hungarian langauge file.")
translator.load(resource_path('./i18n/hu_HU'))
else:
print(f"Unknown language setting '{language}' -> defaulting to english language.")
qApp.installTranslator(translator)
winMain = MyMainWindow(language)
# winMain.setWidth(600)
# winMain.setHeight(625)
winMain.resize(610, 640)
winMain.show()
sys.exit(qApp.exec_())

View file

@ -34,18 +34,21 @@ def show_about():
msg = QMessageBox()
msg.setIconPixmap(QPixmap(resource_path(APP_ICON)))
APP_NAME = qApp.translate("main", "Garage Space Calculator")
APP_DESCR = qApp.translate("main", "Calculates available garage space")
text = "<p align='center'><h1>" + qApp.applicationDisplayName() + " " + \
"<br>" + qApp.applicationVersion() + "</h1>" + \
"<br>" + qApp.applicationName() + "<br>" + \
"<br>" + qApp.description + "<br>" + \
"<br>" + "Idee von: Balazs Fabian" + "<br>" + \
"<br>" + APP_NAME + "<br>" + \
"<br>" + APP_DESCR + "<br>" + \
"<br>" + qApp.translate("utils", "Idea") + ": Balazs Fabian" + "<br>" + \
"<br>" + qApp.copyright + "<br>" \
"<br> <a href='" + qApp.website + "'>" + qApp.website + "</a></p>"
text = text + "<p align='center'>Used icons: Theme 'Cute Color' from <a href='https://icons8.com/'>Icons8</a></p>"
text = text + "<p align='center'>Python version: " + f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro} {sys.version_info.releaselevel}"
text = text + "<p align='center'>" + qApp.translate("utils", "Used icons: Theme") + " 'Cute Color' " + qApp.translate("utils", "from") + " <a href='https://icons8.com/'>Icons8</a></p>"
text = text + "<p align='center'>Python " + qApp.translate("utils", "Version") + ": " + f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro} {sys.version_info.releaselevel}"
text = text + "<br>" + f"{sys.executable}" + "<br>"
text = text + "<br>Qt version: " + f"{QtCore.__version__}"
text = text + "<br>Qt " + qApp.translate("utils", "Version") + ": " + f"{QtCore.__version__}"
msg.setText(text)
msg.setWindowTitle("About")