2019-09-15 01:44:12 +02:00
# include "mainwindow.h"
# include "./ui_mainwindow.h"
/*
*
* TODO : Find another way how to play it for myself and others ( maybe just loopback the default output to the sink monitor )
*
*/
static vector < PulseAudioRecordingStream * > streams ;
2019-11-03 23:40:56 +01:00
static vector < QHotkey * > hotkeys ;
2019-10-06 01:28:46 +02:00
static string configFolder ;
static string soundFilesConfig ;
2019-11-03 23:40:56 +01:00
MainWindow : : MainWindow ( QWidget * parent ) : QMainWindow ( parent ) , ui ( new Ui : : MainWindow )
2019-09-15 01:44:12 +02:00
{
ui - > setupUi ( this ) ;
2019-10-08 00:31:44 +02:00
ui - > tabWidget - > setTabsClosable ( true ) ;
ui - > tabWidget - > setMovable ( true ) ;
ui - > stopButton - > setDisabled ( true ) ;
2019-09-15 01:44:12 +02:00
2019-10-07 01:43:35 +02:00
// Set the config variables
2019-10-06 01:28:46 +02:00
configFolder = QStandardPaths : : standardLocations ( QStandardPaths : : ConfigLocation ) [ 0 ] . toStdString ( ) + " / " + windowTitle ( ) . toStdString ( ) ;
2019-10-08 00:31:44 +02:00
if ( ! filesystem : : exists ( configFolder ) )
{
2019-10-06 01:28:46 +02:00
filesystem : : create_directory ( configFolder ) ;
}
2019-10-08 00:31:44 +02:00
soundFilesConfig = configFolder + " /sounds.json " ;
2019-10-06 01:28:46 +02:00
2019-09-15 01:44:12 +02:00
// Disable resizing
this - > setFixedSize ( this - > width ( ) , this - > height ( ) ) ;
//TODO: Only remove modules created by Soundboard
system ( " pacmd unload-module module-null-sink " ) ;
system ( " pacmd unload-module module-loopback " ) ;
// Create null sink
system ( " pacmd load-module module-null-sink sink_name=soundboard_sink sink_properties=device.description=Soundboard-Sink " ) ;
// Create loopback for output devices (so that you can hear it)
//system("pacmd load-module module-loopback source=\"soundboard_sink.monitor\"");
2019-09-15 02:50:45 +02:00
// get default input device
string defaultInput = " " ;
char cmd [ ] = " pacmd dump " ;
string result = getCommandOutput ( cmd ) ;
regex reg ( R " rgx(set-default-source (.+) ) rgx " ) ;
smatch sm ;
regex_search ( result , sm , reg ) ;
defaultInput = sm [ 1 ] . str ( ) ;
2019-09-15 01:44:12 +02:00
// Create loopback for input
2019-10-08 00:31:44 +02:00
if ( defaultInput ! = " " )
{
2019-10-06 01:28:46 +02:00
cout < < " Found default input device " < < defaultInput < < endl ;
2019-09-15 02:50:45 +02:00
auto createLoopBack = " pacmd load-module module-loopback source= \" " + defaultInput + " \" sink= \" soundboard_sink \" " ;
system ( createLoopBack . c_str ( ) ) ;
}
2019-09-15 01:44:12 +02:00
loadSoundFiles ( ) ;
loadSources ( ) ;
}
void MainWindow : : closeEvent ( QCloseEvent * event )
{
//TODO: Only remove modules created by Soundboard
system ( " pacmd unload-module module-null-sink " ) ;
system ( " pacmd unload-module module-loopback " ) ;
2019-10-06 01:32:51 +02:00
//TODO: Switch all recording streams back to default device
2019-09-15 01:44:12 +02:00
event - > accept ( ) ;
}
2019-10-08 00:31:44 +02:00
string MainWindow : : getCommandOutput ( char cmd [ ] )
{
2019-09-15 01:44:12 +02:00
array < char , 1028 > buffer ;
string result ;
unique_ptr < FILE , decltype ( & pclose ) > pipe ( popen ( cmd , " r " ) , pclose ) ;
2019-10-08 00:31:44 +02:00
if ( ! pipe )
{
2019-09-15 01:44:12 +02:00
throw runtime_error ( " popen() failed ! " ) ;
}
2019-10-08 00:31:44 +02:00
while ( fgets ( buffer . data ( ) , buffer . size ( ) , pipe . get ( ) ) ! = nullptr )
{
2019-09-15 01:44:12 +02:00
result + = buffer . data ( ) ;
}
2019-09-15 02:50:45 +02:00
return result ;
}
2019-10-08 00:31:44 +02:00
bool MainWindow : : isValidDevice ( PulseAudioRecordingStream * stream )
{
2019-09-15 02:50:45 +02:00
return ! strstr ( stream - > source . c_str ( ) , " .monitor " ) & & ! strstr ( stream - > flags . c_str ( ) , " DONT_MOVE " ) ;
}
2019-10-08 00:31:44 +02:00
bool MainWindow : : loadSources ( )
{
2019-09-15 02:50:45 +02:00
// Save previously selected applicaton
auto previouslySelected = ui - > outputApplication - > currentText ( ) ;
streams . clear ( ) ;
ui - > outputApplication - > clear ( ) ;
char cmd [ ] = " pacmd list-source-outputs " ;
string result = getCommandOutput ( cmd ) ;
2019-09-15 01:44:12 +02:00
string delimiter = " \n " ;
size_t pos = 0 ;
string currentLine ;
2019-10-17 23:17:10 +02:00
// Tell me if there is a better way to parse the pulseaudio output
2019-09-15 01:44:12 +02:00
regex reg ( R " rgx(((index: ( \ d+) ) ) | ( driver : ) ( . * ) | ( state : ) ( . * ) | ( flags : ) ( . * ) | ( source : . * ) ( < ( . * ) > ) | ( muted : ) ( . { 0 , 3 } ) | ( [ a - zA - Z - .0 - 9 _ ] * ) \ = \ ( \ " (.*) \" ))rgx " ) ;
smatch sm ;
2019-10-08 00:31:44 +02:00
PulseAudioRecordingStream * current = nullptr ;
2019-09-15 01:44:12 +02:00
2019-10-08 00:31:44 +02:00
while ( ( pos = result . find ( delimiter ) ) ! = string : : npos )
{
2019-09-15 01:44:12 +02:00
currentLine = result . substr ( 0 , pos ) ;
2019-10-08 00:31:44 +02:00
if ( regex_search ( currentLine , sm , reg ) )
{
2019-09-15 01:44:12 +02:00
auto index = sm [ 3 ] ;
2019-10-08 00:31:44 +02:00
if ( index . length ( ) > 0 )
{
2019-09-15 01:44:12 +02:00
2019-10-08 00:31:44 +02:00
if ( current & & isValidDevice ( current ) )
{
2019-09-15 01:44:12 +02:00
streams . push_back ( current ) ;
}
current = new PulseAudioRecordingStream ( ) ;
current - > index = stoi ( index ) ;
2019-10-08 00:31:44 +02:00
}
else if ( current )
{
2019-09-15 01:44:12 +02:00
auto driver = sm [ 5 ] ;
auto state = sm [ 7 ] ;
auto flags = sm [ 9 ] ;
auto source = sm [ 12 ] ;
auto muted = sm [ 14 ] ;
auto propertyName = sm [ 15 ] ;
auto propertyValue = sm [ 17 ] ;
2019-10-08 00:31:44 +02:00
if ( driver . length ( ) > 0 )
{
2019-09-15 01:44:12 +02:00
current - > driver = driver . str ( ) ;
}
2019-10-08 00:31:44 +02:00
if ( state . length ( ) > 0 )
{
2019-09-15 01:44:12 +02:00
current - > state = state . str ( ) ;
}
2019-10-08 00:31:44 +02:00
if ( flags . length ( ) > 0 )
{
2019-09-15 01:44:12 +02:00
current - > flags = flags . str ( ) ;
}
2019-10-08 00:31:44 +02:00
if ( source . length ( ) > 0 )
{
2019-09-15 01:44:12 +02:00
current - > source = source . str ( ) ;
}
2019-10-08 00:31:44 +02:00
if ( muted . length ( ) > 0 )
{
2019-09-15 01:44:12 +02:00
current - > muted = muted = = " yes " ? true : false ;
}
2019-10-08 00:31:44 +02:00
if ( propertyName . length ( ) > 0 )
{
if ( propertyName = = " application.name " )
{
2019-09-15 01:44:12 +02:00
current - > applicationName = propertyValue . str ( ) ;
}
2019-10-08 00:31:44 +02:00
if ( propertyName = = " application.process.id " )
{
2019-09-15 01:44:12 +02:00
current - > processId = stoi ( propertyValue ) ;
}
2019-10-08 00:31:44 +02:00
if ( propertyName = = " application.process.binary " )
{
2019-09-15 01:44:12 +02:00
current - > processBinary = propertyValue . str ( ) ;
}
}
}
}
result . erase ( 0 , pos + delimiter . length ( ) ) ;
}
2019-10-08 00:31:44 +02:00
if ( isValidDevice ( current ) )
{
2019-09-15 01:44:12 +02:00
streams . push_back ( current ) ;
}
2019-10-08 00:31:44 +02:00
for ( auto stream : streams )
{
if ( stream - > driver = = " <protocol-native.c> " )
{
2019-09-15 01:44:12 +02:00
ui - > outputApplication - > addItem ( QString ( stream - > processBinary . c_str ( ) ) ) ;
}
}
2019-09-15 02:50:45 +02:00
// This automatically sets the selected item to the previous one. if it does not exists it does nothing
ui - > outputApplication - > setCurrentText ( previouslySelected ) ;
// Return if the output was not changed
return ui - > outputApplication - > currentText ( ) = = previouslySelected ;
2019-09-15 01:44:12 +02:00
}
MainWindow : : ~ MainWindow ( )
{
delete ui ;
}
2019-10-08 00:31:44 +02:00
void MainWindow : : playSound ( string path )
{
//TODO: Remove this and stop old playback or enable multiple sounds at once (maybe create a setting for it)
2019-10-09 22:14:11 +02:00
if ( ui - > stopButton - > isEnabled ( ) )
{
2019-10-08 00:31:44 +02:00
return ;
}
2019-09-15 01:44:12 +02:00
2019-09-15 02:50:45 +02:00
// Don't play the sound if the app changed (previous one no longer available)
2019-10-08 00:31:44 +02:00
if ( ! loadSources ( ) )
{
2019-09-15 02:50:45 +02:00
QMessageBox : : warning ( this , " " , tr ( " Output stream no longer available... \n Aborting \n " ) , QMessageBox : : Ok ) ;
return ;
}
2019-10-17 23:30:50 +02:00
bool isMP3 = strstr ( path . c_str ( ) , " .mp3 " ) ;
if ( isMP3 )
{
ostringstream mpg123Check ;
2019-10-17 23:32:06 +02:00
mpg123Check < < " which mpg123 >/dev/null 2>&1 " ;
2019-10-17 23:30:50 +02:00
bool canPlayMP3 = ( system ( mpg123Check . str ( ) . c_str ( ) ) = = 0 ) ;
if ( ! canPlayMP3 )
{
2019-11-07 19:04:12 +01:00
QMessageBox : : critical ( this , " " , tr ( " Can't play mp3 file! \n mpg123 is not installed or not in the $PATH \n Please install it and restart the program \n " ) , QMessageBox : : Ok ) ;
2019-10-17 23:30:50 +02:00
return ;
}
}
2019-09-15 01:44:12 +02:00
// Get selected application
string selectedApp = ui - > outputApplication - > currentText ( ) . toStdString ( ) ;
2019-10-08 00:31:44 +02:00
PulseAudioRecordingStream * selected = nullptr ;
for ( auto stream : streams )
{
if ( stream - > processBinary = = selectedApp )
{
2019-09-15 01:44:12 +02:00
selected = stream ;
}
}
2019-10-08 00:31:44 +02:00
if ( selected )
{
2019-09-15 01:44:12 +02:00
int index = selected - > index ;
string source = selected - > source ;
2019-10-06 01:28:46 +02:00
cout < < " Source before was " < < source < < endl ;
2019-09-15 01:44:12 +02:00
auto moveToSink = " pacmd move-source-output " + to_string ( index ) + " soundboard_sink.monitor " ;
auto moveBack = " pacmd move-source-output " + to_string ( index ) + " " + source ;
2019-10-08 00:31:44 +02:00
// Switch recording stream device to game sink
2019-09-15 01:44:12 +02:00
system ( moveToSink . c_str ( ) ) ;
2019-10-17 23:17:10 +02:00
auto forMe = std : : thread ( [ = ] ( ) {
2019-11-03 23:40:56 +01:00
auto cmdForMe = " paplay --volume= " + to_string ( ui - > volumeSlider - > value ( ) ) + " \" " + path + " \" " ;
2019-10-17 23:30:50 +02:00
if ( isMP3 )
2019-10-17 23:17:10 +02:00
{
2019-11-07 19:04:12 +01:00
cmdForMe = " mpg123 -o pulse -f " + to_string ( ui - > volumeSlider - > value ( ) / 2 ) + " \" " + path + " \" " ;
2019-10-17 23:17:10 +02:00
}
2019-10-06 01:28:46 +02:00
system ( cmdForMe . c_str ( ) ) ;
2019-09-15 01:44:12 +02:00
} ) ;
2019-10-17 23:17:10 +02:00
forMe . detach ( ) ;
2019-09-15 01:44:12 +02:00
2019-10-17 23:17:10 +02:00
auto forOthers = std : : thread ( [ = ] ( ) {
2019-10-08 00:31:44 +02:00
ui - > stopButton - > setDisabled ( false ) ;
2019-11-07 19:04:12 +01:00
ui - > volumeSlider - > setDisabled ( true ) ;
2019-11-03 23:40:56 +01:00
auto cmdForOthers = " paplay -d soundboard_sink --volume= " + to_string ( ui - > volumeSlider - > value ( ) ) + " \" " + path + " \" " ;
2019-10-17 23:30:50 +02:00
if ( isMP3 )
2019-10-17 23:17:10 +02:00
{
2019-11-07 19:04:12 +01:00
cmdForOthers = " mpg123 -o pulse -a soundboard_sink -f " + to_string ( ui - > volumeSlider - > value ( ) / 2 ) + " \" " + path + " \" " ;
2019-10-17 23:17:10 +02:00
}
2019-10-06 01:28:46 +02:00
system ( cmdForOthers . c_str ( ) ) ;
// Switch recording stream device back
system ( moveBack . c_str ( ) ) ;
2019-10-08 00:31:44 +02:00
ui - > stopButton - > setDisabled ( true ) ;
2019-11-07 19:04:12 +01:00
ui - > volumeSlider - > setDisabled ( false ) ;
2019-10-17 23:17:10 +02:00
// Repeat when the check box is checked
if ( ui - > repeatCheckBox - > isChecked ( ) )
{
playSound ( path ) ;
}
2019-10-06 01:28:46 +02:00
} ) ;
2019-10-17 23:17:10 +02:00
forOthers . detach ( ) ;
2019-09-15 01:44:12 +02:00
}
}
2019-10-18 00:03:05 +02:00
void MainWindow : : checkAndChangeVolume ( PulseAudioPlaybackStream * stream , int value )
{
// TODO: Only set it when this was created by Soundboard
// Set the volume if the application is paplay or mpg123
if ( stream - > applicationName = = " paplay " | | stream - > applicationName = = " mpg123 " )
{
system ( ( " pacmd set-sink-input-volume " + to_string ( stream - > index ) + " " + to_string ( value ) ) . c_str ( ) ) ;
}
}
2019-10-17 23:17:10 +02:00
void MainWindow : : syncVolume ( )
{
// Get volume from slider
int value = ui - > volumeSlider - > value ( ) ;
char cmd [ ] = " pacmd list-sink-inputs " ;
string result = getCommandOutput ( cmd ) ;
string delimiter = " \n " ;
size_t pos = 0 ;
string currentLine ;
// Tell me if there is a better way to parse the pulseaudio output
regex reg ( R " rgx(((index: ( \ d+) ) ) | ( driver : ) ( . * ) | ( state : ) ( . * ) | ( flags : ) ( . * ) | ( source : . * ) ( < ( . * ) > ) | ( muted : ) ( . { 0 , 3 } ) | ( [ a - zA - Z - .0 - 9 _ ] * ) \ = \ ( \ " (.*) \" ))rgx " ) ;
smatch sm ;
2019-10-18 00:03:05 +02:00
PulseAudioPlaybackStream * current = nullptr ;
2019-10-17 23:17:10 +02:00
while ( ( pos = result . find ( delimiter ) ) ! = string : : npos )
{
currentLine = result . substr ( 0 , pos ) ;
if ( regex_search ( currentLine , sm , reg ) )
{
auto index = sm [ 3 ] ;
if ( index . length ( ) > 0 )
{
2019-10-18 00:03:05 +02:00
if ( current )
{
checkAndChangeVolume ( current , value ) ;
}
current = new PulseAudioPlaybackStream ( ) ;
current - > index = stoi ( index ) ;
2019-10-17 23:17:10 +02:00
}
else
{
auto propertyName = sm [ 15 ] ;
auto propertyValue = sm [ 17 ] ;
if ( propertyName . length ( ) > 0 )
{
if ( propertyName = = " application.name " )
{
2019-10-18 00:03:05 +02:00
current - > applicationName = propertyValue . str ( ) ;
2019-10-17 23:17:10 +02:00
}
}
}
}
result . erase ( 0 , pos + delimiter . length ( ) ) ;
}
2019-10-18 00:03:05 +02:00
checkAndChangeVolume ( current , value ) ;
2019-10-17 23:17:10 +02:00
}
// Sync volume when the slider value has changed
void MainWindow : : on_volumeSlider_valueChanged ( int value )
{
syncVolume ( ) ;
}
2019-09-15 01:44:12 +02:00
void MainWindow : : on_refreshAppsButton_clicked ( )
{
loadSources ( ) ;
}
void MainWindow : : on_stopButton_clicked ( )
{
2019-10-17 23:17:10 +02:00
// Fix continuous playback
if ( ui - > repeatCheckBox - > isChecked ( ) )
{
ui - > repeatCheckBox - > setChecked ( false ) ;
}
//TODO: Only kill players started from Soundboard
2019-10-06 01:28:46 +02:00
system ( " killall mpg123 " ) ;
2019-10-17 23:17:10 +02:00
system ( " killall paplay " ) ;
2019-10-08 00:31:44 +02:00
ui - > stopButton - > setDisabled ( true ) ;
2019-11-07 19:04:12 +01:00
ui - > volumeSlider - > setDisabled ( false ) ;
2019-09-15 01:44:12 +02:00
}
2019-10-09 22:14:11 +02:00
void MainWindow : : on_addFolderButton_clicked ( )
{
auto selectedFolder = QFileDialog : : getExistingDirectory ( this , ( " Select folder " ) , QDir : : homePath ( ) ) ;
if ( selectedFolder ! = " " )
{
QDir directory ( selectedFolder ) ;
QFileInfo fileInfo ( selectedFolder ) ;
auto created = createTab ( fileInfo . fileName ( ) ) ;
2019-10-17 23:17:10 +02:00
QStringList files = directory . entryList ( { " *.mp3 " , " *.wav " , " *.ogg " } , QDir : : Files ) ;
2019-10-09 22:14:11 +02:00
for ( auto fileName : files )
{
QFile file ( directory . absoluteFilePath ( fileName ) ) ;
addSoundToView ( file , created ) ;
}
saveSoundFiles ( ) ;
}
}
void MainWindow : : addSoundToView ( QFile & file , QListWidget * widget )
{
QFileInfo fileInfo ( file ) ;
auto path = fileInfo . absoluteFilePath ( ) . toStdString ( ) ;
for ( QListWidgetItem * item : widget - > findItems ( " * " , Qt : : MatchWildcard ) )
{
// Check if Sound is already added
if ( path = = item - > toolTip ( ) . toStdString ( ) )
{
2019-10-17 23:17:10 +02:00
auto already = " The sound " + item - > text ( ) . toStdString ( ) + " is already in the list " ;
QMessageBox : : warning ( this , " " , tr ( already . c_str ( ) ) , QMessageBox : : Ok ) ;
2019-10-09 22:14:11 +02:00
return ;
}
}
auto item = new QListWidgetItem ( ) ;
item - > setText ( fileInfo . baseName ( ) ) ;
item - > setToolTip ( fileInfo . absoluteFilePath ( ) ) ;
widget - > addItem ( item ) ;
}
2019-09-15 01:44:12 +02:00
void MainWindow : : on_addSoundButton_clicked ( )
{
2019-10-08 00:31:44 +02:00
if ( ! getActiveView ( ) )
{
createTab ( " Main " ) ;
}
2019-10-17 23:17:10 +02:00
QStringList selectedFiles = QFileDialog : : getOpenFileNames ( this , tr ( " Select file " ) , QDir : : homePath ( ) , tr ( " Sound files (*.mp3 *.wav *.ogg) " ) ) ;
2019-10-08 00:31:44 +02:00
for ( auto selectedFile : selectedFiles )
{
if ( selectedFile ! = " " )
{
2019-10-06 23:25:17 +02:00
QFile file ( selectedFile ) ;
2019-10-09 22:14:11 +02:00
addSoundToView ( file , getActiveView ( ) ) ;
2019-10-06 23:25:17 +02:00
}
2019-09-15 01:44:12 +02:00
}
2019-10-09 22:14:11 +02:00
saveSoundFiles ( ) ;
2019-09-15 01:44:12 +02:00
}
2019-10-08 00:31:44 +02:00
void MainWindow : : on_soundsListWidget_itemDoubleClicked ( QListWidgetItem * listWidgetItem )
{
if ( listWidgetItem )
{
2019-10-07 01:43:35 +02:00
playSound ( listWidgetItem - > toolTip ( ) . toStdString ( ) ) ;
}
}
2019-09-15 01:44:12 +02:00
void MainWindow : : on_removeSoundButton_clicked ( )
{
2019-10-08 00:31:44 +02:00
if ( getActiveView ( ) )
{
QListWidgetItem * it = getActiveView ( ) - > takeItem ( getActiveView ( ) - > currentRow ( ) ) ;
if ( it )
{
delete it ;
2019-10-09 22:14:11 +02:00
saveSoundFiles ( ) ;
2019-10-08 00:31:44 +02:00
}
}
2019-09-15 01:44:12 +02:00
}
void MainWindow : : on_clearSoundsButton_clicked ( )
{
2019-10-08 00:31:44 +02:00
if ( getActiveView ( ) )
{
QMessageBox : : StandardButton resBtn = QMessageBox : : question ( this , " Clear sounds " , tr ( " Are you sure? \n " ) , QMessageBox : : No | QMessageBox : : Yes , QMessageBox : : Yes ) ;
if ( resBtn = = QMessageBox : : Yes )
{
clearSoundFiles ( ) ;
saveSoundFiles ( ) ;
}
2019-09-15 02:50:45 +02:00
}
2019-09-15 01:44:12 +02:00
}
2019-11-03 23:40:56 +01:00
QListWidgetItem * MainWindow : : getSelectedItem ( )
2019-09-15 01:44:12 +02:00
{
2019-10-08 00:31:44 +02:00
if ( getActiveView ( ) )
{
2019-11-03 23:40:56 +01:00
return getActiveView ( ) - > item ( getActiveView ( ) - > currentRow ( ) ) ;
}
return nullptr ;
}
void MainWindow : : on_playSoundButton_clicked ( )
{
QListWidgetItem * it = getActiveView ( ) - > item ( getActiveView ( ) - > currentRow ( ) ) ;
if ( it )
{
playSound ( it - > toolTip ( ) . toStdString ( ) ) ;
2019-10-08 00:31:44 +02:00
}
}
void MainWindow : : on_addTabButton_clicked ( )
{
bool ok ;
2019-11-03 23:40:56 +01:00
QString text = QInputDialog : : getText ( this , " Add a tab " , " Tab Text: " , QLineEdit : : Normal , " " , & ok ) ;
2019-10-08 00:31:44 +02:00
if ( ok & & ! text . isEmpty ( ) )
{
createTab ( text ) ;
2019-10-09 22:44:06 +02:00
saveSoundFiles ( ) ;
2019-09-15 01:44:12 +02:00
}
}
2019-11-03 23:40:56 +01:00
void MainWindow : : on_setHotkeyButton_clicked ( )
{
QListWidgetItem * it = getActiveView ( ) - > item ( getActiveView ( ) - > currentRow ( ) ) ;
if ( it )
{
// TODO: Replace this with an automated user input
bool ok ;
QString keys = QInputDialog : : getText ( this , " Bind " , " Enter keys: " , QLineEdit : : Normal , it - > data ( 1 ) . toString ( ) , & ok ) ;
if ( ok )
{
if ( ! keys . isEmpty ( ) )
{
registerHotkey ( it , keys ) ;
}
else
{
unregisterHotkey ( it ) ;
}
saveSoundFiles ( ) ;
}
}
}
void MainWindow : : registerHotkey ( QListWidgetItem * it , QString keys )
{
// Unregister previous hotkey
unregisterHotkey ( it ) ;
it - > setData ( 1 , keys ) ;
auto neger = QKeySequence ( keys ) ;
auto hotkey = new QHotkey ( QKeySequence ( keys ) , true , this ) ;
if ( hotkey - > isRegistered ( ) )
{
hotkeys . push_back ( hotkey ) ;
auto toPlay = it - > toolTip ( ) . toStdString ( ) ;
connect ( hotkey , & QHotkey : : activated , this , [ = ] ( ) {
playSound ( toPlay ) ;
} ) ;
}
else
{
unregisterHotkey ( it ) ;
QMessageBox : : warning ( this , " Could not register " + keys , " Either the key combination is not valid or it's not possible to use this combination (Maybe another program is using it) " , QMessageBox : : Ok ) ;
}
}
bool compareChar ( char & c1 , char & c2 )
{
if ( c1 = = c2 )
return true ;
else if ( toupper ( c1 ) = = toupper ( c2 ) )
return true ;
return false ;
}
bool caseInSensStringCompare ( string & str1 , string & str2 )
{
return ( ( str1 . size ( ) = = str2 . size ( ) ) & &
equal ( str1 . begin ( ) , str1 . end ( ) , str2 . begin ( ) , & compareChar ) ) ;
}
void MainWindow : : unregisterHotkey ( QListWidgetItem * it )
{
auto previousHotkey = it - > data ( 1 ) ;
if ( ! previousHotkey . isNull ( ) )
{
auto previousHotkeyStr = previousHotkey . toString ( ) . toStdString ( ) ;
for ( QHotkey * hotkey : hotkeys )
{
auto hotkeyStr = hotkey - > shortcut ( ) . toString ( ) . toStdString ( ) ;
if ( caseInSensStringCompare ( hotkeyStr , previousHotkeyStr ) )
{
delete hotkey ;
}
}
// Reset Data
it - > setData ( 1 , QVariant ( ) ) ;
}
}
2019-10-08 00:31:44 +02:00
void MainWindow : : on_tabWidget_tabBarDoubleClicked ( int index )
{
bool ok ;
2019-11-03 23:40:56 +01:00
QString text = QInputDialog : : getText ( this , " Rename tab " , " Tab Text: " , QLineEdit : : Normal , ui - > tabWidget - > tabText ( index ) , & ok ) ;
2019-10-08 00:31:44 +02:00
if ( ok & & ! text . isEmpty ( ) )
2019-09-15 01:44:12 +02:00
{
2019-10-08 00:31:44 +02:00
ui - > tabWidget - > setTabText ( index , text ) ;
saveSoundFiles ( ) ;
2019-09-15 01:44:12 +02:00
}
}
2019-10-08 00:31:44 +02:00
void MainWindow : : on_tabWidget_tabCloseRequested ( int index )
{
QMessageBox : : StandardButton resBtn = QMessageBox : : question ( this , " Delete tab " , tr ( " Are you sure? \n " ) , QMessageBox : : No | QMessageBox : : Yes , QMessageBox : : Yes ) ;
if ( resBtn = = QMessageBox : : Yes )
{
ui - > tabWidget - > removeTab ( index ) ;
saveSoundFiles ( ) ;
}
}
QListWidget * MainWindow : : createTab ( QString title )
{
auto soundsListWidget = new QListWidget ( ) ;
soundsListWidget - > setObjectName ( title ) ;
connect ( soundsListWidget , SIGNAL ( itemDoubleClicked ( QListWidgetItem * ) ) , this , SLOT ( on_soundsListWidget_itemDoubleClicked ( QListWidgetItem * ) ) ) ;
ui - > tabWidget - > addTab ( soundsListWidget , title ) ;
return soundsListWidget ;
}
void MainWindow : : clearSoundFiles ( )
{
if ( getActiveView ( ) )
{
while ( getActiveView ( ) - > count ( ) > 0 )
{
getActiveView ( ) - > takeItem ( 0 ) ;
}
}
}
QListWidget * MainWindow : : getActiveView ( )
{
return ( QListWidget * ) ui - > tabWidget - > widget ( ui - > tabWidget - > currentIndex ( ) ) ;
}
void MainWindow : : saveSoundFiles ( )
{
json jsonTabs = json : : array ( ) ;
for ( auto i = 0 ; i < ui - > tabWidget - > count ( ) ; i + + )
{
auto title = ui - > tabWidget - > tabText ( i ) . toStdString ( ) ;
QListWidget * listWidget = ( QListWidget * ) ui - > tabWidget - > widget ( i ) ;
json tabJson ;
json tabJsonSounds = json : : array ( ) ;
for ( QListWidgetItem * item : listWidget - > findItems ( " * " , Qt : : MatchWildcard ) )
{
json j ;
2019-11-03 23:40:56 +01:00
j [ " name " ] = item - > text ( ) . toStdString ( ) ;
j [ " path " ] = item - > toolTip ( ) . toStdString ( ) ;
auto hotkey = item - > data ( 1 ) ;
if ( ! hotkey . isNull ( ) )
{
auto hotkeyStr = item - > data ( 1 ) . toString ( ) . toStdString ( ) ;
j [ " hotkey " ] = hotkeyStr ;
}
2019-10-08 00:31:44 +02:00
tabJsonSounds . push_back ( j ) ;
}
tabJson [ title ] = tabJsonSounds ;
jsonTabs . push_back ( tabJson ) ;
2019-09-15 01:44:12 +02:00
}
ofstream myfile ;
2019-10-06 01:28:46 +02:00
myfile . open ( soundFilesConfig ) ;
2019-10-08 00:31:44 +02:00
myfile < < jsonTabs . dump ( ) ;
2019-09-15 01:44:12 +02:00
myfile . close ( ) ;
}
2019-10-08 00:31:44 +02:00
void MainWindow : : loadSoundFiles ( )
{
ifstream fileIn ( soundFilesConfig ) ;
if ( fileIn . is_open ( ) )
{
2019-10-09 22:14:11 +02:00
clearSoundFiles ( ) ;
2019-09-15 01:44:12 +02:00
2019-10-09 22:14:11 +02:00
string content ( ( istreambuf_iterator < char > ( fileIn ) ) , istreambuf_iterator < char > ( ) ) ;
2019-09-15 01:44:12 +02:00
json j = json : : parse ( content ) ;
2019-10-08 00:31:44 +02:00
for ( auto item : j . get < vector < json > > ( ) )
{
for ( auto object : item . items ( ) )
{
auto tabName = object . key ( ) . c_str ( ) ;
auto soundsListWidget = createTab ( tabName ) ;
auto childItems = object . value ( ) . get < vector < json > > ( ) ;
for ( auto _child : childItems )
{
2019-11-03 23:40:56 +01:00
auto soundName = _child [ " name " ] ;
auto soundPath = _child [ " path " ] ;
remove ( soundPath . begin ( ) , soundPath . end ( ) , ' " ' ) ;
auto item = new QListWidgetItem ( ) ;
item - > setText ( QString : : fromStdString ( soundName ) ) ;
item - > setToolTip ( QString : : fromStdString ( soundPath ) ) ;
auto soundHotkey = _child [ " hotkey " ] ;
if ( ! soundHotkey . is_null ( ) )
2019-10-08 00:31:44 +02:00
{
2019-11-03 23:40:56 +01:00
// Set hotkey back
registerHotkey ( item , QString : : fromStdString ( soundHotkey ) ) ;
2019-10-08 00:31:44 +02:00
}
2019-11-03 23:40:56 +01:00
soundsListWidget - > addItem ( item ) ;
2019-10-08 00:31:44 +02:00
}
2019-09-15 01:44:12 +02:00
}
}
fileIn . close ( ) ;
}
2019-11-03 23:40:56 +01:00
}