/*************************************************************************** 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 #include #include #include #include #include #include #include #include #include /// 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(); }