#ifndef SINGLE_SOURCE_COMPILE

/*
 * setup_dialog.cpp - dialog for setting up LMMS
 *
 * Copyright (c) 2005-2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 * 
 * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
 *
 * 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 (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */


#include <QtGui/QComboBox>
#include <QtGui/QFileDialog>
#include <QtGui/QImageReader>
#include <QtGui/QLabel>
#include <QtGui/QLayout>
#include <QtGui/QLineEdit>
#include <QtGui/QMessageBox>
#include <QtGui/QSlider>
#include <QtGui/QWhatsThis>
#include <QtGui/QTableWidget>
#include <QtGui/QHeaderView>


#include "setup_dialog.h"
#include "tab_bar.h"
#include "tab_button.h"
#include "tab_widget.h"
#include "gui_templates.h"
#include "mixer.h"
#include "project_journal.h"
#include "config_mgr.h"
#include "embed.h"
#include "engine.h"
#include "debug.h"
#include "tooltip.h"
#include "led_checkbox.h"
#include "group_box.h"
#include "lcd_spinbox.h"
#include "tool_button.h"
#include "midi_port_menu.h"
#include "midi_control_listener.h"
#include "setup_dialog_mcl.h"


// platform-specific audio-interface-classes
#include "audio_alsa.h"
#include "audio_jack.h"
#include "audio_oss.h"
#include "audio_portaudio.h"
#include "audio_pulseaudio.h"
#include "audio_sdl.h"
#include "audio_dummy.h"

// platform-specific midi-interface-classes
#include "midi_alsa_raw.h"
#include "midi_alsa_seq.h"
#include "midi_oss.h"
#include "midi_winmm.h"
#include "midi_dummy.h"


inline void labelWidget( QWidget * _w, const QString & _txt )
{
	QLabel * title = new QLabel( _txt, _w );
	QFont f = title->font();
	f.setBold( TRUE );
	title->setFont( pointSize<12>( f ) );

#ifdef LMMS_DEBUG
	assert( dynamic_cast<QBoxLayout *>( _w->layout() ) != NULL );
#endif
	dynamic_cast<QBoxLayout *>( _w->layout() )->addSpacing( 5 );
	dynamic_cast<QBoxLayout *>( _w->layout() )->addWidget( title );
	dynamic_cast<QBoxLayout *>( _w->layout() )->addSpacing( 10 );
}




setupDialog::setupDialog( ConfigTabs _tab_to_open ) :
	m_bufferSize( configManager::inst()->value( "mixer",
					"framesperaudiobuffer" ).toInt() ),
	m_toolTips( !configManager::inst()->value( "tooltips",
							"disabled" ).toInt() ),
	m_warnAfterSetup( !configManager::inst()->value( "app",
						"nomsgaftersetup" ).toInt() ),
	m_displaydBV( configManager::inst()->value( "app", 
		      				"displaydbv" ).toInt() ),
	m_MMPZ( !configManager::inst()->value( "app", "nommpz" ).toInt() ),
	m_hqAudioDev( configManager::inst()->value( "mixer",
							"hqaudio" ).toInt() ),
	m_workingDir( configManager::inst()->workingDir() ),
	m_vstDir( configManager::inst()->vstDir() ),
	m_artworkDir( configManager::inst()->artworkDir() ),
	m_flDir( configManager::inst()->flDir() ),
	m_ladDir( configManager::inst()->ladspaDir() ),
#ifdef LMMS_HAVE_FLUIDSYNTH
	m_defaultSoundfont( configManager::inst()->defaultSoundfont() ),
#endif
#ifdef LMMS_HAVE_STK
	m_stkDir( configManager::inst()->stkDir() ),
#endif
	m_backgroundArtwork( configManager::inst()->backgroundArtwork() ),
	m_disableChActInd( configManager::inst()->value( "ui",
				"disablechannelactivityindicators" ).toInt() ),
	m_manualChPiano( configManager::inst()->value( "ui",
					"manualchannelpiano" ).toInt() ),
	m_mclEnabled( engine::getMidiControlListener()->getEnabled() ),
	m_mclChannel( engine::getMidiControlListener()->getChannel() ),
	m_mclUseControlKey( engine::getMidiControlListener()->getUseControlKey() ),
	m_mclActionMapKeys( engine::getMidiControlListener()->getActionMapKeys() ),
	m_mclActionMapControllers( engine::getMidiControlListener()->getActionMapControllers() ),
	m_mclMidiPortMenu( midiPort::Input ),
	m_mclMidiPort( "MCL config",
		      engine::getMixer()->getMidiClient(),
		      &m_mclMep,
		      NULL,
		      midiPort::Input )
{
	setWindowIcon( embed::getIconPixmap( "setup_general" ) );
	setWindowTitle( tr( "Setup LMMS" ) );
	setModal( TRUE );

	engine::getProjectJournal()->setJournalling( FALSE );

	QVBoxLayout * vlayout = new QVBoxLayout( this );
	vlayout->setSpacing( 0 );
	vlayout->setMargin( 0 );
	QWidget * settings = new QWidget( this );
	QHBoxLayout * hlayout = new QHBoxLayout( settings );
	hlayout->setSpacing( 0 );
	hlayout->setMargin( 0 );

	m_tabBar = new tabBar( settings, QBoxLayout::TopToBottom );
	m_tabBar->setExclusive( TRUE );
	m_tabBar->setFixedWidth( 72 );

	QWidget * ws = new QWidget( settings );
	int wsHeight = 336;
#ifdef LMMS_HAVE_STK
	wsHeight += 50;
#endif
#ifdef LMMS_HAVE_FLUIDSYNTH
	wsHeight += 50;
#endif
	ws->setFixedSize( 360, wsHeight );
	QWidget * general = new QWidget( ws );
	general->setFixedSize( 360, 240 );
	QVBoxLayout * gen_layout = new QVBoxLayout( general );
	gen_layout->setSpacing( 0 );
	gen_layout->setMargin( 0 );
	labelWidget( general, tr( "General settings" ) );

	tabWidget * bufsize_tw = new tabWidget( tr( "BUFFER SIZE" ), general );
	bufsize_tw->setFixedHeight( 80 );

	m_bufSizeSlider = new QSlider( Qt::Horizontal, bufsize_tw );
	m_bufSizeSlider->setRange( 1, 256 );
	m_bufSizeSlider->setTickPosition( QSlider::TicksBelow );
	m_bufSizeSlider->setPageStep( 8 );
	m_bufSizeSlider->setTickInterval( 8 );
	m_bufSizeSlider->setGeometry( 10, 16, 340, 18 );
	m_bufSizeSlider->setValue( m_bufferSize / 64 );

	connect( m_bufSizeSlider, SIGNAL( valueChanged( int ) ), this,
						SLOT( setBufferSize( int ) ) );

	m_bufSizeLbl = new QLabel( bufsize_tw );
	m_bufSizeLbl->setGeometry( 10, 40, 200, 24 );
	setBufferSize( m_bufSizeSlider->value() );

	QPushButton * bufsize_reset_btn = new QPushButton(
			embed::getIconPixmap( "reload" ), "", bufsize_tw );
	bufsize_reset_btn->setGeometry( 290, 40, 28, 28 );
	connect( bufsize_reset_btn, SIGNAL( clicked() ), this,
						SLOT( resetBufSize() ) );
	toolTip::add( bufsize_reset_btn, tr( "Reset to default-value" ) );

	QPushButton * bufsize_help_btn = new QPushButton(
			embed::getIconPixmap( "help" ), "", bufsize_tw );
	bufsize_help_btn->setGeometry( 320, 40, 28, 28 );
	connect( bufsize_help_btn, SIGNAL( clicked() ), this,
						SLOT( displayBufSizeHelp() ) );


	tabWidget * misc_tw = new tabWidget( tr( "MISC" ), general );
	misc_tw->setFixedHeight( 120 );

	ledCheckBox * enable_tooltips = new ledCheckBox(
							tr( "Enable tooltips" ),
								misc_tw );
	enable_tooltips->move( 10, 18 );
	enable_tooltips->setChecked( m_toolTips );
	connect( enable_tooltips, SIGNAL( toggled( bool ) ),
					this, SLOT( toggleToolTips( bool ) ) );


	ledCheckBox * restart_msg = new ledCheckBox(
			tr( "Show restart warning after changing settings" ),
								misc_tw );
	restart_msg->move( 10, 36 );
	restart_msg->setChecked( m_warnAfterSetup );
	connect( restart_msg, SIGNAL( toggled( bool ) ),
				this, SLOT( toggleWarnAfterSetup( bool ) ) );


	ledCheckBox * dbv = new ledCheckBox( tr( "Display volume as dBV " ),
								misc_tw );
	dbv->move( 10, 54 );
	dbv->setChecked( m_displaydBV );
	connect( dbv, SIGNAL( toggled( bool ) ),
				this, SLOT( toggleDisplaydBV( bool ) ) );


	ledCheckBox * mmpz = new ledCheckBox(
				tr( "Compress project files per default" ),
								misc_tw );
	mmpz->move( 10, 72 );
	mmpz->setChecked( m_MMPZ );
	connect( mmpz, SIGNAL( toggled( bool ) ),
					this, SLOT( toggleMMPZ( bool ) ) );

	ledCheckBox * hqaudio = new ledCheckBox(
				tr( "HQ-mode for output audio-device" ),
								misc_tw );
	hqaudio->move( 10, 90 );
	hqaudio->setChecked( m_hqAudioDev );
	connect( hqaudio, SIGNAL( toggled( bool ) ),
				this, SLOT( toggleHQAudioDev( bool ) ) );



	gen_layout->addWidget( bufsize_tw );
	gen_layout->addSpacing( 10 );
	gen_layout->addWidget( misc_tw );
	gen_layout->addStretch();



	QWidget * paths = new QWidget( ws );
	int pathsHeight = 356;
#ifdef LMMS_HAVE_STK
	pathsHeight += 55;
#endif
#ifdef LMMS_HAVE_FLUIDSYNTH
	pathsHeight += 55;
#endif
	paths->setFixedSize( 360, pathsHeight );
	QVBoxLayout * dir_layout = new QVBoxLayout( paths );
	dir_layout->setSpacing( 0 );
	dir_layout->setMargin( 0 );
	labelWidget( paths, tr( "Paths" ) );

	// working-dir
	tabWidget * lmms_wd_tw = new tabWidget( tr(
					"LMMS working directory" ).toUpper(),
								paths );
	lmms_wd_tw->setFixedHeight( 48 );

	m_wdLineEdit = new QLineEdit( m_workingDir, lmms_wd_tw );
	m_wdLineEdit->setGeometry( 10, 20, 300, 16 );
	connect( m_wdLineEdit, SIGNAL( textChanged( const QString & ) ), this,
				SLOT( setWorkingDir( const QString & ) ) );

	QPushButton * workingdir_select_btn = new QPushButton(
				embed::getIconPixmap( "project_open", 16, 16 ),
							"", lmms_wd_tw );
	workingdir_select_btn->setFixedSize( 24, 24 );
	workingdir_select_btn->move( 320, 16 );
	connect( workingdir_select_btn, SIGNAL( clicked() ), this,
						SLOT( openWorkingDir() ) );

	// vst-dir
	tabWidget * vst_tw = new tabWidget( tr(
					"VST-plugin directory" ).toUpper(),
								paths );
	vst_tw->setFixedHeight( 48 );

	m_vdLineEdit = new QLineEdit( m_vstDir, vst_tw );
	m_vdLineEdit->setGeometry( 10, 20, 300, 16 );
	connect( m_vdLineEdit, SIGNAL( textChanged( const QString & ) ), this,
					SLOT( setVSTDir( const QString & ) ) );

	QPushButton * vstdir_select_btn = new QPushButton(
				embed::getIconPixmap( "project_open", 16, 16 ),
								"", vst_tw );
	vstdir_select_btn->setFixedSize( 24, 24 );
	vstdir_select_btn->move( 320, 16 );
	connect( vstdir_select_btn, SIGNAL( clicked() ), this,
						SLOT( openVSTDir() ) );

	// artwork-dir
	tabWidget * artwork_tw = new tabWidget( tr(
					"Artwork directory" ).toUpper(),
								paths );
	artwork_tw->setFixedHeight( 48 );

	m_adLineEdit = new QLineEdit( m_artworkDir, artwork_tw );
	m_adLineEdit->setGeometry( 10, 20, 300, 16 );
	connect( m_adLineEdit, SIGNAL( textChanged( const QString & ) ), this,
				SLOT( setArtworkDir( const QString & ) ) );

	QPushButton * artworkdir_select_btn = new QPushButton(
				embed::getIconPixmap( "project_open", 16, 16 ),
							"", artwork_tw );
	artworkdir_select_btn->setFixedSize( 24, 24 );
	artworkdir_select_btn->move( 320, 16 );
	connect( artworkdir_select_btn, SIGNAL( clicked() ), this,
						SLOT( openArtworkDir() ) );



	// background artwork file
	tabWidget * backgroundArtwork_tw = new tabWidget( tr(
			"Background artwork" ).toUpper(), paths );
	backgroundArtwork_tw->setFixedHeight( 48 );

	m_baLineEdit = new QLineEdit( m_backgroundArtwork, 
			backgroundArtwork_tw );
	m_baLineEdit->setGeometry( 10, 20, 300, 16 );
	connect( m_baLineEdit, SIGNAL( textChanged( const QString & ) ), this,
			SLOT( setBackgroundArtwork( const QString & ) ) );

	QPushButton * backgroundartworkdir_select_btn = new QPushButton(
			embed::getIconPixmap( "project_open", 16, 16 ),
			"", backgroundArtwork_tw );
	backgroundartworkdir_select_btn->setFixedSize( 24, 24 );
	backgroundartworkdir_select_btn->move( 320, 16 );
	connect( backgroundartworkdir_select_btn, SIGNAL( clicked() ), this,
					SLOT( openBackgroundArtwork() ) );





	// FL Studio-dir
	tabWidget * fl_tw = new tabWidget( tr(
				"FL Studio installation directory" ).toUpper(),
								paths );
	fl_tw->setFixedHeight( 48 );

	m_fdLineEdit = new QLineEdit( m_flDir, fl_tw );
	m_fdLineEdit->setGeometry( 10, 20, 300, 16 );
	connect( m_fdLineEdit, SIGNAL( textChanged( const QString & ) ), this,
					SLOT( setFLDir( const QString & ) ) );

	QPushButton * fldir_select_btn = new QPushButton(
				embed::getIconPixmap( "project_open", 16, 16 ),
								"", fl_tw );
	fldir_select_btn->setFixedSize( 24, 24 );
	fldir_select_btn->move( 320, 16 );
	connect( fldir_select_btn, SIGNAL( clicked() ), this,
						SLOT( openFLDir() ) );
	// LADSPA-dir
	tabWidget * lad_tw = new tabWidget( tr(
			"LADSPA plugin paths" ).toUpper(),
							paths );
	lad_tw->setFixedHeight( 48 );

	m_ladLineEdit = new QLineEdit( m_ladDir, lad_tw );
	m_ladLineEdit->setGeometry( 10, 20, 300, 16 );
	connect( m_ladLineEdit, SIGNAL( textChanged( const QString & ) ), this,
		 		SLOT( setLADSPADir( const QString & ) ) );

	QPushButton * laddir_select_btn = new QPushButton(
				embed::getIconPixmap( "project_open", 16, 16 ),
								"", lad_tw );
	laddir_select_btn->setFixedSize( 24, 24 );
	laddir_select_btn->move( 320, 16 );
	connect( laddir_select_btn, SIGNAL( clicked() ), this,
				 		SLOT( openLADSPADir() ) );

#ifdef LMMS_HAVE_STK
	// STK-dir
	tabWidget * stk_tw = new tabWidget( tr(
			"STK rawwave directory" ).toUpper(),
							paths );
	stk_tw->setFixedHeight( 48 );

	m_stkLineEdit = new QLineEdit( m_stkDir, stk_tw );
	m_stkLineEdit->setGeometry( 10, 20, 300, 16 );
	connect( m_stkLineEdit, SIGNAL( textChanged( const QString & ) ), this,
		 SLOT( setSTKDir( const QString & ) ) );

	QPushButton * stkdir_select_btn = new QPushButton(
			embed::getIconPixmap( "project_open", 16, 16 ),
								"", stk_tw );
	stkdir_select_btn->setFixedSize( 24, 24 );
	stkdir_select_btn->move( 320, 16 );
	connect( stkdir_select_btn, SIGNAL( clicked() ), this,
		 SLOT( openSTKDir() ) );
#endif

#ifdef LMMS_HAVE_FLUIDSYNTH
	// Soundfont
	tabWidget * sf_tw = new tabWidget( tr(
			"Default Soundfont File" ).toUpper(), paths );
	sf_tw->setFixedHeight( 48 );

	m_sfLineEdit = new QLineEdit( m_defaultSoundfont, sf_tw );
	m_sfLineEdit->setGeometry( 10, 20, 300, 16 );
	connect( m_sfLineEdit, SIGNAL( textChanged( const QString & ) ), this,
		 		SLOT( setDefaultSoundfont( const QString & ) ) );

	QPushButton * sf_select_btn = new QPushButton(
				embed::getIconPixmap( "project_open", 16, 16 ),
								"", sf_tw );
	sf_select_btn->setFixedSize( 24, 24 );
	sf_select_btn->move( 320, 16 );
	connect( sf_select_btn, SIGNAL( clicked() ), this,
				 		SLOT( openDefaultSoundfont() ) );
#endif	


	dir_layout->addWidget( lmms_wd_tw );
	dir_layout->addSpacing( 10 );
	dir_layout->addWidget( vst_tw );
	dir_layout->addSpacing( 10 );
	dir_layout->addWidget( artwork_tw );
	dir_layout->addSpacing( 10 );
	dir_layout->addWidget( backgroundArtwork_tw );
	dir_layout->addSpacing( 10 );
	dir_layout->addWidget( fl_tw );
	dir_layout->addSpacing( 10 );
	dir_layout->addWidget( lad_tw );
#ifdef LMMS_HAVE_STK
	dir_layout->addSpacing( 10 );
	dir_layout->addWidget( stk_tw );
#endif	
#ifdef LMMS_HAVE_FLUIDSYNTH
	dir_layout->addSpacing( 10 );
	dir_layout->addWidget( sf_tw );
#endif	
	dir_layout->addStretch();





	QWidget * performance = new QWidget( ws );
	performance->setFixedSize( 360, 240 );
	QVBoxLayout * perf_layout = new QVBoxLayout( performance );
	perf_layout->setSpacing( 0 );
	perf_layout->setMargin( 0 );
	labelWidget( performance, tr( "Performance settings" ) );

	tabWidget * ui_fx_tw = new tabWidget( tr( "UI effects vs. "
						"performance" ).toUpper(),
								performance );
	ui_fx_tw->setFixedHeight( 70 );

	ledCheckBox * disable_ch_act_ind = new ledCheckBox(
				tr( "Disable channel activity indicators" ),
								ui_fx_tw );
	disable_ch_act_ind->move( 10, 20 );
	disable_ch_act_ind->setChecked( m_disableChActInd );
	connect( disable_ch_act_ind, SIGNAL( toggled( bool ) ),
				this, SLOT( toggleDisableChActInd( bool ) ) );


	ledCheckBox * manual_ch_piano = new ledCheckBox(
			tr( "Only press keys on channel-piano manually" ),
								ui_fx_tw );
	manual_ch_piano->move( 10, 40 );
	manual_ch_piano->setChecked( m_manualChPiano );
	connect( manual_ch_piano, SIGNAL( toggled( bool ) ),
				this, SLOT( toggleManualChPiano( bool ) ) );



	perf_layout->addWidget( ui_fx_tw );
	perf_layout->addStretch();



	QWidget * audio = new QWidget( ws );
	audio->setFixedSize( 360, 200 );
	QVBoxLayout * audio_layout = new QVBoxLayout( audio );
	audio_layout->setSpacing( 0 );
	audio_layout->setMargin( 0 );
	labelWidget( audio, tr( "Audio settings" ) );

	tabWidget * audioiface_tw = new tabWidget( tr( "AUDIO INTERFACE" ),
									audio );
	audioiface_tw->setFixedHeight( 60 );

	m_audioInterfaces = new QComboBox( audioiface_tw );
	m_audioInterfaces->setGeometry( 10, 20, 240, 22 );


	QPushButton * audio_help_btn = new QPushButton(
			embed::getIconPixmap( "help" ), "", audioiface_tw );
	audio_help_btn->setGeometry( 320, 20, 28, 28 );
	connect( audio_help_btn, SIGNAL( clicked() ), this,
						SLOT( displayAudioHelp() ) );


	// create ifaces-settings-widget
	QWidget * asw = new QWidget( audio );
	asw->setFixedHeight( 60 );

	QHBoxLayout * asw_layout = new QHBoxLayout( asw );
	asw_layout->setSpacing( 0 );
	asw_layout->setMargin( 0 );
	//asw_layout->setAutoAdd( TRUE );

#ifdef LMMS_HAVE_JACK
	m_audioIfaceSetupWidgets[audioJACK::name()] =
					new audioJACK::setupWidget( asw );
#endif

#ifdef LMMS_HAVE_ALSA
	m_audioIfaceSetupWidgets[audioALSA::name()] =
					new audioALSA::setupWidget( asw );
#endif

#ifdef LMMS_HAVE_PULSEAUDIO
	m_audioIfaceSetupWidgets[audioPulseAudio::name()] =
					new audioPulseAudio::setupWidget( asw );
#endif

#ifdef LMMS_HAVE_PORTAUDIO
	m_audioIfaceSetupWidgets[audioPortAudio::name()] =
					new audioPortAudio::setupWidget( asw );
#endif

#ifdef LMMS_HAVE_SDL
	m_audioIfaceSetupWidgets[audioSDL::name()] =
					new audioSDL::setupWidget( asw );
#endif

#ifdef LMMS_HAVE_OSS
	m_audioIfaceSetupWidgets[audioOSS::name()] =
					new audioOSS::setupWidget( asw );
#endif
	m_audioIfaceSetupWidgets[audioDummy::name()] =
					new audioDummy::setupWidget( asw );


	for( aswMap::iterator it = m_audioIfaceSetupWidgets.begin();
				it != m_audioIfaceSetupWidgets.end(); ++it )
	{
		m_audioIfaceNames[tr( it.key().toAscii())] = it.key();
	}
	for( trMap::iterator it = m_audioIfaceNames.begin();
				it != m_audioIfaceNames.end(); ++it )
	{
		QWidget * audioWidget = m_audioIfaceSetupWidgets[it.value()];
		audioWidget->hide();
		asw_layout->addWidget( audioWidget );
		m_audioInterfaces->addItem( it.key() );
	}
	m_audioInterfaces->setCurrentIndex( m_audioInterfaces->findText(
			tr( engine::getMixer()->audioDevName().toAscii() ) ) );
	m_audioIfaceSetupWidgets[engine::getMixer()->audioDevName()]->show();

	connect( m_audioInterfaces, SIGNAL( activated( const QString & ) ),
		this, SLOT( audioInterfaceChanged( const QString & ) ) );


	audio_layout->addWidget( audioiface_tw );
	audio_layout->addSpacing( 20 );
	audio_layout->addWidget( asw );
	audio_layout->addStretch();




	QWidget * midi = new QWidget( ws );
	QVBoxLayout * midi_layout = new QVBoxLayout( midi );
	midi_layout->setSpacing( 0 );
	midi_layout->setMargin( 0 );
	labelWidget( midi, tr( "MIDI settings" ) );

	tabWidget * midiiface_tw = new tabWidget( tr( "MIDI INTERFACE" ),
									midi );
	midiiface_tw->setFixedHeight( 60 );

	m_midiInterfaces = new QComboBox( midiiface_tw );
	m_midiInterfaces->setGeometry( 10, 20, 240, 22 );


	QPushButton * midi_help_btn = new QPushButton(
			embed::getIconPixmap( "help" ), "", midiiface_tw );
	midi_help_btn->setGeometry( 320, 20, 28, 28 );
	connect( midi_help_btn, SIGNAL( clicked() ), this,
						SLOT( displayMIDIHelp() ) );


	// create ifaces-settings-widget
	QWidget * msw = new QWidget( midi );
	msw->setFixedHeight( 60 );

	QHBoxLayout * msw_layout = new QHBoxLayout( msw );
	msw_layout->setSpacing( 0 );
	msw_layout->setMargin( 0 );
	//msw_layout->setAutoAdd( TRUE );

#ifdef LMMS_HAVE_ALSA
	m_midiIfaceSetupWidgets[midiALSASeq::name()] =
					new midiALSASeq::setupWidget( msw );
	m_midiIfaceSetupWidgets[midiALSARaw::name()] =
					new midiALSARaw::setupWidget( msw );
#endif

#ifdef LMMS_HAVE_OSS
	m_midiIfaceSetupWidgets[midiOSS::name()] =
					new midiOSS::setupWidget( msw );
#endif

#ifdef LMMS_BUILD_WIN32
	m_midiIfaceSetupWidgets[midiWinMM::name()] =
					new midiWinMM::setupWidget( msw );
#endif

	m_midiIfaceSetupWidgets[midiDummy::name()] =
					new midiDummy::setupWidget( msw );


	for( mswMap::iterator it = m_midiIfaceSetupWidgets.begin();
				it != m_midiIfaceSetupWidgets.end(); ++it )
	{
		m_midiIfaceNames[tr( it.key().toAscii())] = it.key();
	}
	for( trMap::iterator it = m_midiIfaceNames.begin();
				it != m_midiIfaceNames.end(); ++it )
	{
		QWidget * midiWidget = m_midiIfaceSetupWidgets[it.value()];
		midiWidget->hide();
		msw_layout->addWidget( midiWidget );
		m_midiInterfaces->addItem( it.key() );
	}

	m_midiInterfaces->setCurrentIndex( m_midiInterfaces->findText(
		tr( engine::getMixer()->midiClientName().toAscii() ) ) );
	m_midiIfaceSetupWidgets[engine::getMixer()->midiClientName()]->show();

	connect( m_midiInterfaces, SIGNAL( activated( const QString & ) ),
		this, SLOT( midiInterfaceChanged( const QString & ) ) );

	groupBox * midicl_gb = setupMidiControlListener( midi );
	
	midi_layout->addWidget( midiiface_tw );
	midi_layout->addSpacing( 20 );
	midi_layout->addWidget( msw );
	midi_layout->addSpacing( 20 );
	midi_layout->addWidget( midicl_gb );
	midi_layout->addStretch();

	m_tabBar->addTab( general, tr( "General settings" ), 0, FALSE, TRUE 
			)->setIcon( embed::getIconPixmap( "setup_general" ) );
	m_tabBar->addTab( paths, tr( "Paths" ), 1, FALSE, TRUE 
			)->setIcon( embed::getIconPixmap(
							"setup_directories" ) );
	m_tabBar->addTab( performance, tr( "Performance settings" ), 2, FALSE,
				TRUE )->setIcon( embed::getIconPixmap(
							"setup_performance" ) );
	m_tabBar->addTab( audio, tr( "Audio settings" ), 3, FALSE, TRUE
			)->setIcon( embed::getIconPixmap( "setup_audio" ) );
	m_tabBar->addTab( midi, tr( "MIDI settings" ), 4, TRUE, TRUE
			)->setIcon( embed::getIconPixmap( "setup_midi" ) );


	m_tabBar->setActiveTab( _tab_to_open );

	hlayout->addWidget( m_tabBar );
	hlayout->addSpacing( 10 );
	hlayout->addWidget( ws );
	hlayout->addSpacing( 10 );
	hlayout->addStretch();

	QWidget * buttons = new QWidget( this );
	QHBoxLayout * btn_layout = new QHBoxLayout( buttons );
	btn_layout->setSpacing( 0 );
	btn_layout->setMargin( 0 );
	QPushButton * ok_btn = new QPushButton( embed::getIconPixmap( "apply" ),
						tr( "OK" ), buttons );
	connect( ok_btn, SIGNAL( clicked() ), this, SLOT( accept() ) );

	QPushButton * cancel_btn = new QPushButton( embed::getIconPixmap(
								"cancel" ),
							tr( "Cancel" ),
							buttons );
	connect( cancel_btn, SIGNAL( clicked() ), this, SLOT( reject() ) );

	btn_layout->addStretch();
	btn_layout->addSpacing( 10 );
	btn_layout->addWidget( ok_btn );
	btn_layout->addSpacing( 10 );
	btn_layout->addWidget( cancel_btn );
	btn_layout->addSpacing( 10 );

	vlayout->addWidget( settings );
	vlayout->addSpacing( 10 );
	vlayout->addWidget( buttons );
	vlayout->addSpacing( 10 );
	vlayout->addStretch();

	show();


}




setupDialog::~setupDialog()
{
	engine::getProjectJournal()->setJournalling( TRUE );
}




groupBox * setupDialog::setupMidiControlListener( QWidget * midi )
{
	// MIDI control listener
	groupBox * gb = new groupBox( tr( "MIDI REMOTE CONTROL" ),
									midi );
	gb->setFixedHeight( 235 );
	gb->ledButton()->setChecked( m_mclEnabled );
	
	connect( gb->ledButton(), SIGNAL( toggled( bool ) ),
		this, SLOT( toggleMCLEnabled( bool ) ) );
	
	// channel
	lcdSpinBoxModel * channelSbModel = new lcdSpinBoxModel( /* this */ );
	channelSbModel->setRange( 0, 16 );
	channelSbModel->setStep( 1 );
	channelSbModel->setValue( m_mclChannel + 1 );
	lcdSpinBox * channelSb = new lcdSpinBox( 3, gb );
	channelSb->setModel( channelSbModel );
	channelSb->addTextForValue( 0, "---" );
	channelSb->setLabel( tr( "CHANNEL" ) );
	channelSb->move( 20, 20 );
	
	// device
	toolButton * devicesBtn = new toolButton( gb );
	devicesBtn->setText( tr( "MIDI-device to receive "
			     "remote control events from" ) );
	devicesBtn->setIcon( embed::getIconPixmap( "piano" ) );
	devicesBtn->setGeometry( 100, 20, 32, 32 );
	devicesBtn->setMenu( &m_mclMidiPortMenu );
	devicesBtn->setPopupMode( QToolButton::InstantPopup );
	m_mclMidiPortMenu.setModel( &m_mclMidiPort );
	QDomDocument mclDoc;
	QDomElement mclPortConfig = mclDoc.createElement( "devices" );
	engine::getMidiControlListener()->getMidiPort()->saveSettings( 
		mclDoc, mclPortConfig );
	m_mclMidiPort.loadSettings( mclPortConfig );
	
	// use control key
	ledCheckBox * controlKeyCb = new ledCheckBox(
						   tr( "Use control key" ),
						   gb );
	controlKeyCb->move( 20, 60 );
	controlKeyCb->setChecked( m_mclUseControlKey );
	connect( controlKeyCb, SIGNAL( toggled( bool ) ),
		this, SLOT( toggleMCLControlKey( bool ) ) );
	
	// help button
	QPushButton * mclHelpButton = new QPushButton(
			embed::getIconPixmap( "help" ), "", gb );
	mclHelpButton->setGeometry( 320, 20, 28, 28 );
	connect( mclHelpButton, SIGNAL( clicked() ), this,
		SLOT( displayMclHelp() ) );
	
	// action table
	m_mclActionTable = new QTableWidget( gb );
	mclUpdateActionTable();
	
	// add/delete buttons
	QWidget * buttons = new QWidget( gb );
	QVBoxLayout * btn_layout = new QVBoxLayout( buttons );
	btn_layout->setSpacing( 0 );
	btn_layout->setMargin( 0 );
	QPushButton * new_btn = new QPushButton( tr( "New" ), buttons );
	connect( new_btn, SIGNAL( clicked() ), this, SLOT( mclNewAction() ) );
	QPushButton * del_btn = new QPushButton( tr( "Del" ), buttons );
	connect( del_btn, SIGNAL( clicked() ), this, SLOT( mclDelAction() ) );
	
	btn_layout->addWidget( new_btn );
	btn_layout->addSpacing( 5 );
	btn_layout->addWidget( del_btn );
	btn_layout->addStretch();
	buttons->move( 275, 80 );
	
	return gb;
}




void setupDialog::mclUpdateActionTable( void )
{
	m_mclActionTableMap.clear();
	
	QTableWidget * table = m_mclActionTable;
	table->setColumnCount( 2 );
	table->setRowCount( m_mclActionMapKeys.count() + 
			   m_mclActionMapControllers.count() );
	table->setGeometry(20, 80, 250, 148 );
	QStringList headers;
	headers << "Key/Ctrl" << "Action";
	table->setHorizontalHeaderLabels( headers );
	int row = 0;
	QString key2NameMap[] =
	{
		"C", "C#", "D", "D#", "E", "F", 
		"F#", "G", "G#", "A", "A#", "B"
	};
	for( MidiControlListener::ActionMap::const_iterator it = m_mclActionMapKeys.begin(); 
	    it != m_mclActionMapKeys.end(); ++it, ++row )
	{
		int keyNr = it.key();
		QString key = "Key "; 
		key += key2NameMap[ keyNr % 12 ];
		key += QString::number( int( keyNr / 12 ) );
		QTableWidgetItem * item = new QTableWidgetItem( key );
		item->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
		table->setItem( row, 0, item );
		
		QString actionName = MidiControlListener::action2ActionNameMap( it.value() ).name;
		item = new QTableWidgetItem( actionName );
		item->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
		table->setItem( row, 1, item );
		
		table->setRowHeight( row, 20 );
		
		m_mclActionTableMap.append( qMakePair( 'k', keyNr ) );
	}
	
	for( MidiControlListener::ActionMap::const_iterator it = m_mclActionMapControllers.begin(); 
	    it != m_mclActionMapControllers.end(); ++it, ++row )
	{
		QString controller = "Controller #"; 
		controller += QString::number( it.key() );
		QTableWidgetItem * item = new QTableWidgetItem( controller );
		item->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
		table->setItem( row, 0, item );
		
		QString actionName = MidiControlListener::action2ActionNameMap( it.value() ).name;
		item = new QTableWidgetItem( actionName );
		item->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
		table->setItem( row, 1, item );
		
		table->setRowHeight( row, 20 );
		
		m_mclActionTableMap.append( qMakePair( 'c', it.key() ) );
	}
	
	table->setColumnWidth( 0, 100 );
	table->setColumnWidth( 1, 130 );
	table->setEnabled( true );
	table->setShowGrid( false );
	table->setSortingEnabled( false );
	table->setSelectionBehavior( QTableWidget::SelectRows );
	table->verticalHeader()->hide();
	table->setAlternatingRowColors( true );
}




void setupDialog::accept( void )
{
	configManager::inst()->setValue( "mixer", "framesperaudiobuffer",
					QString::number( m_bufferSize ) );
	configManager::inst()->setValue( "mixer", "audiodev",
			m_audioIfaceNames[m_audioInterfaces->currentText()] );
	configManager::inst()->setValue( "mixer", "mididev",
			m_midiIfaceNames[m_midiInterfaces->currentText()] );
	configManager::inst()->setValue( "tooltips", "disabled",
					QString::number( !m_toolTips ) );
	configManager::inst()->setValue( "app", "nomsgaftersetup",
					QString::number( !m_warnAfterSetup ) );
	configManager::inst()->setValue( "app", "displaydbv",
					QString::number( m_displaydBV ) );
	configManager::inst()->setValue( "app", "nommpz",
						QString::number( !m_MMPZ ) );
	configManager::inst()->setValue( "mixer", "hqaudio",
					QString::number( m_hqAudioDev ) );
	configManager::inst()->setValue( "ui",
					"disablechannelactivityindicators",
					QString::number( m_disableChActInd ) );
	configManager::inst()->setValue( "ui", "manualchannelpiano",
					QString::number( m_manualChPiano ) );

	configManager::inst()->setWorkingDir( m_workingDir );
	configManager::inst()->setVSTDir( m_vstDir );
	configManager::inst()->setArtworkDir( m_artworkDir );
	configManager::inst()->setFLDir( m_flDir );
	configManager::inst()->setLADSPADir( m_ladDir );
#ifdef LMMS_HAVE_FLUIDSYNTH
	configManager::inst()->setDefaultSoundfont( m_defaultSoundfont );
#endif
#ifdef LMMS_HAVE_STK
	configManager::inst()->setSTKDir( m_stkDir );
#endif	
	configManager::inst()->setBackgroundArtwork( m_backgroundArtwork );

	// tell all audio-settings-widget to save their settings
	for( aswMap::iterator it = m_audioIfaceSetupWidgets.begin();
				it != m_audioIfaceSetupWidgets.end(); ++it )
	{
		it.value()->saveSettings();
	}
	// tell all MIDI-settings-widget to save their settings
	for( mswMap::iterator it = m_midiIfaceSetupWidgets.begin();
				it != m_midiIfaceSetupWidgets.end(); ++it )
	{
		it.value()->saveSettings();
	}
	
	// MIDI control listener
	MidiControlListener * listener = engine::getMidiControlListener();
	listener->setEnabled( m_mclEnabled );
	listener->setChannel( m_mclChannel );
	listener->setUseControlKey( m_mclUseControlKey );
	listener->setActionMapKeys( m_mclActionMapKeys );
	listener->setActionMapControllers( m_mclActionMapControllers );
	// export port config to XML and import to MCL's port
	QDomDocument mclDoc;
	QDomElement mclPortConfig = mclDoc.createElement( "devices" );
	m_mclMidiPort.saveSettings( mclDoc, mclPortConfig );
	listener->getMidiPort()->unsubscribeAllPorts();
	listener->getMidiPort()->loadSettings( mclPortConfig );
	
	configManager::inst()->saveConfigFile();

	QDialog::accept();
	if( m_warnAfterSetup )
	{
		QMessageBox::information( NULL, tr( "Restart LMMS" ),
					tr( "Please note that most changes "
						"won't take effect until "
						"you restart LMMS!" ),
					QMessageBox::Ok );
	}
}




void setupDialog::setBufferSize( int _value )
{
	const int step = DEFAULT_BUFFER_SIZE / 64;
	if( _value > step && _value % step )
	{
		int mod_value = _value % step;
		if( mod_value < step / 2 )
		{
			m_bufSizeSlider->setValue( _value - mod_value );
		}
		else
		{
			m_bufSizeSlider->setValue( _value + step - mod_value );
		}
		return;
	}

	if( m_bufSizeSlider->value() != _value )
	{
		m_bufSizeSlider->setValue( _value );
	}

	m_bufferSize = _value * 64;
	m_bufSizeLbl->setText( tr( "Frames: %1\nLatency: %2 ms" ).arg(
					m_bufferSize ).arg(
						1000.0f * m_bufferSize /
				engine::getMixer()->processingSampleRate(),
						0, 'f', 1 ) );
}




void setupDialog::resetBufSize( void )
{
	setBufferSize( DEFAULT_BUFFER_SIZE / 64 );
}




void setupDialog::displayBufSizeHelp( void )
{
	QWhatsThis::showText( QCursor::pos(),
			tr( "Here you can setup the internal buffer-size "
					"used by LMMS. Smaller values result "
					"in a lower latency but also may cause "
					"unusable sound or bad performance, "
					"especially on older computers or "
					"systems with a non-realtime "
					"kernel." ) );
}




void setupDialog::toggleToolTips( bool _enabled )
{
	m_toolTips = _enabled;
}




void setupDialog::toggleWarnAfterSetup( bool _enabled )
{
	m_warnAfterSetup = _enabled;
}




void setupDialog::toggleDisplaydBV( bool _enabled )
{
	m_displaydBV = _enabled;
}




void setupDialog::toggleMMPZ( bool _enabled )
{
	m_MMPZ = _enabled;
}




void setupDialog::toggleHQAudioDev( bool _enabled )
{
	m_hqAudioDev = _enabled;
}




void setupDialog::toggleDisableChActInd( bool _disabled )
{
	m_disableChActInd = _disabled;
}




void setupDialog::toggleManualChPiano( bool _enabled )
{
	m_manualChPiano = _enabled;
}





void setupDialog::openWorkingDir( void )
{
	QString new_dir = QFileDialog::getExistingDirectory( this,
					tr( "Choose LMMS working directory" ),
							m_workingDir );
	if( new_dir != QString::null )
	{
		m_wdLineEdit->setText( new_dir );
	}
}




void setupDialog::setWorkingDir( const QString & _wd )
{
	m_workingDir = _wd;
}




void setupDialog::openVSTDir( void )
{
	QString new_dir = QFileDialog::getExistingDirectory( this,
				tr( "Choose your VST-plugin directory" ),
							m_vstDir );
	if( new_dir != QString::null )
	{
		m_vdLineEdit->setText( new_dir );
	}
}




void setupDialog::setVSTDir( const QString & _vd )
{
	m_vstDir = _vd;
}




void setupDialog::openArtworkDir( void )
{
	QString new_dir = QFileDialog::getExistingDirectory( this,
				tr( "Choose artwork-theme directory" ),
							m_artworkDir );
	if( new_dir != QString::null )
	{
		m_adLineEdit->setText( new_dir );
	}
}




void setupDialog::setArtworkDir( const QString & _ad )
{
	m_artworkDir = _ad;
}




void setupDialog::openFLDir( void )
{
	QString new_dir = QFileDialog::getExistingDirectory( this,
				tr( "Choose FL Studio installation directory" ),
							m_flDir );
	if( new_dir != QString::null )
	{
		m_fdLineEdit->setText( new_dir );
	}
}




void setupDialog::openLADSPADir( void )
{
	QString new_dir = QFileDialog::getExistingDirectory( this,
				tr( "Choose LADSPA plugin directory" ),
							m_ladDir );
	if( new_dir != QString::null )
	{
		if( m_ladLineEdit->text() == "" )
		{
			m_ladLineEdit->setText( new_dir );
		}
		else
		{
			m_ladLineEdit->setText( m_ladLineEdit->text() + "," +
								new_dir );
		}
	}
}




void setupDialog::openSTKDir( void )
{
#ifdef LMMS_HAVE_STK
	QString new_dir = QFileDialog::getExistingDirectory( this,
				tr( "Choose STK rawwave directory" ),
							m_stkDir );
	if( new_dir != QString::null )
	{
		m_stkLineEdit->setText( new_dir );
	}
#endif
}




void setupDialog::openDefaultSoundfont( void )
{
#ifdef LMMS_HAVE_FLUIDSYNTH
	QString new_file = QFileDialog::getOpenFileName( this,
				tr( "Choose default SoundFont" ), m_defaultSoundfont, 
				"SoundFont2 Files (*.sf2)" );
	
	if( new_file != QString::null )
	{
		m_sfLineEdit->setText( new_file );
	}
#endif
}




void setupDialog::openBackgroundArtwork( void )
{
	QList<QByteArray> fileTypesList = QImageReader::supportedImageFormats();
	QString fileTypes;
	for( int i = 0; i < fileTypesList.count(); i++ )
	{
		if( fileTypesList[i] != fileTypesList[i].toUpper() )
		{
			if( !fileTypes.isEmpty() )
			{
				fileTypes += " ";
			}
			fileTypes += "*." + QString( fileTypesList[i] );
		}
	}

	QString dir = ( m_backgroundArtwork.isEmpty() ) ?
		m_artworkDir :
		m_backgroundArtwork;
	QString new_file = QFileDialog::getOpenFileName( this,
			tr( "Choose background artwork" ), dir, 
			"Image Files (" + fileTypes + ")" );
	
	if( new_file != QString::null )
	{
		m_baLineEdit->setText( new_file );
	}
}




void setupDialog::setFLDir( const QString & _fd )
{
	m_flDir = _fd;
}




void setupDialog::setLADSPADir( const QString & _fd )
{
	m_ladDir = _fd;
}




void setupDialog::setSTKDir( const QString & _fd )
{
#ifdef LMMS_HAVE_STK
	m_stkDir = _fd;
#endif
}




void setupDialog::setDefaultSoundfont( const QString & _sf )
{
#ifdef LMMS_HAVE_FLUIDSYNTH
	m_defaultSoundfont = _sf;
#endif
}




void setupDialog::setBackgroundArtwork( const QString & _ba )
{
#ifdef LMMS_HAVE_FLUIDSYNTH
	m_backgroundArtwork = _ba;
#endif
}




void setupDialog::audioInterfaceChanged( const QString & _iface )
{
	for( aswMap::iterator it = m_audioIfaceSetupWidgets.begin();
				it != m_audioIfaceSetupWidgets.end(); ++it )
	{
		it.value()->hide();
	}

	m_audioIfaceSetupWidgets[m_audioIfaceNames[_iface]]->show();
}




void setupDialog::displayAudioHelp( void )
{
	QWhatsThis::showText( QCursor::pos(),
				tr( "Here you can select your preferred "
					"audio-interface. Depending on the "
					"configuration of your system during "
					"compilation time you can choose "
					"between ALSA, JACK, OSS and more. "
					"Below you see a box which offers "
					"controls to setup the selected "
					"audio-interface." ) );
}




void setupDialog::midiInterfaceChanged( const QString & _iface )
{
	for( mswMap::iterator it = m_midiIfaceSetupWidgets.begin();
				it != m_midiIfaceSetupWidgets.end(); ++it )
	{
		it.value()->hide();
	}

	m_midiIfaceSetupWidgets[m_midiIfaceNames[_iface]]->show();
}




void setupDialog::displayMIDIHelp( void )
{
	QWhatsThis::showText( QCursor::pos(),
				tr( "Here you can select your preferred "
					"MIDI-interface. Depending on the "
					"configuration of your system during "
					"compilation time you can choose "
					"between ALSA, OSS and more. "
					"Below you see a box which offers "
					"controls to setup the selected "
					"MIDI-interface." ) );
}




void setupDialog::toggleMCLEnabled( bool _enabled )
{
	m_mclEnabled = _enabled;
}




void setupDialog::toggleMCLControlKey( bool _enabled )
{
	m_mclUseControlKey = _enabled;
}




void setupDialog::mclNewAction( void )
{
	setupDialogMCL sdMcl( this );
	sdMcl.exec();
}




void setupDialog::mclDelAction( void )
{
	
	int row = m_mclActionTable->currentRow();
	if( row < 0 )
	{
		return; // sanity check: no row selected
	}
	QPair<char, int> entry = m_mclActionTableMap[ row ];
	if( entry.first == 'k' )
	{
		m_mclActionMapKeys.remove( entry.second );
	}
	else if( entry.first == 'c' )
	{
		m_mclActionMapControllers.remove( entry.second );
	}
	
	mclUpdateActionTable();
}




void setupDialog::mclAddKeyAction( int _key, 
				  MidiControlListener::EventAction _action )
{
	m_mclActionMapKeys[ _key ] = _action;
	mclUpdateActionTable();
}




void setupDialog::mclAddControllerAction( int _controller, 
				  MidiControlListener::EventAction _action )
{
	m_mclActionMapControllers[ _controller ] = _action;
	mclUpdateActionTable();
}




void setupDialog::displayMclHelp( void )
{
	QWhatsThis::showText( QCursor::pos(),
			     tr( "You can remote control LMMS via MIDI: " 
				"start or stop the song, toggle loop mode "
				"or jump to a particular position. "
				"A remote control action can be triggered "
				"either by a keypress or a controller "
				"change. With the 'use control key' option "
				"turned on, you need to press and hold the "
				"control key before issuing a keypress "
				"action. "
			       ) );
}




#include "moc_setup_dialog.cxx"


#endif
