FYjE{ap)PDnIYJVik-$9ur1HZ>9^Rr__eUDQ1Z(k!So}uhN
z?!mf$)8xa?60Q0v-F@_RqJly9{Qnnt{|YTGy@>by^wzsSf&96y^K=FD4y|h3JxH|r
zcir2bJ`TLsx(_}fq4ZSuI}iN}?;kYo>wSr+=e%)b7`SxCI5~e9_p`>EKR!j2n=t2%vRu@$o}8~*h$x9
zAHMxda6~=(r}JOO`g?Qhp9X%mo*Vz|dEgz+9eM+Ljc0nTy+e5a>)sEmd-497{PW-Z
z5A1v+|I1@1Vdu~DuP;KLewBao@F4JB%71*_w_$IkZ}!q3LGSiH=jd+8pXqyH>C3SH
zhlN+(_kp{$aCG(^$PX8eKUu{3mscM=@*ec&i{E?kap?K9XrF)|47+&p&`q%W@&4ks
z5U9{@;K16!e$+&pimg6>
z)@9Je>%SUbPl8NbKJwrLng>Fiu{27KQH19%q#_l8v)#+fkiexCX||x=5HH{8(Up|Fs(o~{8X%MbTi_>5wYRdDSRvy8yBnv
z?j-Kn5~<=9gse6Gz%Iv^p7NeBYk~Aqb!>$WK{a4Fus*^MQZ?|ZD6W^pG)&2w>!rJV
zE!~nvRTItJY5Et4)}|Cu#R2TXJY`=*`Pr+WE|@Sw%2)w5HjG_X`DW9*>c3B>W|X~4
zHr)AiYc?UkaY@L53?rsf%7<7NGpk2bz`JR+b`jrE>TDb_?Ml-&1L+HM-n49PlcH{VW?c$@
z&a8AW3UeurD!}Zt(u>xsU3b|It05iVavkB;L@?dPOxky&%1q8l581%YiJi*4T@*T+
z8!QW`2@MDfp2jrA3UZUy<+qi&Q!}y>_##XLKR}UIld1=4l=dSYqcoNhkNoKVkX!~h{%+V!WZPO+L)ugb?vCpFNPBUA=o#A0miu)jG?Yf7mINQ&u!8%r?3k91=iJq5DzFW#uc%~+`r*c14z|078E{#f
zQ!a)Su55E|&bBJ*Y0@cq8YgZyHqC3wxiQnJH_=^^OV=QOnF9B^kMNzaa!fk)U^*#a
z&|5U4QM<>b8qOl8t>yQyXftX&Kn!i#0ybA^i2@|V=8?d&w~SwvgdT*yc?5Jo-h!~2
z)3l(mdrmq@fh(1r+^EBC5mR7?=G`&P0}OyvZfW1$p}nYjJ`ZDa+|eVwdzw~9q;I-N
zq}416t6MNIDCvtmF-990x-*nwb2;$pTlRF&8$iwSCR0_-7%tKTF+TWByMtmu`I3jM
zge_$=oHL?$4aFCBa4pBUu4d7e>&hM6@@h!&5W0v}rW`bDwPd`$gSKIz2BfltXI|dL
zWk-kNS+Ju&X>V28Vcq
z=Ti)iA>6(AIgHalgOje^Y{>R-kk;xqwe0DwVC*UP)H`;(p_WDR03x`Ml
zdVzdusJ
+
+
+
+ TableWidget
+
+
+
+ Vágd ki
+
+
+
+
+ Vettem
+
+
+
+
+ Beillesztés
+
+
+
+
+ Törölje
+
+
+
+
+ Vágott vonal
+
+
+
+
+ Vettem a szöveget
+
+
+
+
+ Beilleszteni a sort
+
+
+
+
+ A fenti sort beilleszteni
+
+
+
+
+ Az alábbi sor beillesztése
+
+
+
+
+ Távolítsa el a sort
+
+
+
+
+ Tartalom törlése
+
+
+
+
+ Vonalszám.
+
+
+
+
+ eltávolítani?
+
+
+
+
+ A eltávolítása
+
+
+
+
+ Cellatartalom törlése?
+
+
+
+ main
+
+
+
+ Hallo Welt
+
+
+
+
+ &Beállítások
+
+
+
+
+ Nyelv
+
+
+
+
+ Tárgy
+
+
+
+
+ Hosszúság
+
+
+
+
+ Szélesség
+
+
+
+
+ Magasság
+
+
+
+
+ Súly
+
+
+
+
+ A garázs mérete
+
+
+
+
+ A tárolandó objektumok méretei
+
+
+
+
+ Eredmény
+
+
+
+
+ A garázs térfogata
+
+
+
+
+ A tételek mennyisége
+
+
+
+
+ Szabad hely a garázsban
+
+
+
+
+ Teljes súly
+
+
+
+
+ Új (Ctrl+N)
+
+
+
+
+ Nyissa ki (Ctrl+O)
+
+
+
+
+ Mentés (Ctrl+S)
+
+
+
+
+ Exportálás EXCEL-be...
+
+
+
+
+ Az alkalmazással kapcsolatos információk
+
+
+
+
+ Az alkalmazás kilépése (Ctrl+Q)
+
+
+
+
+ Garázs
+
+
+
+
+ Kilépés
+
+
+
+
+ Új
+
+
+
+
+ Mentés
+
+
+
+
+ CSV-fájl
+
+
+
+
+ Minden fájl
+
+
+
+
+ fájl
+
+
+
+
+ mentett
+
+
+
+
+ Megnyitott
+
+
+
+
+ Exportálás
+
+
+
+
+ EXCEL-fájl
+
+
+
+
+ Hiba a garázs dimenziójában
+
+
+
+
+ Hiba a tárolandó objektumok méreteiben
+
+
+
+
+ Sikeresen exportált EXCEL-be
+
+
+
+
+ CSV-fájl
+
+
+
+
+ EXCEL-fájl
+
+
+
+
+ Vannak mentetlen bejegyzések. Mentés nélkül minden módosítás elveszik. Folytassa mégis?
+
+
+
+
+ Garázs hely kalkulátor
+
+
+
+
+ Kiszámítja a rendelkezésre álló garázshelyet
+
+
+
+ utils
+
+
+
+ Ötlet
+
+
+
+
+ Használt ikonok: Téma
+
+
+
+
+ a weboldalról
+
+
+
+
+ Verzió
+
+
+
diff --git a/requirements.txt b/requirements.txt
index e190d6a..ff357c2 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,4 @@
# project: GarageCalc1
# file: requirements.txt
-wheel
-pyside2==5.15.2
-XlsxWriter==1.3.8
+pyside2
+xlsxwriter
diff --git a/scripts/pyinstaller_v2.cmd b/scripts/pyinstaller_v2.cmd
index da1ed72..5892f60 100644
--- a/scripts/pyinstaller_v2.cmd
+++ b/scripts/pyinstaller_v2.cmd
@@ -1,36 +1,36 @@
@ECHO OFF
:: --------------------------------------------------------------------------------------------------------------------------------------
-:: project: GarageCalc1 Window-Exe Generator
-:: summary: create a GarageCalc1-executable for Windows (version with no-console-windows as well as version with console windows for traces)
+:: project: GarageCalc Window-Exe Generator
+:: summary: create a GarageCalc-executable for Windows (version with no-console-windows as well as version with console windows for traces)
:: file: pyinstaller.cmd
:: date: version author
:: 2021-06-27 1 paul salajean
:: --------------------------------------------------------------------------------------------------------------------------------------
-SET version="v0.1"
+SET version="v0.4"
SET release_dir="D:\Temp\Prog\ownCloud\profp@uberspace\transfer"
SET prev_dir=%cd%
-SET reinstall_venv="true"
+SET reinstall_venv="false"
SET do_zip="false"
CD ..
-ECHO Creating GarageCalc1 Windows.exe-version in folder %cd%\dist
+ECHO Creating GarageCalc Windows.exe-version in folder %cd%\dist
PAUSE
REM pyinstaller --noconfirm --log-level=ERROR ^
REM --onedir --nowindow ^
REM --add-data="README;." ^
REM --add-data="image1.png;img" ^
REM --add-data="img;doc;ui" ^
-REM --add-data="LICENSE.txt;changelog.md;GarageCalc1.bat" ^
+REM --add-data="LICENSE.txt;changelog.md;GarageCalc.bat" ^
REM --add-binary="libfoo.so;lib" ^
REM --hidden-import=secret1 ^
REM --hidden-import=secret2 ^
-REM --icon=.\img\GarageCalc1.ico ^
+REM --icon=.\img\GarageCalc.ico ^
REM --debug=imports ^
REM --key=N0T1me40pp0ssum5
REM --paths=.\src ^
-REM GarageCalc1.spec
+REM GarageCalc.spec
REM The key-string is a string of 16 characters which is used to encrypt each file of Python byte-code before it is stored in the archive inside the executable file.
REM This feature uses the "tinyaes" module internally for the encryption.
REM
@@ -55,19 +55,21 @@ python -m pip install -r requirements.txt
:PYINSTALL
IF %reinstall_venv%=="false" CALL .\env2\Scripts\activate.bat
ECHO Running "pyinstaller"...
-REM pyinstaller .\main.py --name=GarageCalc1 --noconfirm --console --clean --onedir --log-level=ERROR --hidden-import=PySide2.QtXml --icon=.\img\GarageCalc1.ico --add-data="LICENSE;." --add-data="README.md;." --add-data="changelog.md;." --add-data="*.ui;." --add-data="img;.\img"
-pyinstaller .\src\main.py --name=GarageCalc1 --noconfirm --windowed --clean --onefile --log-level=ERROR --hidden-import=PySide2.QtXml ^
+REM pyinstaller .\main.py --name=GarageCalc --noconfirm --console --clean --onedir --log-level=ERROR --hidden-import=PySide2.QtXml --icon=.\img\GarageCalc.ico --add-data="LICENSE;." --add-data="README.md;." --add-data="changelog.md;." --add-data="*.ui;." --add-data="img;.\img"
+REM --windowed
+pyinstaller .\src\main.py --name=GarageCalc --noconfirm --windowed --clean --onefile --log-level=ERROR --hidden-import=PySide2.QtXml ^
--icon=.\img\icons8-garage-32.ico ^
--add-data="*.txt;." ^
--add-data="*.md;." ^
--add-data="ui;.\ui" ^
+ --add-data="i18n;.\i18n" ^
--add-data="img;.\img"
-::MOVE .\dist\GarageCalc1\*.md .\dist\
-::MOVE .\dist\GarageCalc1\LICENSE .\dist\
+::MOVE .\dist\GarageCalc\*.md .\dist\
+::MOVE .\dist\GarageCalc\LICENSE .\dist\
::clean-up img-folder
-::MOVE .\dist\GarageCalc1\img .\dist\img>NUL
+::MOVE .\dist\GarageCalc\img .\dist\img>NUL
::Remove temp dir and files
DEL /Q *.spec>NUL
@@ -81,7 +83,7 @@ IF %do_zip%=="false" GOTO END
::-mx5 = This is default (compression is normal).
::-mx7 = Maximum compression.
::-mx9 = Ultra compression.
-"C:\Program Files\7-zip\7z.exe" a %release_dir%\GarageCalc1_%version%_portable.exe -mx9 -sfx7z.sfx .\dist\*
+"C:\Program Files\7-zip\7z.exe" a %release_dir%\GarageCalc_%version%_portable.exe -mx9 -sfx7z.sfx .\dist\*
::Disable Virtual env
CALL .\env2\Scripts\deactivate.bat
diff --git a/scripts/update_ts_files.cmd b/scripts/update_ts_files.cmd
new file mode 100644
index 0000000..71dfb33
--- /dev/null
+++ b/scripts/update_ts_files.cmd
@@ -0,0 +1,22 @@
+@ECHO OFF
+:: --------------------------------------------------------------------------------------------------------------------------------------
+:: project: GarageCalc
+:: summary: Update or create GarageCalc ts-files
+:: file: update_ts_files.cmd
+:: date: version author
+:: 2021-06-30 1 paul salajean
+:: --------------------------------------------------------------------------------------------------------------------------------------
+SET prev_dir=%cd%
+
+CD ..
+
+mkdir .\i18n
+
+pyside2-lupdate -verbose .\src\main.py .\src\utils.py .\src\clsTableWidget.py -ts .\i18n\de_DE.ts
+pyside2-lupdate -verbose .\src\main.py .\src\utils.py .\src\clsTableWidget.py -ts .\i18n\hu_HU.ts
+
+:END
+CD %prev_dir%
+ECHO Done.
+
+PAUSE
diff --git a/src/clsTableWidget.py b/src/clsTableWidget.py
new file mode 100644
index 0000000..98c5bb4
--- /dev/null
+++ b/src/clsTableWidget.py
@@ -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)
diff --git a/src/img/icons8-add-row-16.png b/src/img/icons8-add-row-16.png
new file mode 100644
index 0000000000000000000000000000000000000000..df7f82193320ee4486fc83f7844fce7f60120dd3
GIT binary patch
literal 447
zcmV;w0YLtVP)Eu|J?_O@s!O6zxj_8_KV==NI~Z`d)*Gm0Ce-XFHd3&%O6t;2-2*_dLnl
zOj5T{sj-SmsOeYD1-0GD49sq!R5qV~_GZS4Am%KyEJB>k{zY3=*01!^s
zvsIK21c1Wu9jBdL$Zs|t2o3;voB4B91L%DM?Ro}^)&`9f0na=jNqq)%kSlpeplnT}
zIH$m{AfV{40XHF_#rm{VQ&pm5UwgydF1cOJplR=%<&{REQJ_4>kQ
pOSejNm=t7oy0O1@Jxu#2yaUF?iW?7PB<
zg9)*Nn}huuj4Vdulc|F1{{jRRbUt=BtLt@&F!$xR5oT!CsnAj%&VdT`mFuDI|vPH~<7*
z(0+aQG42Fj&~6sp93x~IA=@mvxfsDD;^yp$lKuezFf+9kBjART6w$~
zChHVT)+tn+d@n{2hJ(ia+0_gwW@*h#g?%|_06=NK6i!M!u|5F@XNriIVmfC40000<
KMNUMnLSTYD;2p6`6;
zyBsd?zdOyO0gqXQwqB$O!;=I=+$`2=tq>(%0J?{)OndTL1+L0N@Sh
zK$#%%62V})mf^KZN*Cp^L^v{t-fuyb^YBLpL7srA?<5VDrk5U-dd$5vB?INi!2N8(
z8ybLV{O+2CFf8AF)^fXB(;LnK0K(Tbs5^O3;3o|x=O1o;)0nCo@%?y14rV~UgsyFa
zwMG1)0l#!LVITqE?Rxc7`R0A{D71j`7;@fUqDcfRjC
z=L$rE!Q%Pk>_f2G8_iozBCUyolfuq}`%mv}N8e-={Bmk;zQy6O%=n0?jHGGe%1~cb
zs&s(i4ws~J=l%T34FJ=jg=nbbBIM_f7##Gg5=p|an*r7!>423FXs*O&5cPbxu!N)?
zVEF@($vO~Zfpq|q4z%(h>;~A$WVUV#wSndOTwK21^-nf5h!W7s16V_74c1D<8d$d7
zoU*IauC3tsAi&0I0fHo~1fjb(jqR-x2CntREK`+9SYE)er3je?2_%vZEL#9tn_Si9%Xf~0}cCWEAdgTfIuR`(#t
z42#cQ%)!mIKvgQ`Sc9Yd&cw>Aw^Eog-QS%WWaXJ{xdya%U#er&l`;a~JFVTt{{@S$
z-|c5R(`SS*003@h_4gj`o`SUxt$ZBqmh!`QM|wg9F$N93Fwj%S-0E6Tf0geQ*8P};
xXzb;SQ?oCYZboxTvHJDX`&PUEF8K?!^B=gM*#P^Pc4`0s002ovPDHLkV1jK;Iqv`f
literal 0
HcmV?d00001
diff --git a/src/img/icons8-delete-16.png b/src/img/icons8-delete-16.png
new file mode 100644
index 0000000000000000000000000000000000000000..c57ba92bb2b529536d3d5e49dce0c276a0f7ed44
GIT binary patch
literal 751
zcmV2Y-=Hgq|k&+G4J#oXfT!9vG^l8{I-S=c1+
zBQN+oLA9KP)to}V8b_w;zIi7!;KY2ev<)DqLUZZEgoT+mOSW6m)!~0f3GTea-P8iI
z`rmscSh7T;eNzIE#W&$Uqr-OCnAHp`tLnkfMD1+jYy4aPgE2(FMB2i2ppewU}0H7l(21YYBxiukApSi)~0lHv1i3TICoH+CP&vkxN+_e~a
zV4+7UB#c2xLy!;@vo@`(1D-r_%!fDZ*nW7=MVL;aK$uf6PPGWsqlRUbjuo9grLu)r
zl+@Q7ys$!D7;yKl8+enIo!bxZy*P8+51G4gwD+%h^TkP(h%!*kpFR|1a^jKU+f0fi%&jorvJl+-H$(^7_w%bDK3U`t5
zgo}ukN3I8Y-UqhM2!GqGl-fdx`dX7(q=PcQ1Z%|sWJOK&g;VEChd#b|wZ3o8LeDP*fm8W2-!S~2@KZcZ$ue|Y}o_T_Zd|m
zj`**2H*Q2J7K`jvO_fbgh#hMq)6koBpmY=Bgo^t4S$vKyD^$(gyxQ%Rw%(0qD2BtI
zW;wuNY&eE=QU+r@FPSBU&1+-JmwjE{r-i8z0C>|D7&xe`Hj>v
z^tC+O?q@c<23w`)hcfadcY})n1gj&{_^C5S!&%za+}HeiJ8>QW0A99Aw+Uw#wN`^A
z9ZSXIRQ#rJ$N<1OiQj$L)O+vNV28ljaQmYx<2yljRet~=v+Hw9x>+;;00008!0#Ou(-+N~!4H1LFEHH#tZ7Ny>^%sJujr+i*Mo4Z0
zgBFG0qSo1Oh&Dm{KxmQCA}WyV;x#iW_&G#X>-DCCj#LcP6P^WtNFk1ld0l*z2Ne;wRifV&wZ1LL9T
zk?!WdT)ao=q8O9`psMPy%JmjNQ?2O0~m59PBk$5`X;F2)NYS}<05hF6?n%|qfJIQa|
z=JNeEQRvTxxds4>n~Qq0K-bN+tAnF163hhvOrTWrd$XTS_G7&O*6f=jbfHvp00000
LNkvXXu0mjfahun(
literal 0
HcmV?d00001
diff --git a/src/img/icons8-paste-16.png b/src/img/icons8-paste-16.png
new file mode 100644
index 0000000000000000000000000000000000000000..0e3db7da518e8bdbf0de89492b4c5f15214c0c5a
GIT binary patch
literal 612
zcmV-q0-ODbP)MaWVYK}Ve&Iw=S$>fq$&Dx#!?U2K3b4D|*|_&;?hJqt0lXNtpH``I-Qbun@G}xWBm0|AW~{3JIDqgopC7D>W2fW-Q7T)sX<`A@Cyc_VSO4rsR&VbD|p9S4wu0Fi{U5mF(f
zLKC1&hcIX(keHU09QuVw{l-a(;7o2a$?}ZGPn|2n4npVk~6UoBmM^t!WL6M3yS*bzz1qoghQqVqJA5&)p5VK9@^bmx8XfJ`$lh
zRZ$=w6<@bGPS5?#3;=+euT?&4xM(Z#zFjOd%tQ*KeqLbG*{_UAzYQY{6ib&lo19##
zr7!>h0+eVSI^%QaM5g0qo8v_tUo(+K0-lz`r*dwEhqwyI3xQ8K5@i~g(~Ii<8-`w$4M5%}oc
zlo1pHYZ5A&@3>jdCq+IOY!7*YK7zoi@5}ntmhP%|sQ^C#n-L^hoGSGs00000NkvXX
Hu0mjfL%&vX
literal 0
HcmV?d00001
diff --git a/src/main.py b/src/main.py
index 7ca07de..de26027 100644
--- a/src/main.py
+++ b/src/main.py
@@ -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_())
diff --git a/src/utils.py b/src/utils.py
index ec0dcfc..9d008bb 100644
--- a/src/utils.py
+++ b/src/utils.py
@@ -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 = "" + qApp.applicationDisplayName() + " " + \
"
" + qApp.applicationVersion() + "
" + \
- "
" + qApp.applicationName() + "
" + \
- "
" + qApp.description + "
" + \
- "
" + "Idee von: Balazs Fabian" + "
" + \
+ "
" + APP_NAME + "
" + \
+ "
" + APP_DESCR + "
" + \
+ "
" + qApp.translate("utils", "Idea") + ": Balazs Fabian" + "
" + \
"
" + qApp.copyright + "
" \
"
" + qApp.website + "
"
- text = text + "Used icons: Theme 'Cute Color' from Icons8
"
- text = text + "Python version: " + f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro} {sys.version_info.releaselevel}"
+ text = text + "
" + qApp.translate("utils", "Used icons: Theme") + " 'Cute Color' " + qApp.translate("utils", "from") + " Icons8
"
+ text = text + "Python " + qApp.translate("utils", "Version") + ": " + f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro} {sys.version_info.releaselevel}"
text = text + "
" + f"{sys.executable}" + "
"
- text = text + "
Qt version: " + f"{QtCore.__version__}"
+ text = text + "
Qt " + qApp.translate("utils", "Version") + ": " + f"{QtCore.__version__}"
msg.setText(text)
msg.setWindowTitle("About")
diff --git a/ui/main.ui b/ui/main.ui
index c799198..85b7d1d 100644
--- a/ui/main.ui
+++ b/ui/main.ui
@@ -64,7 +64,7 @@
- Freier Raum i. d. Garage:
+ Freier Raum in der Garage:
@@ -183,7 +183,7 @@
kg
-
+
10
@@ -212,52 +212,7 @@
true
-
- -
-
-
-
- 0
- 0
-
-
-
- true
-
-
- QAbstractItemView::SingleSelection
-
-
- QAbstractItemView::SelectRows
-
-
-
- Gegenstand
-
-
-
-
- Länge [m]
-
-
-
-
- Breite [m]
-
-
-
-
- Höhe [m]
-
-
-
-
- Gewicht [kg]
-
-
-
-
-
+
@@ -326,7 +281,6 @@
tableGarage
- tableStuff
efVol_Garage
efVol_Stuff
efVol_Free