//=============================================================================
//
//   File : libkvidialog.cpp
//   Creation date : Sat Sep 15 2001 01:13:25 by Szymon Stefanek
//
//   This file is part of the KVirc irc client distribution
//   Copyright (C) 2001-2005 Szymon Stefanek (pragma at kvirc dot 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 opinion) 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. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
//=============================================================================


#include "libkvidialog.h"

#include <tqmessagebox.h>
#include <tqlayout.h>
#include "kvi_tal_hbox.h"
#include <tqlineedit.h>
#ifdef COMPILE_USE_QT4
	#include <tq3multilineedit.h>
	#define TQMultiLineEdit Q3MultiLineEdit
	#include <tqdesktopwidget.h>
#else
	#include <tqmultilineedit.h>
#endif
#include <tqevent.h>
#include <tqlabel.h>
#include <tqpushbutton.h>

#include "kvi_locale.h"
#include "kvi_module.h"
#include "kvi_modulemanager.h"
#include "kvi_error.h"
#include "kvi_app.h"
#include "kvi_iconmanager.h"
#include "kvi_console.h"
#include "kvi_iconmanager.h"
#include "kvi_kvs_script.h"
#include "kvi_msgbox.h"

static KviPointerList<TQWidget> * g_pDialogModuleDialogList;

KviKvsCallbackMessageBox::KviKvsCallbackMessageBox(
	const TQString &szCaption,
	const TQString &szText,
	const TQString &szIcon,
	const TQString &szButton0,
	const TQString &szButton1,
	const TQString &szButton2,
	const TQString &szCode,
	KviKvsVariantList * pMagicParams,
	KviWindow * pWindow,bool modal)
: TQMessageBox(
	szCaption,
	szText,
	TQMessageBox::NoIcon,
	szButton0.isEmpty() ? TQMessageBox::NoButton : TQMessageBox::Ok | TQMessageBox::Default,
	szButton1.isEmpty() ? TQMessageBox::NoButton : (szButton2.isEmpty() ? TQMessageBox::No | TQMessageBox::Escape : TQMessageBox::No),
	szButton2.isEmpty() ? TQMessageBox::NoButton : TQMessageBox::Cancel | TQMessageBox::Escape,
	0,0,modal) ,
	KviKvsCallbackObject("dialog.message",pWindow,szCode,pMagicParams,0)
{
	g_pDialogModuleDialogList->append(this);
#ifndef COMPILE_USE_QT4
	setIcon(*(g_pIconManager->getSmallIcon(KVI_SMALLICON_KVIRC)));
#endif

	TQPixmap * pix = g_pIconManager->getImage(szIcon);

	if(pix)setIconPixmap(*pix);
	else {
		if(KviTQString::equalCI(szIcon,"information"))setIcon(TQMessageBox::Information);
		else if(KviTQString::equalCI(szIcon,"warning"))setIcon(TQMessageBox::Warning);
		else if(KviTQString::equalCI(szIcon,"critical"))setIcon(TQMessageBox::Critical);
	}
	if(!szButton0.isEmpty())setButtonText(TQMessageBox::Ok,szButton0);
	if(!szButton1.isEmpty())setButtonText(TQMessageBox::No,szButton1);
	if(!szButton2.isEmpty())setButtonText(TQMessageBox::Cancel,szButton2);
}

KviKvsCallbackMessageBox::~KviKvsCallbackMessageBox()
{
	g_pDialogModuleDialogList->removeRef(this);
}

void KviKvsCallbackMessageBox::done(int code)
{
	TQMessageBox::done(code);

	kvs_int_t iVal = 0;
	
	switch(code)
	{
		case TQMessageBox::No: iVal = 1; break;
		case TQMessageBox::Cancel: iVal = 2; break;
	}

	KviKvsVariantList params;
	params.append(new KviKvsVariant(iVal));

	execute(&params);

	delete this;
}


/*
	@doc: dialog.message
	@type:
		command
	@title:
		dialog.message
	@short:
		Shows a message box
	@syntax:
		dialog.message [-b] (<caption>,<message_text>,<icon>,<button0>[,<button1>[,<button2>[,<magic1>[,<magic2>[...]]]]])
		{
			<callback_command>
		}
	@description:
		Shows a message dialog box with the specified <caption> , <message_text> , <icon> and
		buttons.[br]
		<caption> is a text string that will appear in the caption of the dialog box.[br]
		<message_text> is a text string that will appear in the dialog box and can contain HTML formatting.[br]
		<icon> is an [doc:image_id]image identifier[/doc] that defines an icon to be placed in the dialog box.
		<icon> can be a relative or absolute path to an image file , a signed number (in that case it defines
		an internal KVIrc image) or one of the special strings "critical", "information" and "warning".[br]
		<button0> is the text of the first button (on the left).[br]
		<button1> is the text of the second button (if empty or not given at all, only one button will appear in the dialog).[br]
		<button2> is the text of the third button (if empty or not given, only two buttons will appear in the dialog).[br]
		The first button is always the default button: it is activated when the user presses the
		enter key. The thirs, or the second if the third is not present, is the escape button
		and is activated when the user presses the Esc key.[br]
		<magic1>,<magic2>... are the magic parameters: evaluated at dialog.message call time and passed
		to the <callback_command> as positional parameters.[br]
		If the -b or -modal switch is specified the dialog will have non-blocking modal behaviour:
		it will appear above its parent widget and block its input until it's closed.[br] 
		Once the dialog has been shown , the user will click one of the buttons. At this point the dialog
		is hidden and the <callback_command> is executed passing the number of the button clicked
		as $0 and the magic parameters as positional parameters $1 , $2 , $3....[br]
		Please note that if the user closes the window with the window manager close button , 
		the action is interpreted as a button2 click (that is usually sth as "Cancel").[br]
	@examples:
		[example]
		[comment]# Just a warning dialog[/comment]
		dialog.message("Warning","You're being <b>warned</b>",warning,"Ok"){ echo The user clicked OK; }
		[comment]# A question[/comment]
		dialog.message("And now ?","What do you want to do ?",information,"Go home","Watch TV","Scream")
		{
			if($0 == 0)echo "The user want's to go home"
			else if($0 == 1)echo "The user want's to watch TV"
			else echo "The user wants to scream!"
		}
		[/example]
*/

static bool dialog_kvs_cmd_message(KviKvsModuleCallbackCommandCall * c)
{
	TQString szCaption,szMessage,szIcon,szButton0,szButton1,szButton2;
	KviKvsVariantList params;

	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("caption",KVS_PT_STRING,0,szCaption)
		KVSM_PARAMETER("message",KVS_PT_STRING,0,szMessage)
		KVSM_PARAMETER("icon",KVS_PT_STRING,0,szIcon)
		KVSM_PARAMETER("button0",KVS_PT_STRING,KVS_PF_OPTIONAL,szButton0)
		KVSM_PARAMETER("button1",KVS_PT_STRING,KVS_PF_OPTIONAL,szButton1)
		KVSM_PARAMETER("button2",KVS_PT_STRING,KVS_PF_OPTIONAL,szButton2)
		KVSM_PARAMETER("magic",KVS_PT_VARIANTLIST,KVS_PF_OPTIONAL,params)
	KVSM_PARAMETERS_END(c)
	bool modal;
	if(c->hasSwitch('b',"modal")) modal=true;
	else modal=false;
	TQString szCmd = c->callback()->code();

	KviKvsCallbackMessageBox * box = new KviKvsCallbackMessageBox(
			szCaption,szMessage,szIcon,szButton0,szButton1,szButton2,szCmd,&params,c->window(),modal);
	box->show();

	return true;
}



KviKvsCallbackTextInput::KviKvsCallbackTextInput(
		const TQString &szCaption,
		const TQString &szLabel,
		const TQString &szDefaultText,
		const TQString &szIcon,
		bool bMultiLine,
		const TQString &szButton0,
		const TQString &szButton1,
		const TQString &szButton2,
		const TQString &szCode,
		KviKvsVariantList * pMagicParams,
		KviWindow * pWindow,bool modal)
	: TQDialog(), KviKvsCallbackObject("dialog.textinput",pWindow,szCode,pMagicParams,0)
{
	g_pDialogModuleDialogList->append(this);
	setIcon(*(g_pIconManager->getSmallIcon(KVI_SMALLICON_KVIRC)));
	setModal(modal);
	setCaption(szCaption);

	TQGridLayout * g = new TQGridLayout(this,2,3,5,5);

	TQPixmap * pix = g_pIconManager->getImage(szIcon);

	if(pix)
	{
		TQLabel * il = new TQLabel(this);
		il->setPixmap(*pix);
		il->tqsetAlignment(TQt::AlignCenter);
		g->addWidget(il,0,0);
		TQLabel * tl = new TQLabel(szLabel,this);
		g->addWidget(tl,0,1);
	} else {
		TQLabel * tl = new TQLabel(szLabel,this);
		g->addMultiCellWidget(tl,0,0,0,1);
	}

	g->setColStretch(1,1);

	m_bMultiLine = bMultiLine;

	if(m_bMultiLine)
	{
		m_pEdit = new TQMultiLineEdit(this);
		((TQMultiLineEdit *)m_pEdit)->setText(szDefaultText);
	} else {
		m_pEdit = new TQLineEdit(this);
		((TQLineEdit *)m_pEdit)->setText(szDefaultText);
	}

	g->addMultiCellWidget(m_pEdit,1,1,0,1);

	KviTalHBox * box = new KviTalHBox(this);
	g->addMultiCellWidget(box,2,2,0,1);

	m_iEscapeButton = 0;
	m_iDefaultButton = 0;

	if(!szButton0.isEmpty())
	{
		TQString szB = szButton0;
		bool bDef = false;
		if(KviTQString::equalCIN(szB,"default=",8))
		{
			bDef = true;
			szB.remove(0,8);
			m_iDefaultButton = 0;
		} else if(KviTQString::equalCIN(szB,"escape=",7))
		{
			szB.remove(0,7);
			m_iEscapeButton = 0;
		}
		TQPushButton * pb1 = new TQPushButton(szB,box);
		if(bDef)pb1->setDefault(true);
		connect(pb1,TQT_SIGNAL(clicked()),this,TQT_SLOT(b0Clicked()));
	}

	if(!szButton1.isEmpty())
	{
		TQString szB = szButton1;
		bool bDef = false;
		if(KviTQString::equalCIN(szB,"default=",8))
		{
			bDef = true;
			szB.remove(0,8);
			m_iDefaultButton = 1;
		} else if(KviTQString::equalCIN(szB,"escape=",7))
		{
			szB.remove(0,7);
			m_iEscapeButton = 1;
		}
		TQPushButton * pb2 = new TQPushButton(szB,box);
		if(bDef)pb2->setDefault(true);
		connect(pb2,TQT_SIGNAL(clicked()),this,TQT_SLOT(b1Clicked()));
	}

	if(!szButton2.isEmpty())
	{
		TQString szB = szButton2;
		bool bDef = false;
		if(KviTQString::equalCIN(szB,"default=",8))
		{
			bDef = true;
			szB.remove(0,8);
			m_iDefaultButton = 2;
		} else if(KviTQString::equalCIN(szB,"escape=",7))
		{
			szB.remove(0,7);
			m_iEscapeButton = 2;
		}
		TQPushButton * pb3 = new TQPushButton(szB,box);
		if(bDef)pb3->setDefault(true);
		connect(pb3,TQT_SIGNAL(clicked()),this,TQT_SLOT(b2Clicked()));
	}

}

KviKvsCallbackTextInput::~KviKvsCallbackTextInput()
{
	g_pDialogModuleDialogList->removeRef(this);
}

void KviKvsCallbackTextInput::b0Clicked()
{
	done(0+10);
}

void KviKvsCallbackTextInput::b1Clicked()
{
	done(1+10);
}

void KviKvsCallbackTextInput::b2Clicked()
{
	done(2+10);
}

void KviKvsCallbackTextInput::closeEvent(TQCloseEvent *e)
{
	e->ignore();
	done(m_iEscapeButton+10);
}

void KviKvsCallbackTextInput::done(int code)
{
	if(code >= 10)
	{
		code -= 10;
	} else {
		switch(code)
		{
			case TQDialog::Accepted:
				code = m_iDefaultButton;
			break;
			default:
				code = m_iEscapeButton;
			break;
		}
	}

	TQString txt;
	
	if(m_bMultiLine)
	{
		txt = ((TQMultiLineEdit *)m_pEdit)->text();
	} else {
		txt = ((TQLineEdit *)m_pEdit)->text();
	}

	KviKvsVariantList params;
	params.append(new KviKvsVariant((kvs_int_t)code));
	params.append(new KviKvsVariant(txt));

	execute(&params);

	//TQDialog::done(code);

	delete this;
}

void KviKvsCallbackTextInput::showEvent(TQShowEvent *e)
{
	move((g_pApp->desktop()->width() - width())/2,(g_pApp->desktop()->height() - height()) / 2);
	TQDialog::showEvent(e);
}



/*
	@doc: dialog.textinput
	@type:
		command
	@title:
		dialog.textinput
	@short:
		Shows a dialog that accepts user input as text
	@syntax:
		dialog.textinput [-d=<default text>] [-i=<icon>] [-m] [-b] (<caption>,<info_text>,<button0>[,<button1>[,<button2>[,<magic1>[,<magic2>[...]]]]])
		{
			<callback_command>
		}
	@switches:
		!sw: -d=<default_text> | --default=<default_text>
		Set the initial text input value to <default_text>
		!sw: -i=<icon> | --icon=<icon>
		Display the specified icon, just of the left of the informational text
		!sw: -m | --multiline
		Input multiline text instead of single line
	@description:
		Shows a text input dialog box with the specified <caption> , <info_text> , <icon> and
		buttons.[br]
		<caption> is a text string that will appear in the caption of the dialog box.[br]
		<info_text> is a fixed text string that will appear in the dialog box and can contain HTML formatting.[br]
		<button0> is the text of the first button (on the left).[br]
		<button1> is the text of the second button (if empty or not given at all, only one button will appear in the dialog).[br]
		<button2> is the text of the third button (if empty or not given, only two buttons will appear in the dialog).[br]
		If one of the text strings starts with a "default=" prefix then the button is assumed
		to be the default button of the dialog and will be also activated when the user presses enter.
		If the -m switch is used , the dialog will be a multi-line text input, otherwise the user will be able to
		input only a single line of text.[br]
		If the -d switch is used , the initial text input value is set to <default text>.[br]
		If the -i switch is used , the dialog displays also the icon <icon> , just on the left ot the <info_text>[br]
		If the -b or -modal switch is specified the dialog will have non-blocking modal behaviour:
		it will appear above its parent widget and block its input until it's closed.[br] 
		In that case <icon> is an [doc:image_id]image identifier[/doc] (can be a relative or absolute
		path to an image file or a signed number (in that case it defines an internal KVIrc image).[br]
		<magic1>,<magic2>... are the magic parameters: evaluated at dialog.textinput call time and passed
		to the <callback_command> as positional parameters.[br]
		Once the dialog has been shown , the user will click one of the buttons. At this point the dialog
		is hidden and the <callback_command> is executed passing the text input value in $1, the number of the button clicked
		as $0, and the magic parameters as positional parameters $2 , $3 , $4....[br]
		Please note that if the user closes the window with the window manager close button , 
		the action is interpreted as a button2 click (that is usually sth as "Cancel").[br]
	@examples:
		[example]
		[comment]# We need a single line "reason"[/comment]
		dialog.textinput -d="Working !" (Away,<center>Please enter the <h1>away message</h1></center>,"Ok","Cancel")
		{
			switch($0)
			{
				case(0):
					away $1-
				break;
				default:
					# Cancelled
				break;
			}
		}
		[/example]
*/

static bool dialog_kvs_cmd_textinput(KviKvsModuleCallbackCommandCall * c)
{
	TQString szCaption,szInfoText,szIcon,szDefaultText,szButton0,szButton1,szButton2;
	KviKvsVariantList params;

	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("caption",KVS_PT_STRING,0,szCaption)
		KVSM_PARAMETER("info_text",KVS_PT_STRING,0,szInfoText)
		KVSM_PARAMETER("button0",KVS_PT_STRING,KVS_PF_OPTIONAL,szButton0)
		KVSM_PARAMETER("button1",KVS_PT_STRING,KVS_PF_OPTIONAL,szButton1)
		KVSM_PARAMETER("button2",KVS_PT_STRING,KVS_PF_OPTIONAL,szButton2)
		KVSM_PARAMETER("magic",KVS_PT_VARIANTLIST,KVS_PF_OPTIONAL,params)
	KVSM_PARAMETERS_END(c)

	TQString szCmd = c->callback()->code();

	c->switches()->getAsStringIfExisting('i',"icon",szIcon);
	c->switches()->getAsStringIfExisting('d',"default",szDefaultText);
	bool modal;
	if(c->hasSwitch('b',"modal")) modal=true;
	else modal=false;
	KviKvsCallbackTextInput * box = new KviKvsCallbackTextInput(
			szCaption,szInfoText,szDefaultText,szIcon,c->switches()->find('m',"multiline"),
			szButton0,szButton1,szButton2,szCmd,&params,c->window(),modal);
	box->show();

	return true;
}



//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


// New KVS
KviKvsCallbackFileDialog::KviKvsCallbackFileDialog(
		const TQString &szCaption,
		const TQString &szInitialSelection,
		const TQString &szFilter,
		const TQString &szCode,
		KviKvsVariantList * pMagicParams,
		KviWindow * pWindow,bool modal)
	: KviFileDialog(szInitialSelection,szFilter,0,0,modal), KviKvsCallbackObject("dialog.file",pWindow,szCode,pMagicParams,0)
{
	g_pDialogModuleDialogList->append(this);
	setCaption(szCaption);
}

KviKvsCallbackFileDialog::~KviKvsCallbackFileDialog()
{
	g_pDialogModuleDialogList->removeRef(this);
}

void KviKvsCallbackFileDialog::done(int code)
{
	KviFileDialog::done(code);
	KviKvsVariantList params;

	if(code == TQDialog::Accepted)
	{
#ifdef COMPILE_KDE_SUPPORT
		if(mode() == KFile::ExistingOnly)
#else
		if(mode() == TQFileDialog::ExistingFiles)
#endif
		{
			KviKvsArray * a = new KviKvsArray();
			TQStringList sl = selectedFiles();
			int idx = 0;
			for(TQStringList::Iterator it = sl.begin();it != sl.end();++it)
			{
				a->set(idx,new KviKvsVariant(*it));
				idx++;
			}
			params.append(new KviKvsVariant(a));
		} else {
			params.append(new KviKvsVariant(selectedFile()));
		}
	} else {
		params.append(new KviKvsVariant(TQString("")));
	}

	hide(); // ensure we're hidden

	// ugly workaround for the TQt filedialog "destructive accept() before this reference" bug
	// we can't delete ourselves in this moment.... :(((
	// ...so skip out of this call stack and ask KviApp to destroy us just
	// when the control returns to the main loop.
	// If the module is unloaded then , KviApp will notice it and will NOT delete the dialog
	g_pApp->collectGarbage(TQT_TQOBJECT(this));

	// calling dialog.unload here WILL lead to a sigsegv (this is SURE
	// with a lot of qt versions that have the ugly file dialog "accept before this reference" bug)
	// to avoid it, we can execute the callback triggered by a timer...
	// ... umpf ...
	execute(&params);
}

/*
	@doc: dialog.file
	@type:
		command
	@title:
		dialog.file
	@short:
		Shows a file dialog
	@syntax:
		dialog.file [-b] (<mode>,<caption>[,<initial_selection[,<file_filter>[,<magic1>[,<magic2>[...]]]]]])
		{
			<callback_command>
		}
	@description:
		Shows an openfile dialog box with the specified <caption> , <initial_selection> , and <file_filter>.[br]
		<mode> can be "open" , "openm" , "save" or "dir":[br]
		"open" causes the dialog to return an existing file[br]
		"openm" is similar to open but allows returning multiple files as a comma separated list[br]
		"save" causes the dialog to return any file name (no overwrite confirmation is built in the dialog!)[br]
		"dir" causes the dialog to return an existing directory name[br]
		<mode> defaults to "open".[br]
		<caption> is a text string that will appear in the caption of the dialog box.[br]
		<initial_selection> can be a directory or filename that will be initially selected in the dialog.[br]
		Only files matching <file_filter> are selectable. If filter is an empty string, all files are selectable.[br]
		In the filter string multiple filters can be specified separated by either two semicolons next to each
		other or separated by newlines. To add two filters, one to show all C++ files and one to show all 
		header files, the filter string could look like "C++ Files (*.cpp *.cc *.C *.cxx *.c++);;Header Files (*.h *.hxx *.h++)" 
		<magic1>,<magic2>... are the magic parameters: evaluated at dialog.message call time and passed
		to the <callback_command> as positional parameters.[br]
		If the -b or -modal switch is specified the dialog will have non-blocking modal behaviour:
		it will appear above its parent widget and block its input until it's closed.[br] 
		Once the dialog has been shown , the user will select an EXISTING file and click either
		Ok or Cancel. At this point the dialog is hidden and the <callback_command> is executed passing the selected file(s) as $0
		and the magic parameters as positional parameters $1 , $2 , $3....[br]
		If the user clicks "Cancel" or does not select any file the positional parameter $0 will be empty.[br]
	@examples:
		[example]
			dialog.file(open,Choose an audio file,/home/pragma/TheAudio.au,"Audio files (*.au *.wav *.snd)")
			{
				if("$0" != "")run play $0
			}
		[/example]
*/

//#warning "Examples for these dialogs!"


static bool dialog_kvs_cmd_file(KviKvsModuleCallbackCommandCall * c)
{
	TQString szMode,szCaption,szInitialSelection,szFilter;
	KviKvsVariantList params;

	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("mode",KVS_PT_STRING,0,szMode)
		KVSM_PARAMETER("caption",KVS_PT_STRING,0,szCaption)
		KVSM_PARAMETER("initial_selection",KVS_PT_STRING,KVS_PF_OPTIONAL,szInitialSelection)
		KVSM_PARAMETER("filter",KVS_PT_STRING,KVS_PF_OPTIONAL,szFilter)
		KVSM_PARAMETER("magic",KVS_PT_VARIANTLIST,KVS_PF_OPTIONAL,params)
	KVSM_PARAMETERS_END(c)
	bool modal;
	if(c->hasSwitch('b',"modal")) modal=true;
	else modal=false;
	TQString szCmd = c->callback()->code();

	KviKvsCallbackFileDialog * box = new KviKvsCallbackFileDialog(szCaption,szInitialSelection,szFilter,szCmd,&params,c->window(),modal);

	KviFileDialog::FileMode md = KviFileDialog::ExistingFile;

	if(KviTQString::equalCI(szMode,"openm"))md = KviFileDialog::ExistingFiles;
	else if(KviTQString::equalCI(szMode,"save"))md = KviFileDialog::AnyFile;
	else if(KviTQString::equalCI(szMode,"dir"))md = KviFileDialog::DirectoryOnly;

	box->setFileMode(md);

	box->show();

	return true;
}



//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


// New KVS
KviKvsCallbackImageDialog::KviKvsCallbackImageDialog(
		const TQString &szCaption,
		const TQString &szInitialSelection,
		int iType,
		int iMaxSize,
		const TQString &szCode,
		KviKvsVariantList * pMagicParams,
		KviWindow * pWindow,bool modal)
	: KviImageDialog(0,szCaption,iType,0,szInitialSelection,iMaxSize,modal), KviKvsCallbackObject("dialog.image",pWindow,szCode,pMagicParams,0)
{
	g_pDialogModuleDialogList->append(this);
}

KviKvsCallbackImageDialog::~KviKvsCallbackImageDialog()
{
	g_pDialogModuleDialogList->removeRef(this);
}

void KviKvsCallbackImageDialog::done(int code)
{
	KviImageDialog::done(code);
	KviKvsVariantList params;

	if(code == TQDialog::Accepted)
	{
		params.append(new KviKvsVariant(selectedImage()));
	} else {
		params.append(new KviKvsVariant(TQString("")));
	}

	hide(); // ensure we're hidden

	// ugly workaround for the TQt filedialog "destructive accept() before this reference" bug
	// we can't delete ourselves in this moment.... :(((
	// ...so skip out of this call stack and ask KviApp to destroy us just
	// when the control returns to the main loop.
	// If the module is unloaded then , KviApp will notice it and will NOT delete the dialog
	g_pApp->collectGarbage(TQT_TQOBJECT(this));

	// calling dialog.unload here WILL lead to a sigsegv (this is SURE
	// with a lot of qt versions that have the ugly file dialog "accept before this reference" bug)
	// to avoid it, we can execute the callback triggered by a timer...
	// ... umpf ...
	execute(&params);
}


/*
	@doc: dialog.image
	@type:
		command
	@title:
		dialog.image
	@short:
		Shows a image dialog
	@syntax:
		dialog.image [-b] (<type>,<caption>,<initial_directory>,[<maxsize>,[,<magic1>[,<magic2>[...]]]]]])
		{
			<callback_command>
		}
	@description:
		Shows a dialog that allows selecting an [doc:image_id]image_id[doc].
		The <type> parameter must be a combination of the following flags:<br>
		's' : allow selecting from the KVIrc builtin small icons<br>
		'f' : allow browsing the local directories<br>
		'a' : all of the above<br>
		The default for <type> is 'a'.<br>
		<caption> is the caption string for the dialog.<br>
		<initial_directory> makes sense only if 'f' is specified (if <initial_directory> is empty
		then the last path used by the image dialog will be used).<br>
		<maxsize> is the maximum size of the images for that the preview will be generated:
		this is 256000 bytes by default (if unspecified). Don't make it a lot bigger : it can take a lot to make
		the thumbnails for bigger images (and it can eat a considerable amount of memory).<br>
		<magic1>,<magic2>... are the magic parameters: evaluated at dialog.image call time and passed
		to the <callback_command> as positional parameters.[br]
		If the -b or -modal switch is specified the dialog will have non-blocking modal behaviour:
		it will appear above its parent widget and block its input until it's closed.[br] 
		Once the dialog has been shown , the user will select an EXISTING file and click either
		Ok or Cancel. At this point the dialog is hidden and the <callback_command> is executed passing the selected file(s) as $0
		and the magic parameters as positional parameters $1 , $2 , $3....[br]
		If the user clicks "Cancel" or does not select any image the positional parameter $0 will be empty.[br]
	@examples:
		[example]
			dialog.image(f,Choose an image file,/home/pragma/,"256000")
			{
				if("$0" != "")run kview $0
			}
		[/example]
*/

//#warning "Examples for these dialogs!"


static bool dialog_kvs_cmd_image(KviKvsModuleCallbackCommandCall * c)
{
	TQString szType,szCaption,szInitialSelection;
	kvs_uint_t iMaxSize;
	KviKvsVariantList params;

	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("mode",KVS_PT_STRING,0,szType)
		KVSM_PARAMETER("caption",KVS_PT_STRING,0,szCaption)
		KVSM_PARAMETER("initial_directory",KVS_PT_STRING,0,szInitialSelection)
		KVSM_PARAMETER("maxsize",KVS_PT_UINT,KVS_PF_OPTIONAL,iMaxSize)
		KVSM_PARAMETER("magic",KVS_PT_VARIANTLIST,KVS_PF_OPTIONAL,params)
	KVSM_PARAMETERS_END(c)
	bool modal;
	if(c->hasSwitch('b',"modal")) modal=true;
	else modal=false;
	TQString szCmd = c->callback()->code();

	int iType = 0;

	if(szType.contains('s'))iType |= KID_TYPE_BUILTIN_IMAGES_SMALL;
	if(szType.contains('f'))iType |= KID_TYPE_FULL_PATH;
	if(szType.isEmpty())iType = KID_TYPE_ALL;

	if(iMaxSize < 1)iMaxSize = 256000;

	KviKvsCallbackImageDialog * box = new KviKvsCallbackImageDialog(szCaption,szInitialSelection,iType,iMaxSize,szCmd,&params,c->window(),modal);

	box->show();

	return true;
}

/*
	@doc: dialog.yesno
	@type:
		function
	@title:
		$dialog.yesno
	@short:
		Shows a simple yes/no dialog
	@syntax:
		$dialog.yesno(<caption:string>,<szText:string>)
	@description:
		Shows a simple yes/no dialog. Returns 1 if user clicks "Yes" and 0 if (s)he clicks "No".
		Please note that this dialog is BLOCKING: it blocks execution of the script
		until the user has selected either YES or NO.
	@examples:
	@seealso:
*/

static bool dialog_kvs_fnc_yesno(KviKvsModuleFunctionCall * c)
{
	TQString szCaption;
	TQString szText;
	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("caption",KVS_PT_STRING,0,szCaption)
		KVSM_PARAMETER("text",KVS_PT_STRING,0,szText)
	KVSM_PARAMETERS_END(c)
	
	c->enterBlockingSection();
	bool yes=KviMessageBox::yesNo(szCaption,szText); // this will happily crash on quit ?
	if(!c->leaveBlockingSection())return true; // just die
	c->returnValue()->setBoolean(yes);
	return true;
}

/*

static int g_iLocalEventLoops = 0;

static bool dialog_module_cmd_unload(KviModule *m,KviCommand *c)
{
	// We use local loops in this module: we must FORBID explicit unloading of the
	// module while local even loops are running
	ENTER_STACK_FRAME(c,"dialog_module_cmd_unload");
	c->warning(__tr("The dialog module can't be explicitly unloaded: a modal dialog is currently open"));
	return c->leaveStackFrame();
}

static void dialog_module_entering_local_loop(KviModule * m)
{
	// Replace unload
	g_iLocalEventLoops++;
	if(g_iLocalEventLoops == 1)m->registerCommand("unload",dialog_module_cmd_unload);
}

static void dialog_module_exiting_local_loop(KviModule * m)
{
	g_pModuleManager->registerDefaultCommands(m);
	g_iLocalEventLoops--;
}

static bool dialog_module_fnc_textline(KviModule *m,KviCommand *c,KviParameterList * parms,KviStr &buffer)
{
	ENTER_STACK_FRAME(c,"dialog_module_fnc_textline");

	KviStr caption = parms->safeFirstParam();
	KviStr info    = parms->safeNextParam();
	KviStr initial = parms->safeNextParam();

	dialog_module_entering_local_loop(m);
	TQMessageBox::information(0,caption.ptr(),info.ptr(),TQMessageBox::Ok);
	dialog_module_exiting_local_loop(m);

	// It might be that the current window is no longer available!!!

	return c->leaveStackFrame();
}

*/

/*
	@doc: noblockingdialogs
	@type:
		generic
	@title:
		Why there are no blocking dialogs in KVIrc ?
	@short:
		Tecnical answer
	@description:
		Why there are no blocking dialogs in KVIrc ?[br]
		The answer is simple: because they're more confusing and tricky than it seems.[br]
		Blocking the entire program control flow while showing a dialog is
		rather a bad idea since we have to deal with external entities (servers and other users)
		that are NOT blocked. This means that the blocking dialogs must block only the
		script control-flow but let the rest of the application running.
		Such blocking dialogs actually seem to simplify scripting because
		the programmer "feels" that the control is always left in the script snippet that he is writing.
		This is actually confusing: the control IS in the script snippet but while the dialog
		is open the whole world can change: you can return from the dialog call and discover
		that the server connection no longer exists and the application is about to quit.[br]
		This may happen even with non-blocking dialogs ,but in non-blocking mode you have
		a way to handle this event. Consider the following snippet of code:[br]
		[example]
			echo My name is $?
		[/example]
		Where $? stands for a blocking input dialog that asks the user for some text.[br]
		When the input dialog returns the window that the echo was directed to no longer
		exists and you have no way to stop the echo! (Well...I could add extra code
		in the executable to handle all these situations but that would be really too expensive).[br]
		With object scripting this is actually dangerous: you might use a blocking dialog
		in an object signal handler and when returning discover that this object has been deleted!
		(The example refers to a simple object , but think about a complex hierarchy of objects
		where one random gets deleted...).[br]
		This is why the dialogs in KVIrc are non-blocking :)[br]
		That's REAL programming.
*/







static bool dialog_module_init(KviModule * m)
{
	g_pDialogModuleDialogList = new KviPointerList<TQWidget>;
	g_pDialogModuleDialogList->setAutoDelete(false);

	KVSM_REGISTER_CALLBACK_COMMAND(m,"message",dialog_kvs_cmd_message);
	KVSM_REGISTER_CALLBACK_COMMAND(m,"textinput",dialog_kvs_cmd_textinput);
	KVSM_REGISTER_CALLBACK_COMMAND(m,"file",dialog_kvs_cmd_file);
	KVSM_REGISTER_CALLBACK_COMMAND(m,"image",dialog_kvs_cmd_image);

	KVSM_REGISTER_FUNCTION(m,"yesno",dialog_kvs_fnc_yesno);

	return true;
}

static bool dialog_module_cleanup(KviModule *m)
{
	// Here we get a tragedy if g_iLocalEventLoops > 0!
	while(g_pDialogModuleDialogList->first())delete g_pDialogModuleDialogList->first();
	delete g_pDialogModuleDialogList;
	g_pDialogModuleDialogList = 0;
	return true;
}

static bool dialog_module_can_unload(KviModule *m)
{
	return g_pDialogModuleDialogList->isEmpty();
}


KVIRC_MODULE(
	"KVIrc script dialogs",
	"1.0.0",
	"Szymon Stefanek <pragma at kvirc dot net>" ,
	"Adds the /dialog.* commands functionality\n",
	dialog_module_init ,
	dialog_module_can_unload,
	0,
	dialog_module_cleanup
)

#include "libkvidialog.moc"