first re-commit.

This commit is contained in:
2025-08-05 22:37:51 +02:00
commit 5295a82aa3
109 changed files with 9928 additions and 0 deletions

View File

@@ -0,0 +1,468 @@
/***************************************************************************
libMiniCash
Copyright © 2013-2018 christoph holzheuer
c.holzheuer@sourceworx.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
***************************************************************************/
#include <QtGui>
#include <QWidget>
#include <QMessageBox>
#include <QShortcut>
#include <QInputDialog>
#include <QDir>
#include <QPalette>
#include <QApplication>
#include <mcmainwindowbase.h>
#include <mcbillingview.h>
/// Für den Test auf CapsLock
///#include "Windows.h"
/*
* bool QMyClass::checkCapsLock()
{
// platform dependent method of determining if CAPS LOCK is on
#ifdef Q_OS_WIN32 // MS Windows version
return GetKeyState(VK_CAPITAL) == 1;
#else // X11 version (Linux/Unix/Mac OS X/etc...)
Display * d = XOpenDisplay((char*)0);
bool caps_state = false;
if (d)
{
unsigned n;
XkbGetIndicatorState(d, XkbUseCoreKbd, &n);
caps_state = (n & 0x01) == 1;
}
return caps_state;
#endif
}
*/
/**
* @brief Der Konstruktor, die Initialisierungen des GUI
* und der Netzverbindung werden in den Unterklassen vorgenommen.
*/
MCMainWindowBase::MCMainWindowBase( QWidget* parent )
: QMainWindow( parent )
{
/// model setzen
_salesModel.setParent( this );
}
/**
* @brief MCMainWindowBase::~MCMainWindowBase !
*/
MCMainWindowBase::~MCMainWindowBase()
{
}
/**
* @brief MCMainWindowBase::transCount !
* @return
*/
QString MCMainWindowBase::transCount()
{
return MCSalesModel::formatInt( _transCount );
}
/**
* @brief Dateipfad anhand der Vorgaben aus dem Setup-Dialog erzeugen.
* @param key settingskey
*
* Dateipfad anhand der Vorgaben aus den settings zusammenbasteln, Hilfsfunktion
*
* @return pfad
*/
QString MCMainWindowBase::fetchSetting( const QString& key )
{
return _mainSettings.value( key ).toString();
}
/**
* @brief Datei-Fehlermeldung anzeigen: Meistens sind einfach die Pfadeinstellungen falsch.
* @param filename
* @param errormsg
*
* Conveniencefunction zur vereinfachten Handhabung von Dateifehlern,
* errortxt holen, Messagebox erzeugen etc.
* @return immer false
*/
bool MCMainWindowBase::showFileError( const QString& filename, const QString& errormsg )
{
QString msg( "Datei '%0' konnte nicht geöffnet werden.\nFehlercode: %1" );
/// je schlimmer je geiler
QMessageBox::critical( this, "Fehler", msg.arg( filename, errormsg ) );
return false;
}
/**
* @brief Dateien & Settings initialisieren
*
* Wird direkt beim Programmstart aufgerufen, setzt die Vorgabewerte
* und erzeugt die Arbeitsdateien.
*
* @see setupDataFile
*
*/
void MCMainWindowBase::setupDefaults()
{
/// leer? dann defaults reinschreiben
if( !_mainSettings.contains( miniCash::keyMobileDrive) )
{
_mainSettings.setValue( miniCash::keyMobileDrive, miniCash::mobileDrive );
_mainSettings.setValue( miniCash::keyProfit, miniCash::profit );
_mainSettings.setValue( miniCash::keySelfID, miniCash::selfID );
_mainSettings.setValue( miniCash::keyFooterText, "" );
}
/// solange Setup-Dialog zeigen bis die Arbeitsfiles
/// nutzbar sind
bool allfine = false;
while( !allfine )
{
allfine = setupDataFile();
if( !allfine )
{
QString msg( "Die lokale Arbeitsdatei konnte nicht angelegt werden.\nBitte die Programmeinstellungen überprüfen." );
QMessageBox::critical( this, "Dateifehler", msg );
setupDataFile();
}
}
}
/**
* @brief Kassendateien öffnen oder erzeugen
*
* Hier werden die beiden Arbeitsdateien geöffnet bzw. erzeugt: es
* wird entschieden, ob ein zum heutigen Datum (also Freitag oder Samstag)
* ein passender Kleidermarkt vorhanden ist.
* Falls nicht, wird eine Kassendatei fürs heutige Datum angelegt.
*/
bool MCMainWindowBase::setupDataFile()
{
/// step 1: Filenamen aus Datum bauen, hack: wir nehmen immer den Freitag
QDate date = QDate::currentDate();
/// Hack: Am Samstag schalten wir auf Freitag
if( date.dayOfWeek() == 6 )
date = date.addDays( -1 );
/// Filenames aus Datum
_dataFileName = date.toString( "MM-dd-yyyy" ) + miniCash::filetype;
QString dirName = QDir::homePath() + miniCash::dataDir;
QDir dir( dirName );
if( !dir.exists() )
dir.mkpath( dirName );
_dataFilePath = dirName + _dataFileName;
/// erstmal alles auf Anfang
_transCount = 1;
/// Ist das File schon vorhanden ? Sonst anlegen
QFile datafile( _dataFilePath );
if( !datafile.exists() )
{
/// hats auch wirklich geklappt?
if( !datafile.open( QIODevice::WriteOnly ) )
/// wenn schon der start misslingt, hat
/// nichts mehr einen sinn
return showFileError( _dataFilePath, datafile.errorString() );
_mainSettings.setValue( miniCash::keyTransCount, "1" );
}
/// Zählerstand lesen.
_transCount = _mainSettings.value( miniCash::keyTransCount ).toInt();
return true;
}
/**
* @brief Speichert die Transaktionsdaten in eine Datei, hier Stick und Festplatte
* @param filename Zieldatei
* @param result die Verkaufstransaktion
*
* Verkaufte Artikel auf Platte oder Stick sichern. Ds ist eine Hilfsfunktion für
* @see onSaveTransaction, wir zweimal aufgerufen: einmal auf Stick und einmal
* als Geheim-Backup auf Platte.
*
*/
bool MCMainWindowBase::saveTransactionToFile( const QString& filename, const QString& transaction )
{
QFile datafile( filename );
if (!datafile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append ))
return showFileError( filename, datafile.errorString() );
/// file nicht direkt beschreiben
QTextStream output( &datafile );
/// Stream füllen
output << transaction;
return true;
}
/**
* @brief Schreibt die Einkäufe eines Kunden (==Transaktion)
* via QTextStream formatiert in einen String.
*
* Alle bisherigen Verkäufe, also der Inhalt des @see MCSalesModel, werden
* mit Hilfe eines QTextStreams als Tab-Separated-Values in einen QString
* geschrieben
*
* @return Die Verkaufstransaktion als String
*
*/
QString MCMainWindowBase::saveTransactionToString()
{
QString result;
QTextStream output( &result );
/// Stream füllen
for( int row = 0; row < _salesModel.rowCount(); ++row )
{
/// TransactionNo
QModelIndex idx = _salesModel.index( row, MCSalesItemMap::Count );
QString content = _salesModel.data( idx ).toString();
output << content << " ";
/// SellerID
idx = _salesModel.index( row, MCSalesItemMap::SellerID );
content = _salesModel.data( idx ).toString();
output << content << " ";
/// Laufende ArtikelNo
idx = _salesModel.index( row, MCSalesItemMap::ItemNo );
/// passiert jetzt schon im model
///output << formatInt( _salesModel.data( idx ).toInt(), 3 );
output << _salesModel.data( idx ).toString();
idx = _salesModel.index( row, MCSalesItemMap::Price );
content = _salesModel.data( idx ).toString();
/// Eurozeichen absäbeln, komma statt punkt wg. kompatibilität
/// mit PCK
if( content.isEmpty() || content.isNull() )
{
/// FIX, murx: log error
content = "0,0";
}
else
{
content = content.split( ' ' ).at(0);
}
/// so sollte man es eigentlich machen
output << Qt::right << qSetFieldWidth(15) << content << Qt::reset;
/// datum/zeit dranhängen & zeile fertig
QString dtstr = QDateTime::currentDateTime().toString( "MM-dd-yyyy hh:mm:ss" );
output << ' ' << dtstr << Qt::endl;
}
return result;
}
/**
* @brief Vom aktuellen Kunden gekaufte Artikel auf Platte sichern.
*
* Speichert die vom aktuellen Kunden gekauften Artikel auf Platte.
* @see saveTransactionToString()
*
*/
bool MCMainWindowBase::onSaveTransaction()
{
// View auslesen
/// an datei anhängen
/// zähler zurücksetzen
/// die Lineedits wieder löschen
///
/// Step 0: gibbet überhaupt View-Daten?
///
if( _salesModel.rowCount() == 0 )
{
QApplication::beep();
return false;
}
///
/// Step 1: View-Daten via Textstream in einen String schreiben
///
QString transaction = saveTransactionToString();
///
/// Step 2a: Die (nunmehr formatierte) Transaktion speichern und sichern
///
/// Offizieller Speicherort auf dem Stick bzw. nunmehr auf SSD
if( !saveTransactionToFile( _dataFilePath, transaction ) )
return false;
/// Dummy für Speichern im Netz
emit transactionCreated( transaction );
///
/// Step 4: das Zählerfeld neu setzen
///
_newTransCount++;
_transCount++;
_mainSettings.setValue( miniCash::keyTransCount, _transCount );
///
/// Step 4: Die Lineedits & view wieder löschen
///
_inputViewProxy->onResetView();
return true;
}
/**
* @brief Verkaufstransaktionen kopieren
*
* Alle Verkaufstransaktionen zur Auswertung auf einen Memorystick
* kopieren
*
*/
void MCMainWindowBase::onCopyTransactions()
{
/// FIX murx
QMessageBox msg;
msg.setWindowTitle( "Auswertungsdatei erzeugen" );
QString txt( "Wenn der Memorystick in Laufwerk '%0' \neingesteckt ist bitte auf 'Speichern' klicken" );
msg.setText( txt.arg( fetchSetting( miniCash::keyMobileDrive ) ) );
msg.setStandardButtons( QMessageBox::Save | QMessageBox::Cancel );
msg.addButton("Speichern",QMessageBox::AcceptRole);
msg.addButton("Abbrechen",QMessageBox::RejectRole);
msg.setDefaultButton(QMessageBox::Save);
msg.setIcon ( QMessageBox::Information );
if( msg.exec() == QMessageBox::Cancel )
return;
QString target = fetchSetting( miniCash::keyMobileDrive ) + fetchSetting( miniCash::keySelfID );
target += "_" + _dataFileName;
/// falls vorhanden löschen weil copy nicht überschreibt
QFileInfo fitarget( target );
if( fitarget.exists() )
QFile::remove( target );
if( !QFile::copy( _dataFilePath, target ) )
{
QString msg( "Dateifehler: Kopieren von %0\nnach %1 fehlgeschlagen.");
QMessageBox::warning(this, "Dateifehler", msg.arg( _dataFilePath, target ) );
return onSetup();
}
QMessageBox::information( this, "Auswertungsdatei erzeugen", "Auswertungsdatei wurde erfolgreich erzeugt." );
}
/**
* @brief Handbuch anzeigen
*
* @bug Handbuch ist noch nicht fertig.
*/
void MCMainWindowBase::onHelpManual()
{
//QMessageBox::StandardButton reply = QMessageBox::information(this, "onHelpContents()", "onHelpContents()" );
//_helpViewer->show();
onHelpAbout();
}
/**
* @brief Speichern und Beenden, die Toolbarversion: Es wird nachgefragt.
*/
void MCMainWindowBase::onExitConfirmed()
{
/// murx
QMessageBox msg;
msg.setWindowTitle("Programm beenden");
msg.setText("Programm wirklich beenden?");
msg.setStandardButtons( QMessageBox::Save | QMessageBox::Cancel );
msg.addButton("OK", QMessageBox::AcceptRole );
msg.addButton("Abbrechen",QMessageBox::RejectRole);
msg.setDefaultButton(QMessageBox::Save);
msg.setIcon ( QMessageBox::Information );
if( msg.exec() == QMessageBox::Cancel )
return;
onExit();
}
/**
* @brief Speichern und Beenden, die Menuversion: Es wird nicht nachgefragt.
*/
void MCMainWindowBase::onExit()
{
/// Falls noch Transaktion vorhanden,
/// diese sichern
if( _salesModel.rowCount() != 0 )
onSaveTransaction();
qApp->exit();
}