385 lines
12 KiB
C++
385 lines
12 KiB
C++
/***************************************************************************
|
|
|
|
miniCashConnect
|
|
Copyright © 2022 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 <QTimer>
|
|
|
|
#include <miniCashConnect.h>
|
|
#include <mcconnectmainwindow.h>
|
|
#include <mcsetupdialog.h>
|
|
#include <mcnetworkdialog.h>
|
|
#include <mcceditview.h>
|
|
#include <mcbillingview.h>
|
|
#include <mccaboutme.h>
|
|
#include <ui_mcconnectmainwindow.h>
|
|
#include <mcnetworkwidget.h>
|
|
|
|
|
|
/**
|
|
* @brief MCConnectMainWindow::MCConnectMainWindow
|
|
* @param parent
|
|
*/
|
|
|
|
MCConnectMainWindow::MCConnectMainWindow( QWidget* parent )
|
|
: MCMainWindowBase{ parent }
|
|
|
|
{
|
|
|
|
setupUi( this );
|
|
|
|
/// kommt aus der miniCash library
|
|
setupDefaults();
|
|
|
|
_billingView->setupDefaults( _dataFileName, &_mainSettings );
|
|
/// das ist ein hack, der der Oberklasse 'MCMainwindowbase' den Zugriff ermöglicht.
|
|
_inputViewProxy = _inputView;
|
|
_inputView->setupDefaults( this, &_salesModel );
|
|
_editView->setupDefaults( this );
|
|
|
|
statusBar()->setFont( QFont( "Arial", 8 ) );
|
|
statusBar()->showMessage( QString( miniCash::copyConnect ) + miniCash::versionConnect );
|
|
|
|
//_helpViewer = new MCHelpViewer();
|
|
//_helpViewer->load( "file:///C:/HandbuchMiniCash.html" );
|
|
|
|
/// actions
|
|
connect( _actionSetup, SIGNAL( triggered() ), this, SLOT( onSetup() ) );
|
|
connect( _actionSetupNetwork, SIGNAL( triggered() ), this, SLOT( onShowNetworkDialog() ) );
|
|
connect( _actionInputTransactions, SIGNAL( triggered() ), this, SLOT( onInputTransactions() ) );
|
|
connect( _actionViewTransactions, SIGNAL( triggered() ), this, SLOT( onViewTransactions() ) );
|
|
connect( _actionEditTransactions, SIGNAL( triggered() ), this, SLOT( onEditTransactions() ) );
|
|
connect( _actionCopySaleData, SIGNAL( triggered() ), this, SLOT( onCopyTransactions() ) );
|
|
connect( _actionStartBilling, SIGNAL( triggered() ), this, SLOT( onStartBilling() ) );
|
|
connect( _actionExit, SIGNAL( triggered() ), this, SLOT( onExit() ) );
|
|
connect( _actionExitConfirmed, SIGNAL( triggered() ), this, SLOT( onExitConfirmed() ) );
|
|
connect( _actionHelpAbout, SIGNAL( triggered() ), this, SLOT( onHelpAbout() ) );
|
|
connect( _actionHelpContents, SIGNAL( triggered() ), this, SLOT( onHelpManual() ) );
|
|
|
|
|
|
/// senden & empfangen sind asynchron, also schieben wir die in
|
|
/// eigenen Threads
|
|
_tcpSender.moveToThread( &_senderThread );
|
|
_tcpReceiver.moveToThread( &_receiverThread );
|
|
|
|
//connect( this, SIGNAL( stopNetwork() ), &_tcpSender, SLOT( onDiscardConnection() ) );
|
|
//connect( this, SIGNAL( stopNetwork() ), &_tcpReceiver, SLOT( onDiscardConnection() ) );
|
|
|
|
connect( this, SIGNAL( startNetwork() ), &_tcpSender, SLOT( onCreateConnection() ) );
|
|
connect( this, SIGNAL( startNetwork() ), &_tcpReceiver, SLOT( onCreateConnection() ) );
|
|
|
|
qRegisterMetaType<miniCash::CState>("miniCash::CState");
|
|
qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
|
|
|
|
connect( &_tcpSender, SIGNAL( connectionChanged(miniCash::CState) ), this, SLOT( onStateChanged(miniCash::CState) ) );
|
|
connect( &_tcpReceiver, SIGNAL( connectionChanged(miniCash::CState) ), this, SLOT( onStateChanged(miniCash::CState) ) );
|
|
|
|
/// das SIG transactionCreated() stammt aus der Basisklass MCMainWindowBase, nette Möglichkleit, eine
|
|
/// abstrakte Methode 'sendTransaction() = 0' zu ersetzen.
|
|
connect( this, SIGNAL( transactionCreated(QString) ), &_tcpSender, SLOT( onSendTransaction(QString) ) );
|
|
connect( &_tcpReceiver, SIGNAL( newTransaction(QString) ), this, SLOT( onTransactionReceived(QString) ) );
|
|
|
|
|
|
/// catch network errors
|
|
connect( &_tcpSender, SIGNAL( errorOccurred(QAbstractSocket::SocketError) ), this, SLOT( onConnectionError(QAbstractSocket::SocketError) ) );
|
|
connect( &_tcpReceiver, SIGNAL( acceptError(QAbstractSocket::SocketError) ), this, SLOT( onConnectionError(QAbstractSocket::SocketError) ) );
|
|
|
|
/// erstmal die Basis ...
|
|
/// wenn wir das erste mal hier sind, defaults laden.
|
|
if( !_mainSettings.contains( miniCash::keyReceiverHost ) )
|
|
{
|
|
_mainSettings.setValue( miniCash::keyIsTcpReceiver, miniCash::isTcpReceiver );
|
|
_mainSettings.setValue( miniCash::keyIsTcpSender, miniCash::isTcpSender );
|
|
_mainSettings.setValue( miniCash::keyReceiverHost, "" );
|
|
_mainSettings.setValue( miniCash::keyReceiverPort, miniCash::receiverPort );
|
|
}
|
|
|
|
connect( _netWidget, SIGNAL( showNetworkDialog() ), this, SLOT( onShowNetworkDialog() ) );
|
|
|
|
/// gleich beim Start NetDlg zeigen?
|
|
//_isSender = _mainSettings.value( miniCash::keyIsTcpSender ).toBool();
|
|
//_host = _mainSettings.value( miniCash::keyReceiverHost ).toString();
|
|
//if( _isSender && _host.isEmpty() )
|
|
|
|
/// Ist schon Ok, den DLG immer anzuzeigen
|
|
_showDlg = true;
|
|
|
|
_isReceiver = _mainSettings.value( miniCash::keyIsTcpReceiver ).toBool();
|
|
|
|
_sideBar->appendAction( _actionInputTransactions );
|
|
if( _isReceiver )
|
|
_sideBar->appendAction( _actionViewTransactions );
|
|
_sideBar->appendAction( _actionEditTransactions );
|
|
_sideBar->appendAction( _actionStartBilling );
|
|
_sideBar->setCheckedAction( _actionInputTransactions );
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Destruktor
|
|
*/
|
|
|
|
MCConnectMainWindow::~MCConnectMainWindow()
|
|
{
|
|
_senderThread.exit();
|
|
_receiverThread.exit();
|
|
|
|
if( !_senderThread.wait( 3000 ) ) //Wait until it actually has terminated (max. 3 sec)
|
|
{
|
|
_senderThread.terminate(); //Thread didn't exit in time, probably deadlocked, terminate it!
|
|
_senderThread.wait(); //We have to wait again here!
|
|
}
|
|
if( !_receiverThread.wait( 3000 ) ) //Wait until it actually has terminated (max. 3 sec)
|
|
{
|
|
_receiverThread.terminate(); //Thread didn't exit in time, probably deadlocked, terminate it!
|
|
_receiverThread.wait(); //We have to wait again here!
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Überschreibt 'QMainWindow::showEvent', um ggf. einen NetworkSetup Dialog
|
|
* einzuschmuggleln.
|
|
* @param event
|
|
*/
|
|
|
|
void MCConnectMainWindow::showEvent( QShowEvent* event )
|
|
{
|
|
|
|
/// 'onShowNetworkDialog' gehört eigentlich in den Konstruktor (falls der Hostname nicht gesetzt ist,
|
|
/// wenn aber dort der NetworkSetup-Dialog aufgerufen wird, dann erscheint dieser _vor_ dem
|
|
/// Hauptfenster. Um das zu vermeiden, schmuggeln wir das per 'showEvent' ein.
|
|
|
|
QMainWindow::showEvent( event );
|
|
|
|
/// guard: der DLG soll nur einmal beim Start erscheinen
|
|
if( !_showDlg )
|
|
return;
|
|
|
|
/// Call slot via queued connection so it's called from the UI thread after this method has returned and the window has been shown
|
|
QMetaObject::invokeMethod( this, &MCConnectMainWindow::onShowNetworkDialog, Qt::ConnectionType::QueuedConnection );
|
|
_showDlg = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MCConnectMainWindow::onStateChanged( miniCash::CState state )
|
|
{
|
|
/// Serverstate schlägt Clientstate, ist deswege numerisch höher,
|
|
/// Errorstates werden woanders gesetzt
|
|
if( state > _netWidget->connectionState() )
|
|
_netWidget->setConnectionState( state );
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief setup dialog anzeigen
|
|
*
|
|
* Maske mit den Programmeinstellungen anzeigen: Ziellaufwerk etc.
|
|
*
|
|
*/
|
|
|
|
void MCConnectMainWindow::onSetup()
|
|
{
|
|
MCSetupDialog( this, &_mainSettings ).exec();
|
|
/// alles kann geändert worden sein -> also nochmal los
|
|
setupDefaults();
|
|
}
|
|
|
|
|
|
void MCConnectMainWindow::onShowNetworkDialog()
|
|
{
|
|
|
|
int result = MCNetworkDialog( this, &_mainSettings ).exec();
|
|
if( QDialog::Rejected == result )
|
|
return;
|
|
|
|
setupNetwork();
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Netzwerksettings initialisieren
|
|
*
|
|
* Wird direkt beim Programmstart aufgerufen, setzt die Vorgabewerte
|
|
* fürs Networking. Das ist eine Ergänzung zu @see setupDefaults in der Basisklasse.
|
|
*/
|
|
|
|
void MCConnectMainWindow::setupNetwork()
|
|
{
|
|
|
|
//emit stopNetwork();
|
|
|
|
_isSender = _mainSettings.value( miniCash::keyIsTcpSender ).toBool();
|
|
_isReceiver = _mainSettings.value( miniCash::keyIsTcpReceiver ).toBool();
|
|
_host = _mainSettings.value( miniCash::keyReceiverHost ).toString();
|
|
_port = _mainSettings.value( miniCash::keyReceiverPort ).toInt();
|
|
|
|
bool useNetwork = _isSender || _isReceiver;
|
|
|
|
/// gar kein Netz?
|
|
if( !useNetwork )
|
|
return _netWidget->setConnectionState( miniCash::Disabled );
|
|
|
|
/*
|
|
/// ... und nochmal Prüfen: Host, default ist ja leer
|
|
if( _host.isEmpty() )
|
|
{
|
|
int result = MCNetworkDialog( this, &_mainSettings ).exec();
|
|
if( QDialog::Rejected == result )
|
|
return;
|
|
}
|
|
*/
|
|
|
|
/// Netz wird verwendet, verrbinden ...
|
|
_netWidget->setConnectionState( miniCash::UnConnected );
|
|
|
|
/// bin ich Server, also Empfänger
|
|
if( _isReceiver )
|
|
{
|
|
/// (Re-)init server
|
|
_tcpReceiver.setupConnection( _port );
|
|
if( !_receiverThread.isRunning() )
|
|
_receiverThread.start();
|
|
}
|
|
|
|
/// bin ich Client, also Sender?
|
|
if( _isSender )
|
|
{
|
|
_tcpSender.setupConnection( _host, _port );
|
|
if( !_senderThread.isRunning() )
|
|
_senderThread.start();
|
|
}
|
|
|
|
emit startNetwork();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MCConnectMainWindow::onConnectionError( QAbstractSocket::SocketError socketError )
|
|
{
|
|
|
|
qDebug() << "socketError:" << socketError;
|
|
|
|
switch( socketError )
|
|
{
|
|
case QAbstractSocket::RemoteHostClosedError:
|
|
QMessageBox::information(this, "QTCPServer", "RemoteHostClosedError:");
|
|
break;
|
|
|
|
case QAbstractSocket::HostNotFoundError:
|
|
QMessageBox::information(this, "QTCPServer", "The host was not found. Please check the host name and port settings.");
|
|
|
|
break;
|
|
|
|
case QAbstractSocket::ConnectionRefusedError:
|
|
QMessageBox::information(this, "QTCPServer", "The connection was refused by the peer. Make sure QTCPServer is running, and check that the host name and port settings are correct.");
|
|
break;
|
|
|
|
default:
|
|
QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
|
|
QMessageBox::information(this, "QTCPServer", QString("The following error occurred: %1.").arg(socket->errorString()));
|
|
break;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* @brief Eingabemaske (wieder) einblenden, in den
|
|
* Eingabemodus schalten
|
|
*/
|
|
|
|
void MCConnectMainWindow::onInputTransactions()
|
|
{
|
|
_contentWidget->setCurrentWidget( _inputView );
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief TransactionView einblenden: Eingehende Transaktionen werden angezeigt
|
|
*/
|
|
|
|
void MCConnectMainWindow::onViewTransactions()
|
|
{
|
|
// Anim??
|
|
_contentWidget->setCurrentWidget( _transactionView );
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Transaktionsdaten korrigieren, z.B. Zahlendreher beheben oder Stornos
|
|
* einbuchen.
|
|
*/
|
|
|
|
void MCConnectMainWindow::onEditTransactions()
|
|
{
|
|
|
|
qDebug() << " -- Edit Transactions: " << _dataFilePath;
|
|
|
|
_editView->loadTransactions( _dataFilePath );
|
|
_contentWidget->setCurrentWidget( _editView );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* @brief MCConnectMainWindow::onTransactionReceived
|
|
* @param transaction: Transaktionen als String
|
|
*/
|
|
|
|
void MCConnectMainWindow::onTransactionReceived( const QString& transaction )
|
|
{
|
|
_transactionView->onTransactionReceived( transaction );
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief In den Abrechungsmodus schalten
|
|
*
|
|
* Abrechnung starten: Dazu wird das Hauptfenster auf die Abrechungsmaske
|
|
* umgeschaltet
|
|
*/
|
|
|
|
void MCConnectMainWindow::onStartBilling()
|
|
{
|
|
_contentWidget->setCurrentWidget( _billingView );
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Kurzinfo anzeigen
|
|
*
|
|
*/
|
|
|
|
void MCConnectMainWindow::onHelpAbout()
|
|
{
|
|
MCCAboutMe().exec();
|
|
}
|