xdsopl-qsstv/qsstv/mainwindow.cpp

628 wiersze
17 KiB
C++

/**************************************************************************
* Copyright (C) 2000-2019 by Johan Maes *
* on4qz@telenet.be *
* http://users.telenet.be/on4qz *
* *
* 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 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "mainwindow.h"
#include "appglobal.h"
#include "logging.h"
#include "dispatch/dispatcher.h"
#include "ui_mainwindow.h"
#include "soundpulse.h"
#include "soundalsa.h"
#include "configdialog.h"
#include "configparams.h"
#include "rigcontrol.h"
#include "waterfalltext.h"
#include "calibration.h"
#include "frequencyselectwidget.h"
#include "hexconvertor.h"
#ifndef QT_NO_DEBUG
#include "scope/scopeview.h"
#endif
#include "scope/scopeoffset.h"
#include "rxfunctions.h"
#include "logbook.h"
#include "testpatternselection.h"
#include <QFont>
#include <QCloseEvent>
#include <QMessageBox>
#include <QScreen>
#include <QApplication>
#include "filewatcher.h"
#include "ftpfunctions.h"
/**
* @brief
*
* @param parent
*/
mainWindow::mainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
inStartup=true;
QApplication::instance()->thread()->setObjectName("qsstv_main");
wfTextPushButton=new QPushButton("WF Text",this);
bsrPushButton=new QPushButton("BSR",this);
setObjectName("mainThread");
freqComboBox=new QComboBox(this);
idPushButton=new QPushButton("WF ID",this);
cwPushButton=new QPushButton("CW ID",this);
QFont f;
freqDisplay = new QLabel(this);
f.setBold(true);
f.setPixelSize(15);
freqDisplay->setFont(f);
freqDisplay->setObjectName("freqDisplay");
freqDisplay->setMinimumSize(QSize(100, 0));
freqDisplay->setMaximumSize(QSize(100, 16777215));
freqDisplay->setFrameShape(QFrame::Box);
freqDisplay->setFrameShadow(QFrame::Raised);
freqDisplay->setLineWidth(2);
pttText.setText(" PTT");
pttIcon=new QLabel(this);
pttIcon->setFixedSize(16,16);
pttIcon->setPixmap(*greenPXMPtr);
pttIcon->setFrameShape(QFrame::Panel);
pttIcon->setFrameShadow(QFrame::Raised);
pttIcon->setLineWidth(2);
rigControllerPtr=new rigControl(1); // must preceed configDialog construction
configDialogPtr=new configDialog(this);
configDialogPtr->readSettings();
ui->setupUi(this);
setWindowTitle(qsstvVersion);
setWindowIcon(QPixmap(":/icons/qsstv.png"));
ui->maintabWidget->setCurrentIndex(0);
ui->statusBar->addPermanentWidget(freqDisplay);
ui->statusBar->addPermanentWidget(freqComboBox);
ui->statusBar->addPermanentWidget(wfTextPushButton);
ui->statusBar->addPermanentWidget(bsrPushButton);
ui->statusBar->addPermanentWidget(idPushButton);
ui->statusBar->addPermanentWidget(cwPushButton);
ui->statusBar->addPermanentWidget(&pttText);
ui->statusBar->addPermanentWidget(pttIcon);
statusBarPtr=statusBar(); // must be after setup UI
spectrumFramePtr=ui->spectrumFrame;
// setting up pointers
soundIOPtr=NULL;
fileWatcherPtr=NULL;
rxWidgetPtr=ui->rxWindow;
txWidgetPtr=ui->txWindow;
galleryWidgetPtr=ui->galleryWindow;
readSettings();
if(pulseSelected) soundIOPtr=new soundPulse;
else soundIOPtr=new soundAlsa;
// setupFtp(notifyRXIntfPtr,"FtpNotificationRx");
// setupFtp(hybridRxIntfPtr,"FtpHybridRx");
// setupFtp(saveImageIntfPtr,"FtpSaveImageRx");
// setupFtp(hybridTxIntfPtr,"FtpHybridTx");
// setupFtp(notifyTXIntfPtr,"FtpNotificationTx");
// setupFtp(onlineStatusIntfPtr,"FtpOnlineStatus");
dispatcherPtr=new dispatcher;
waterfallPtr=new waterfallText;
xmlIntfPtr=new xmlInterface;
logBookPtr=new logBook;
// setup connections
connect(ui->actionSaveWaterfallImage,SIGNAL(triggered()),this, SLOT(slotSaveWaterfallImage()));
connect(ui->actionExit,SIGNAL(triggered()),this, SLOT(slotExit()));
connect(ui->actionConfigure,SIGNAL(triggered()),this, SLOT(slotConfigure()));
connect(ui->actionCalibrate,SIGNAL(triggered()),this, SLOT(slotCalibrate()));
connect(ui->actionAboutQSSTV, SIGNAL(triggered()),SLOT(slotAboutQSSTV()));
connect(ui->actionAboutQt, SIGNAL(triggered()),SLOT(slotAboutQt()));
connect(ui->actionUsersGuide, SIGNAL(triggered()),SLOT(slotDocumentation()));
connect(idPushButton, SIGNAL(clicked()), this, SLOT(slotSendWFID()));
connect(cwPushButton, SIGNAL(clicked()), this, SLOT(slotSendCWID()));
connect(bsrPushButton, SIGNAL(clicked()), this, SLOT(slotSendBSR()));
connect(freqComboBox,SIGNAL(activated(int)),SLOT(slotSetFrequency(int)));
connect(wfTextPushButton, SIGNAL(clicked()), this, SLOT(slotSendWfText()));
connect(rxWidgetPtr,SIGNAL(modeSwitch(int)),this, SLOT(slotModeChange(int)));
connect(txWidgetPtr,SIGNAL(modeSwitch(int)),this, SLOT(slotModeChange(int)));
QAction *fs = new QAction(this);
fs->setShortcut(Qt::Key_F | Qt::CTRL);
connect(fs, SIGNAL(triggered()), this, SLOT(slotFullScreen()));
this->addAction(fs);
#ifdef ENABLELOGGING
connect(ui->actionLogSettings, SIGNAL(triggered()),SLOT(slotLogSettings()));
connect(ui->actionResetLog, SIGNAL(triggered()),SLOT(slotResetLog()));
#else
ui->menuOptions->removeAction(ui->actionLogSettings);
ui->menuOptions->removeAction(ui->actionResetLog);
#endif
#ifndef QT_NO_DEBUG
connect(ui->actionShowDataScope, SIGNAL(triggered()),SLOT(slotShowDataScope()));
connect(ui->actionShowSyncScopeNarrow, SIGNAL(triggered()),SLOT(slotShowSyncScopeNarrow()));
connect(ui->actionShowSyncScopeWide, SIGNAL(triggered()),SLOT(slotShowSyncScopeWide()));
connect(ui->actionScopeOffset,SIGNAL(triggered()),this, SLOT(slotScopeOffset()));
connect(ui->actionClearScope,SIGNAL(triggered()),this, SLOT(slotClearScope()));
connect(ui->actionDumpSamplesPerLine,SIGNAL(triggered()),this, SLOT(slotDumpSamplesPerLine()));
connect(ui->actionTxTestPattern,SIGNAL(triggered()),this, SLOT(slotTxTestPattern()));
#else
ui->menuOptions->removeAction(ui->actionDumpSamplesPerLine);
ui->menuScope->removeAction(ui->actionShowDataScope);
ui->menuScope->removeAction(ui->actionShowSyncScopeNarrow);
ui->menuScope->removeAction(ui->actionShowSyncScopeWide);
ui->menuScope->removeAction(ui->actionScopeOffset);
ui->menuScope->menuAction()->setVisible(false);
#endif
}
/**
* @brief
*
*/
mainWindow::~mainWindow()
{
delete ui;
}
/**
* @brief initialize sound device and dispatcher
*
*/
void mainWindow::init()
{
cleanUpCache(rxSSTVImagesPath);
cleanUpCache(rxDRMImagesPath);
cleanUpCache(txSSTVImagesPath);
cleanUpCache(txDRMImagesPath);
//start rx and tx threads
rxWidgetPtr->functionsPtr()->start();
txWidgetPtr->functionsPtr()->start();
restartSound(true);
dispatcherPtr->init();
galleryWidgetPtr->init();
txWidgetPtr->init();
waterfallPtr->init();
rigControllerPtr->init();
rxWidgetPtr->init();
if(!rigControllerPtr->initError.isEmpty())
{
splashStr+=rigControllerPtr->initError.rightJustified(25,' ')+"\n";
splashPtr->showMessage(splashStr ,Qt::AlignLeft,Qt::white);
}
startTimer(1000);
if(fileWatcherPtr==NULL) fileWatcherPtr=new fileWatcher;
fileWatcherPtr->init();
}
void mainWindow::restartSound(bool inStartUp)
{
//first check if sound
if(soundIOPtr!=NULL)
{
soundIOPtr->stopSoundThread();
delete soundIOPtr;
soundIOPtr=NULL;
}
if(pulseSelected) soundIOPtr=new soundPulse;
else soundIOPtr=new soundAlsa;
if(!soundIOPtr->init(BASESAMPLERATE))
{
if(inStartUp)
{
splashStr+=QString("Soundcard error: %1").arg(soundIOPtr->getLastError()).rightJustified(25,' ')+"\n";;
splashPtr->showMessage(splashStr ,Qt::AlignLeft,Qt::white);
}
else
{
QMessageBox::critical(this, tr("Soundcard error"),soundIOPtr->getLastError());
}
}
soundIOPtr->start();
}
void mainWindow::startRunning()
{
inStartup=false;
dispatcherPtr->startRX();
}
void mainWindow::readSettings()
{
QSettings qSettings;
qSettings.beginGroup("MAIN");
int windowWidth = qSettings.value("windowWidth", 460 ).toInt();
int windowHeight = qSettings.value("windowHeight", 530 ).toInt();
int windowX = qSettings.value( "windowX", -1 ).toInt();
int windowY = qSettings.value( "windowY", -1 ).toInt();
resize( windowWidth, windowHeight );
if ( windowX != -1 || windowY != -1 )
{
move( windowX, windowY );
}
transmissionModeIndex=(etransmissionMode)qSettings.value("transmissionModeIndex",0).toInt();
qSettings.endGroup();
ui->spectrumFrame->readSettings();
// configDialogPtr->readSettings();
}
void mainWindow::writeSettings()
{
QSettings qSettings;
qSettings.beginGroup("MAIN");
qSettings.setValue( "windowWidth", width() );
qSettings.setValue( "windowHeight", height() );
qSettings.setValue( "windowX", x() );
qSettings.setValue( "windowY", y() );
qSettings.setValue("transmissionModeIndex",(int)transmissionModeIndex);
galleryWidgetPtr->writeSettings();
rxWidgetPtr->writeSettings();
txWidgetPtr->writeSettings();
configDialogPtr->writeSettings();
qSettings.endGroup();
ui->spectrumFrame->writeSettings();
}
/**
*\todo fontselection
*/
void mainWindow::setNewFont()
{
// QFont fnt;
// fnt.fromString(fontString);
// setFont(fnt);
// galMW->setFont(fnt);
// rxMW->setFont(fnt);
// txMW->setFont(fnt);
}
void mainWindow::slotSaveWaterfallImage()
{
QImage *wf = ui->spectrumFrame->getImage();
if (wf) {
double freq=0;
QDateTime now=QDateTime::currentDateTime();
QString fn="waterfall-"+now.toString("yyyyMMddhhmmss")+".jpg";
QImage im(wf->width()+2, wf->height()+22, QImage::Format_RGB32);
QPainter p(&im);
im.fill(Qt::black);
p.setPen(Qt::lightGray);
p.drawImage(2,20,*wf);
p.drawRect(0,0,wf->width()+1,wf->height()+21);
//TODO: rig frequency etc
rigControllerPtr->getFrequency(freq);
if (freq>0)
p.drawText(1,15, QString("%1 MHz").arg(freq/1000000.0,1,'f',6));
else
p.drawText(1,15, "no freq");
if (im.save(fn, "jpg"))
{
statusBarPtr->showMessage("Saved "+fn);
}
else {
statusBarPtr->showMessage("Error saving image");
}
delete wf;
}
}
void mainWindow::slotExit()
{
int exit=QMessageBox::Ok;
if(confirmClose)
{
exit=QMessageBox::information(0, tr("Quit..."),tr("Do you really want to quit QSSTV?"), QMessageBox::Ok, QMessageBox::Cancel);
}
if(exit==QMessageBox::Ok)
{
statusBarPtr->showMessage("Cleaning up...");
dispatcherPtr->idleAll();
rxWidgetPtr->setOnlineStatus(false);
rxWidgetPtr->functionsPtr()->stopThread();
txWidgetPtr->functionsPtr()->stopThread();
if(soundIOPtr) soundIOPtr->stopSoundThread();
writeSettings();
QApplication::quit();
}
}
void mainWindow::closeEvent ( QCloseEvent *e )
{
slotExit();
e->ignore();
}
void mainWindow::slotConfigure()
{
if(configDialogPtr->exec()==QDialog::Accepted)
{
if(configDialogPtr->soundNeedsRestart)
{
restartSound(false);
}
dispatcherPtr->init();
}
}
void mainWindow::slotLogSettings()
{
logFilePtr->maskSelect(this);
logFilePtr->writeSettings();
}
void mainWindow::slotResetLog()
{
logFilePtr->reset();
}
void mainWindow::slotDocumentation()
{
QDesktopServices::openUrl(docURL);
}
void mainWindow::slotAboutQSSTV()
{
QString temp=tr("QSSTV\nVersion: ") + MAJORVERSION + MINORVERSION;
temp += "\n http://users.telenet.be/on4qz \n(c) 2000-2019 -- Johan Maes - ON4QZ\n HAMDRM Software based on RX/TXAMADRM\n from PA0MBO";
QMessageBox::about(this,tr("About..."),temp);
}
void mainWindow::slotAboutQt()
{
QMessageBox::aboutQt(this,tr("About..."));
}
void mainWindow::setPTT(bool p)
{
if(p) pttIcon->setPixmap(*redPXMPtr);
else pttIcon->setPixmap(*greenPXMPtr);
}
void mainWindow::setSSTVDRMPushButton(bool inDRM)
{
int i;
QString modeStr;
bsrPushButton->setEnabled(inDRM);
freqComboBox->clear();
if(inDRM) modeStr="DRM";
else modeStr="SSTV";
modModeList.clear();
modPassBandList.clear();
for(i=0;i<freqList.count();i++)
{
if(modeList.at(i)==modeStr)
{
freqComboBox->addItem(freqList.at(i));
modModeList.append(sbModeList.at(i));
modPassBandList.append(passBandList.at(i));
}
}
}
void mainWindow::slotCalibrate()
{
calibration calib(this);
if(calib.exec()==QDialog::Accepted)
{
rxClock=calib.getRXClock();
txClock=calib.getTXClock();
}
writeSettings();
}
void mainWindow::slotModeChange(int rxtxMode)
{
txWidgetPtr->changeTransmissionMode(rxtxMode);
rxWidgetPtr->changeTransmissionMode(rxtxMode);
lastReceivedCall.clear();
}
void mainWindow::slotSendBSR()
{
txWidgetPtr->sendBSR();
}
void mainWindow::slotSendWFID()
{
txWidgetPtr->sendWFID();
}
void mainWindow::slotSendCWID()
{
txWidgetPtr->sendCWID();
}
void mainWindow::slotSendWfText()
{
txWidgetPtr->sendWfText();
}
void mainWindow::slotSetFrequency(int freqIndex)
{
QByteArray ba;
QString freqStr,mode,passBand;
freqStr=freqComboBox->itemText(freqIndex);
mode=modModeList.at(freqIndex);
passBand=modPassBandList.at(freqIndex);
if(freqStr.isEmpty()) return;
double fr=freqStr.toDouble()*1000000.;
rigControllerPtr->setFrequency(fr);
rigControllerPtr->setMode(mode,passBand);
QString s=additionalCommand;
//FEF7AE01A060101FD
if(!s.isEmpty() && !rigControllerPtr->params()->enableXMLRPC)
{
if(hexFromString(s,ba,additionalCommandHex))
{
rigControllerPtr->rawCommand(ba);
}
else
{
QMessageBox::critical(this,"Cat Error","Advanced command invalid");
}
}
}
void mainWindow::timerEvent(QTimerEvent *)
{
double fr;
if(rigControllerPtr->getFrequency(fr))
{
fr/=1000000.;
if(fr>1) freqDisplay->setText(QString::number(fr,'f',6));
}
else
{
freqDisplay->setText("No Rig");
}
}
void mainWindow::cleanUpCache(QString dirPath)
{
int i,j;
bool found;
QFileInfoList orgFileList;
QFileInfoList cacheFileList;
QFileInfoList removeFileList;
QDir dirOrg(dirPath);
dirOrg.setFilter(QDir::Files | QDir::NoSymLinks);
orgFileList = dirOrg.entryInfoList();
// get a orgiriginal filelist
QDir dirCache(dirPath+"/cache");
dirCache.setFilter(QDir::Files | QDir::NoSymLinks);
cacheFileList = dirCache.entryInfoList();
// get a orgiriginal filelist
for(i=0;i<cacheFileList.count();i++)
{
found=false;
for(j=0;j<orgFileList.count();j++)
{
if(cacheFileList.at(i).baseName()==QString(orgFileList.at(j).baseName()+orgFileList.at(j).created().toString()))
{
found=true;
break;
}
}
if(!found)
{
removeFileList.append(cacheFileList.at(i));
}
}
for(i=0;i<removeFileList.count();i++)
{
QFile fi(removeFileList.at(i).absoluteFilePath());
fi.remove();
}
}
void mainWindow::slotFullScreen()
{
if(isFullScreen())
{
this->setWindowState(Qt::WindowMaximized);
}
else
{
this->setWindowState(Qt::WindowFullScreen);
}
}
#ifndef QT_NO_DEBUG
void mainWindow::slotShowDataScope()
{
scopeViewerData->show(true,true,true,true);
}
void mainWindow::slotShowSyncScopeNarrow()
{
scopeViewerSyncNarrow->show(true,true,true,true);
}
void mainWindow::slotShowSyncScopeWide()
{
scopeViewerSyncWide->show(true,true,true,true);
}
void mainWindow::slotScopeOffset()
{
dataScopeOffset=rxWidgetPtr->functionsPtr()->setOffset(dataScopeOffset,true);
}
void mainWindow::slotDumpSamplesPerLine()
{
dumpSamplesPerLine();
}
void mainWindow::slotClearScope()
{
scopeViewerData->clear();
scopeViewerSyncNarrow->clear();
scopeViewerSyncWide->clear();
}
void mainWindow::slotTxTestPattern()
{
etpSelect sel;
testPatternSelection tpsel;
if(tpsel.exec()==QDialog::Accepted)
{
sel=tpsel.getSelection();
txWidgetPtr->txTestPattern(sel);
}
}
#endif