/* vi:set ts=8 sts=0 sw=8:
 *
 * VIM - Vi IMproved		by Bram Moolenaar
 *
 * Do ":help uganda"  in Vim to read copying and usage conditions.
 * Do ":help credits" in Vim to see a list of people who contributed.
 */

/*
 * Porting to KDE(2) was done by
 *
 *  (C) 2000 by Thomas Capricelli <orzel@kde.org>
 *
 *  Please visit http://klotski.berlios.de/kvim for other vim- or
 *  kde-related coding.
 *
 *  $Id: gui_kde_widget.cc,v 1.11 2002/04/02 06:40:34 marchand Exp $
 *
 */


#include <assert.h>

#include <qpainter.h>
#include <qpushbutton.h>
#include <qscrollbar.h>
#include <qlayout.h>
#include <qclipboard.h>
#include <qdragobject.h>
#include <qstrlist.h>
#if QT_VERSION>=300
#include <qptrlist.h>
#endif
#include <kurldrag.h>
#include "gui_kde_widget.h"


// Pixmap for dialog 
#ifdef FEAT_GUI_DIALOG
# include "../../pixmaps/alert.xpm"
# include "../../pixmaps/error.xpm"
# include "../../pixmaps/generic.xpm"
# include "../../pixmaps/info.xpm"
# include "../../pixmaps/quest.xpm"
#endif
 
/**
 * Keycodes recognized by vim.
 */
struct special_key {
    int qtkey;
    char_u code0;
    char_u code1;
} special_keys[] =
{
    { Qt::Key_Up,		'k', 'u' },
    { Qt::Key_Down,		'k', 'd' },
    { Qt::Key_Left,		'k', 'l' },
    { Qt::Key_Right,		'k', 'r' },
    { Qt::Key_F1,		'k', '1' },
    { Qt::Key_F2,		'k', '2' },
    { Qt::Key_F3,		'k', '3' },
    { Qt::Key_F4,		'k', '4' },
    { Qt::Key_F5,		'k', '5' },
    { Qt::Key_F6,		'k', '6' },
    { Qt::Key_F7,		'k', '7' },
    { Qt::Key_F8,		'k', '8' },
    { Qt::Key_F9,		'k', '9' },
    { Qt::Key_F10,		'k', ';' },
    { Qt::Key_F11,		'F', '1' },
    { Qt::Key_F12,		'F', '2' },
    { Qt::Key_F13,		'F', '3' },
    { Qt::Key_F14,		'F', '4' },
    { Qt::Key_F15,		'F', '5' },
    { Qt::Key_F16,		'F', '6' },
    { Qt::Key_F17,		'F', '7' },
    { Qt::Key_F18,		'F', '8' },
    { Qt::Key_F19,		'F', '9' },
    { Qt::Key_F20,		'F', 'A' },
    { Qt::Key_F21,		'F', 'B' },
    { Qt::Key_F22,		'F', 'C' },
    { Qt::Key_F23,		'F', 'D' },
    { Qt::Key_F24,		'F', 'E' },
    { Qt::Key_F25,		'F', 'F' },
    { Qt::Key_F26,		'F', 'G' },
    { Qt::Key_F27,		'F', 'H' },
    { Qt::Key_F28,		'F', 'I' },
    { Qt::Key_F29,		'F', 'J' },
    { Qt::Key_F30,		'F', 'K' },
    { Qt::Key_F31,		'F', 'L' },
    { Qt::Key_F32,		'F', 'M' },
    { Qt::Key_F33,		'F', 'N' },
    { Qt::Key_F34,		'F', 'O' },
    { Qt::Key_F35,		'F', 'P' },
    { Qt::Key_Help,		'%', '1' },
//    { Qt::Key_Undo,		'&', '8' },
    { Qt::Key_BackSpace,	'k', 'b' },
    { Qt::Key_Insert,		'k', 'I' },
    { Qt::Key_Delete,		'k', 'D' },
    { Qt::Key_Home,		'k', 'h' },
    { Qt::Key_End,		'@', '7' },
    { Qt::Key_Prior,		'k', 'P' },
    { Qt::Key_Next,		'k', 'N' },
    { Qt::Key_Print,		'%', '9' },
    
    { Qt::Key_Plus,	'K', '6'},
    { Qt::Key_Minus,	'K', '7'},
    { Qt::Key_Slash,	'K', '8'},
    { Qt::Key_multiply,	'K', '9'},
    { Qt::Key_Enter,	'K', 'A'},
    { Qt::Key_Period,	'K', 'B'},

    { Qt::Key_0,	'K', 'C'},
    { Qt::Key_1,	'K', 'D'},
    { Qt::Key_2,	'K', 'E'},
    { Qt::Key_3,	'K', 'F'},
    { Qt::Key_4,	'K', 'G'},
    { Qt::Key_5,	'K', 'H'},
    { Qt::Key_6,	'K', 'I'},
    { Qt::Key_7,	'K', 'J'},
    { Qt::Key_8,	'K', 'K'},
    { Qt::Key_9,	'K', 'L'},


    /* End of list marker: */
    { 0, 0, 0 }
};
                                                                                                               
typedef int (*QX11EventFilter) (XEvent*);
extern QX11EventFilter qt_set_x11_event_filter (QX11EventFilter filter);
static QX11EventFilter oldFilter = 0;
static int kvim_x11_event_filter( XEvent* e);
//static int isActive=0;
/*
 * Return OK if the key with the termcap name "name" is supported.
 */
int
gui_mch_haskey(char_u * name)
{
    for (int i=0; special_keys[i].qtkey != 0; i++)
	    if (name[0] == special_keys[i].code0 && 
		name[1] == special_keys[i].code1)
		    return OK;
    return FAIL;
}

/*
 * custom Frame for drawing ...
 */
void VimFrame::paintEvent( QPaintEvent *e)
{
	QRect r = e->rect();
	gui_redraw(r.x(), r.y(), r.width(), r.height() );
}


void VimFrame::draw_string(int x, int y, QString s, int len, int flags)
{


	QFont f(*(gui.current_font));
#if QT_VERSION>=300
	f.setStyleStrategy(QFont::NoAntialias);
#endif
	f.setFixedPitch(true);
//	f.setRawName(gui.current_font);
	if (flags & DRAW_BOLD)
		f.setBold( true );

	if (flags & DRAW_UNDERL)
		f.setUnderline( true );

#if defined(DRAW_ITALIC) // should always be true within kvim
	if (flags & DRAW_ITALIC)
		f.setItalic( true );
#endif

	QPainter p(this);
	p.setPen( QPen (gui.w->fg_color, 1) );
	p.setFont( f );
	if ( ! (flags & DRAW_TRANSP)) {
		//dbf("not transparent");
		p.setBackgroundMode( Qt::OpaqueMode );
	} else {
		//dbf("transparent");
		p.setBackgroundMode( Qt::TransparentMode );
	}
	p.setBackgroundColor(gui.w->bg_color);
	p.drawText( x, y, s, len);
}


void VimFrame::mousePressEvent(QMouseEvent *event)
{
	ButtonState state = event->state();	
	// QT does not provide button() information in state() as said in the doc ! Qt Bug ?
	// so until 16032002 we never used right/middle button in kvim :) because this information was never sent to vim, that was quite restrictive ;)
	int button=0;
	int modifiers=0;
	
	//Look at button states
	if(event->button() & QMouseEvent::LeftButton) {
		button|=MOUSE_LEFT;
	}
	if(event->button() & QMouseEvent::RightButton) {
		button|=MOUSE_RIGHT;
	}
	if(event->button() & QMouseEvent::MidButton) {
		button|=MOUSE_MIDDLE;
	}
	//Look for keyboard modifiers
	if(state & QMouseEvent::ShiftButton) {
		modifiers|=MOUSE_SHIFT;
	}
	if(state & QMouseEvent::ControlButton){
		modifiers|=MOUSE_CTRL;
	}
	if(state & QMouseEvent::AltButton){
		modifiers|=MOUSE_ALT;
	}
	gui_send_mouse_event(button,event->x(),event->y(),FALSE,modifiers);	
}

void VimFrame::wheelEvent (QWheelEvent *event)
{
	ButtonState state = event->state();
	int button=0;
	int modifiers=0;

	if (event->delta()>0) 
		button|=MOUSE_4;
	else button|=MOUSE_5;

	if(state & ShiftButton)	
		modifiers|=MOUSE_SHIFT;
	if(state & ControlButton)
		modifiers|=MOUSE_CTRL;
	if(state & AltButton)
		modifiers|=MOUSE_ALT;
		
	gui_send_mouse_event(button,event->x(),event->y(),FALSE,modifiers);
}

void VimFrame::mouseDoubleClickEvent(QMouseEvent *event)
{
	ButtonState state = event->state();	
	int modifiers=0;
	int button=0;

	//Look at button states
	if(event->button() & LeftButton)
		button|=MOUSE_LEFT;
	if(event->button() & RightButton)
		button|=MOUSE_RIGHT;
	if(event->button() & MidButton)
		button|=MOUSE_MIDDLE;

	//Look for keyboard modifiers
	if(state & ShiftButton)	
		modifiers|=MOUSE_SHIFT;
	if(state & ControlButton)
		modifiers|=MOUSE_CTRL;
	if(state & AltButton)
		modifiers|=MOUSE_ALT;

	gui_send_mouse_event(button,event->x(),event->y(),TRUE,modifiers);	


}

void VimFrame::mouseMoveEvent(QMouseEvent *event){
	gui_mch_mousehide(FALSE);
	gui_send_mouse_event(MOUSE_DRAG,event->x(),event->y(),FALSE,0);	
};

void VimFrame::mouseReleaseEvent(QMouseEvent *event)
{
	ButtonState state = event->state();	
	int modifiers=0;

	//Look for keyboard modifiers
	if(state & ShiftButton)	
		modifiers|=MOUSE_SHIFT;
	if(state & ControlButton)
		modifiers|=MOUSE_CTRL;
	if(state & AltButton)
		modifiers|=MOUSE_ALT;

	gui_send_mouse_event(MOUSE_RELEASE,event->x(),event->y(),FALSE,modifiers);
}

/*
 *  The main widget (everything but toolbar/menubar)
 */
VimWidget::VimWidget( QWidget *parent=0, const char *name=0, WFlags f=0 )
	:QWidget(parent, name, f),
	DCOPObject("KVim"),
	drawing_area(this)
{
	setFocusPolicy( QWidget::StrongFocus );
	setAcceptDrops(TRUE); // DND
	blink_state = BLINK_NONE;
	blink_on_time = 700;
	blink_off_time = 400;
	blink_wait_time = 250;
	connect( &blink_timer, SIGNAL( timeout() ), SLOT( blink_cursor() ));
	connect( &wait_timer, SIGNAL( timeout() ), SLOT ( wait_timeout() ));
}

void VimWidget::exec(QString command)
{
	do_cmdline_cmd((char_u *)command.latin1());
}

void VimWidget::wait(long wtime)
{
	if ( wait_timer.isActive() ) wait_timer.stop();
	wait_done = false;
	wait_timer.start( wtime, true);
}

void VimWidget::wait_timeout() 
{
	wait_done = true;
}

void VimWidget::dragEnterEvent (QDragEnterEvent *e)
{
	e->accept(QUriDrag::canDecode(e));
}

void VimWidget::dropEvent (QDropEvent *e)
{
    QStrList  urls;

    char_u	**fnames;
    int		redo_dirs = FALSE;
    int		i;
    int		n;
    int		nfiles;
    int		url = FALSE;
    
    /* Count how many items there may be and normalize delimiters. */
    n = urls.count();
    fnames = (char_u **)malloc((n + 1) * sizeof(char_u *));
    nfiles = 0;
    
    if (QUriDrag::decode(e, urls)) {
#if QT_VERSION>=300
	QPtrListIterator<char> it(urls);
	for( ; it.current(); ++it ) {
		KURL u(*it);
#else
	for (i=0;i<urls.count();++i) {
		KURL u(urls.at(i));
#endif
		
		if ( !u.isLocalFile() )
		{
		    url = TRUE;
		}
		if (u.isLocalFile())
		{
			fnames[nfiles] = (char_u *)strdup((const char *)u.path());
			++nfiles;
		}
    	}
    /* Real files (i.e. not http and not ftp) */
    if (url == FALSE)
    {
	if (nfiles == 1)
	{
	    if (mch_isdir(fnames[0]))
	    {
		/* Handle dropping a directory on Vim. */
		if (mch_chdir((char *)fnames[0]) == 0)
		{
		    free(fnames[0]);
		    fnames[0] = NULL;
		    redo_dirs = TRUE;
		}
	    }
	}
	else
	{
	    /* Ignore any directories */
	    for (i = 0; i < nfiles; ++i)
	    {
		if (mch_isdir(fnames[i]))
		{
		    vim_free(fnames[i]);
		    fnames[i] = NULL;
		}
	    }
	}

	if (/*current_modifiers & GDK_SHIFT_MASK*/0) // mikmak: is this possible in KDE ? don't know how to get the key
	{
	    /* Shift held down, change to first file's directory */
	    if (fnames[0] != NULL && vim_chdirfile(fnames[0]) == OK)
		redo_dirs = TRUE;
	}
	else
	{
	    char_u	dirname[MAXPATHL];
	    char_u	*s;

	    /* Shorten dropped file names. */
	    if (mch_dirname(dirname, MAXPATHL) == OK)
		for (i = 0; i < nfiles; ++i)
		    if (fnames[i] != NULL)
		    {
			s = shorten_fname(fnames[i], dirname);
			if (s != NULL && (s = vim_strsave(s)) != NULL)
			{
			    vim_free(fnames[i]);
			    fnames[i] = s;
			}
		    }
	}
    }

    /* Handle the drop, :edit or :split to get to the file */
    handle_drop(nfiles, fnames, /*current_modifiers & GDK_CONTROL_MASK*/0);

    if (redo_dirs)
	shorten_fnames(TRUE);

    /* Update the screen display */
    update_screen(NOT_VALID);
#ifdef FEAT_MENU
    gui_update_menus(0);
#endif
    setcursor();
    out_flush();
    gui_update_cursor(FALSE, FALSE);
    gui_mch_flush();
    }
}

void VimWidget::keyPressEvent( QKeyEvent *e ) 
{
	int key = (int)e->key();
	int modifiers = 0,i;
	uchar string[256];
	uchar *s,*d;
	if (e->text().latin1()!=NULL) strcpy( (char *) string, (char *) e->text().latin1());
	string[e->text().length()] = 0;
	int len=strlen((char *) string);
	
	// ignore certain keys 
	if (key == Key_Shift || key == Key_Alt || key == Key_Control || key == Key_Meta 
		|| key == Key_CapsLock || key == Key_NumLock || key == Key_ScrollLock ) {
		e->ignore();
		return;
	}

	s = string;//(char_u *)event->string;
	d = string;
	for (i = 0; i < len; ++i)
	{
	    *d++ = s[i];
	    if (d[-1] == CSI && d + 2 < string + sizeof(string))
	    {
		/* Turn CSI into K_CSI. */
		*d++ = KS_EXTRA;
		*d++ = (int)KE_CSI;
	    }
	}
	len = d - string;
		

	// change shift-tab (backtab) into S_TAB
	if ( key == Qt::Key_BackTab && e->state() & Qt::ShiftButton) {
		key = Qt::Key_Tab;
	}

	// Change C-@ and C-2 in NUL ? Gtk does this
	if ( (key == Qt::Key_2 || key == Qt::Key_At) 
		&& e->state() & Qt::ControlButton ) {
		string[0] = NUL;
		len = 1;
	}
	else if (len == 0 && (key == Qt::Key_Space || key == Qt::Key_Tab))
    	{
		/* When there are modifiers, these keys get zero length; we need the
		 * original key here to be able to add a modifier below. */
		string[0] = (key & 0xff);
		len = 1;
    	}
    /* Check for Alt/Meta key (Mod1Mask), but not for a BS, DEL or character
     * that already has the 8th bit set.
     * Don't do this for <S-M-Tab>, that should become K_S_TAB with ALT. */
    if (len == 1
	    && (e->state() & Qt::AltButton)
	    && !(key == Qt::Key_BackSpace || key == Qt::Key_Delete)
	    && (string[0] & 0x80) == 0
	    && !(key == Qt::Key_Tab && (e->state() & ShiftButton)))
    {
	string[0] |= 0x80;
#ifdef FEAT_MBYTE
	if (enc_utf8) /* convert to utf-8 */
	{
	    string[1] = string[0] & 0xbf;
	    string[0] = ((unsigned)string[0] >> 6) + 0xc0;
	    if (string[1] == CSI)
	    {
		string[2] = KS_EXTRA;
		string[3] = (int)KE_CSI;
		len = 4;
	    }
	    else
		len = 2;
	}
#endif
    }
	
	/* Check for special keys, making sure BS and DEL are recognised. */
	if (len == 0 || key == Qt::Key_BackSpace || key == Qt::Key_Delete) 
	{
		for (i = 0; special_keys[i].qtkey != 0; i++)
		{
			if (special_keys[i].qtkey == key) 
			{
				string[0] = CSI;
				string[1] = special_keys[i].code0;
				string[2] = special_keys[i].code1;
				len = -3;

				break;
			}
		}
	}

	if (len == 0)   {
		dbf("Unrecognised Key : %X", key);
		e->ignore();
		return;
	}


	/* Special keys (and a few others) may have modifiers */
	if (len == -3 || key == Qt::Key_Space || key == Qt::Key_Tab ||
		key == Key_Return || key == Key_Enter ||
		key == Key_Escape) {

		modifiers = 0;
		if (e->state() & ShiftButton) modifiers |= MOD_MASK_SHIFT;
		if (e->state() & ControlButton) modifiers |= MOD_MASK_CTRL;
		if (e->state() & AltButton) modifiers |= MOD_MASK_ALT;

		/*
		* For some keys a shift modifier is translated into another key
		* code. Do we need to handle the case where len != 1 and
		* string[0] != CSI?
		*/
		if (len == -3)
			key = TO_SPECIAL(string[1], string[2]);
		else
			key = string[0];

		key = simplify_key(key, &modifiers);
		if (key == CSI) key=K_CSI;

		if (IS_SPECIAL(key)) {
			string[0] = CSI;
			string[1] = K_SECOND(key);
			string[2] = K_THIRD(key);
			len = 3;
		} else {
			string[0] = key;
			len = 1;
		}


		if (modifiers!=0) {
			uchar string2[10];
			string2[0] = CSI;
			string2[1] = KS_MODIFIER;
			string2[2] = modifiers;
			add_to_input_buf(string2, 3);
		}

	} /* special keys */

 	if (len == 1 && ((string[0] == Ctrl_C && ctrl_c_interrupts)
		   || (string[0] == intr_char && intr_char != Ctrl_C)))
	{	
		trash_input_buf();
		got_int = TRUE;
	}

	add_to_input_buf(string, len);
	if (p_mh) {
		gui_mch_mousehide(TRUE);
	}

	e->accept();
}

void VimWidget::resizeEvent ( QResizeEvent *e )
{
	// will call gui_mch_set_winsize() which will call itself 
	// vmw->resize() which will resize the widget

	//	gui_resize_shell( width(),((int)(height()/gui.char_height))*gui.char_height);
//	dbf("resizeEvent");
	gui_resize_shell( e->size().width(),((int)(e->size().height()/gui.char_height))*gui.char_height);
	// So this call is unneeded
//	QWidget::resizeEvent(e);
}

void VimWidget::focusInEvent( QFocusEvent * fe )
{
	gui_focus_change(true);

	if (blink_state == BLINK_NONE)
		gui_mch_start_blink();

}

void VimWidget::focusOutEvent( QFocusEvent * fe )
{
	gui_focus_change(false);

	if (blink_state != BLINK_NONE)
		gui_mch_stop_blink();

	// ???
#ifdef USE_XIM
	xim_set_focus(FALSE);
#endif
}

void VimWidget::set_blink_time( long wait, long on, long off)
{
	blink_wait_time = wait;
	blink_on_time = on;
	blink_off_time = off;
}

void VimWidget::start_cursor_blinking()
{
	if (blink_timer.isActive()) blink_timer.stop();

	/* Only switch blinking on if none of the times is zero */
	if (blink_wait_time && blink_on_time && blink_off_time && gui.in_focus) {
		blink_state = BLINK_ON;
		gui_update_cursor(TRUE, FALSE);
		// The first blink appears after wait_time
		blink_timer.start( blink_wait_time, true);
	}

}
void VimWidget::blink_cursor()
{
	if (blink_state == BLINK_ON) {
		// set cursor off
		gui_undraw_cursor();
		blink_state = BLINK_OFF;
		blink_timer.start( blink_off_time, true);
	} else {
		// set cursor on
		gui_update_cursor(TRUE, FALSE);
		blink_state = BLINK_ON;
		blink_timer.start( blink_on_time, true);
	}
}

void VimWidget::stop_cursor_blinking()
{
	if (blink_timer.isActive()) blink_timer.stop();

	if (blink_state == BLINK_OFF)
		gui_update_cursor(TRUE, FALSE);

	blink_state = BLINK_NONE;

}

void VimWidget::flash(){
	QPainter p(&(drawing_area));

	p.setRasterOp(Qt::XorROP);
	p.fillRect(drawing_area.geometry(),QColor(0xFF,0xFF,0xFF));
	p.flush();
	//FIXME: Make this a little smarter. Maybe add a timer or something
	usleep(19000);
	p.fillRect(drawing_area.geometry(),QColor(0xFF,0xFF,0xFF));
	p.flush();
	p.end();
}


/*
 *  The main Window
 */

VimMainWindow::VimMainWindow ( const char *name , WFlags f)
	:KMainWindow(0L, name,f)
{
	oldFilter = qt_set_x11_event_filter( kvim_x11_event_filter );
	if (echo_wid_arg== 1) {
		fprintf(stderr, "WID: %d\n", winId());
		fflush(stderr);
	}


	w = new VimWidget(this, "main vim widget");
	gui.w = w;
	setCentralWidget(w);
	w->setFocus();
	have_tearoff=0;

    	finddlg=new KEdFind (this,0,false);
	repldlg=new KEdReplace (this,0,false);
	QObject::connect( finddlg, SIGNAL(search()), this, SLOT(slotSearch()) );
	QObject::connect( repldlg, SIGNAL(find()), this, SLOT(slotFind()) );
	QObject::connect( repldlg, SIGNAL(replace()), this, SLOT(slotReplace()) );
	QObject::connect( repldlg, SIGNAL(replaceAll()), this, SLOT(slotReplaceAll()) );

	/* we use a hack based on this assertion, so check it.. */
	assert(sizeof(void*)==sizeof(int));

	connect(toolBar(), SIGNAL(clicked(int)), this, SLOT(menu_activated(int)));

}

void VimWidget::serverActivate() 
{
	// seems it must be done _after_ the mainwindow is created, not _while_ it is created
	// not sure but that works better :=), mikmak
	if (serverName == NULL && serverDelayedStartName != NULL) {
		commWindow = winId();
		(void)serverRegisterName(qt_xdisplay(), serverDelayedStartName);
	} else {
		serverChangeRegisteredWindow( qt_xdisplay(), winId() );
	}
}


bool VimMainWindow::close(bool alsoDelete)
{

	gui_shell_closed();

	return true;
}

void VimMainWindow::menu_activated(int dx)
{
	if (!dx) { 	// tearoff
		// XXX transfer focus to main window
		return; 
	}

	gui_menu_cb((VimMenu *) dx);

}


void VimMainWindow::clipboard_update(){
	if(!kapp->clipboard()->ownsSelection()){
		clip_lose_selection(&clip_plus);
	} else
		clip_own_selection(&clip_star);
}

void VimMainWindow::slotSearch()
{
    QString 	find_text;
    bool	direction_down = TRUE;
    bool	casesensitive = TRUE;

    find_text = finddlg->getText().latin1();
    direction_down = !(finddlg->get_direction());
    casesensitive = finddlg->case_sensitive();
    if (casesensitive) find_text = "\\C" + find_text;
    else find_text = "\\c" + find_text;
    gui_do_findrepl(FR_FINDNEXT, (char_u *)(const char *)find_text, NULL,(int)direction_down, 0);
}

void VimMainWindow::slotFind()
{
    QString	find_text;
    bool 	direction_down=TRUE;
    bool	casesensitive = TRUE;

    find_text=repldlg->getText().latin1();
    direction_down = !(repldlg->get_direction());
    casesensitive = repldlg->case_sensitive();
    if (casesensitive) find_text = "\\C" + find_text;
    else find_text = "\\c" + find_text;
	
    gui_do_findrepl(FR_R_FINDNEXT, (char_u *)(const char *)find_text, NULL,(int)direction_down, 0);

}

void VimMainWindow::slotReplace()
{
    QString	find_text;
    char	*repl_text;
    bool 	direction_down=TRUE;
    bool	casesensitive = TRUE;

    find_text=repldlg->getText().latin1();
    repl_text=(char *)repldlg->getReplaceText().latin1();
    direction_down = !(repldlg->get_direction());
    if (casesensitive) find_text = "\\C" + find_text;
    else find_text = "\\c" + find_text;
    
    gui_do_findrepl(FR_REPLACE, (char_u *)(const char *)find_text,(char_u *)repl_text,(int)direction_down, 0);
}

void VimMainWindow::slotReplaceAll()
{
    QString	find_text;
    char	*repl_text;
    bool 	direction_down=TRUE;
    bool	casesensitive = TRUE;

    find_text=repldlg->getText().latin1();
    repl_text=(char *)repldlg->getReplaceText().latin1();
    direction_down = !(repldlg->get_direction());
    casesensitive = repldlg->case_sensitive();
    if (casesensitive) find_text = "\\C" + find_text;
    else find_text = "\\c" + find_text;
    
    gui_do_findrepl(FR_REPLACEALL, (char_u *)(const char *)find_text,(char_u *)repl_text,(int)direction_down, 0);
	
}
/*
 *   Vim Dialog
 *
 * Returns:
 *  0: Cancel
 *  1- : nb of the pressed button
 */

VimDialog::VimDialog (int type,		/* type of dialog */
	       char_u * title,		/* title of dialog */
	       char_u * message,	/* message text */
	       char_u * buttons,	/* names of buttons */
	       int def_but,		/* default button */
	       char_u *textfield )	/* input field */
	:QDialog(vmw, "vim generic dialog", true), // true is for "modal"
	mapper(this, "dialog signal mapper")
{
	// if mouse pointer is hidden, show it	
	gui_mch_mousehide( FALSE );

	/*
	 * Create Icon
	 */
	char ** icon_data;
	switch (type) {
	case VIM_GENERIC:
		icon_data = generic_xpm;
	break;
	case VIM_ERROR:
		icon_data = error_xpm;
	break;
	case VIM_WARNING:
		icon_data = alert_xpm;
	break;
	case VIM_INFO:
		icon_data = info_xpm;
	break;
	case VIM_QUESTION:
		icon_data = quest_xpm;
	break;
	default:
		icon_data = generic_xpm;
	};                                                                                                          
	QLabel * icon = new QLabel( this );
	icon->setPixmap( QPixmap( (const char **) icon_data ) );
	icon->setFixedSize( icon->sizeHint() );

	QLabel * text = new QLabel( (char *) message, this );
	text->setAlignment( AlignHCenter | AlignVCenter | ExpandTabs );

		
	
	QStringList buttonText = QStringList::split( DLG_BUTTON_SEP, (char *) buttons);
	int butNb = buttonText.count();

	/*
	 *  Layout
	 */

	QVBoxLayout * vly = new QVBoxLayout( this, 5, 5 );
	QHBoxLayout * hly1 = new QHBoxLayout( vly, 5);
	hly1->addWidget( icon );
	hly1->addWidget( text );
	QHBoxLayout * hly3 = new QHBoxLayout ( vly , 5);
	if (textfield!=NULL) {
		entry = new QLineEdit((const char *)textfield,this);
		entry->setText((const char *)textfield);
		hly3->addWidget( entry );
		ret=textfield;
	}

	QHBoxLayout * hly2 = new QHBoxLayout( vly, 15);
	QString s;
	QPushButton * pushButton = 0L;
	for( int i=0; i<butNb; i++) {
		s = buttonText[i];
		pushButton = new QPushButton(s, this );
		if (s.find('&') != -1) {
			pushButton->setAccel( s.at(s.find('&')+1).latin1() );
		}

		hly2->addWidget( pushButton );
		if (i == def_but-1) {
			pushButton->setDefault( true );
			pushButton->setAutoDefault( true );
			setResult( i+1 );
		}
		connect(pushButton, SIGNAL(clicked()), &mapper, SLOT(map()));
		mapper.setMapping(pushButton, i+1);
	}
	connect( &mapper, SIGNAL(mapped(int)), this, SLOT(done(int)));

	setCaption((const char *) title);

	vly->activate();
}

/*
 * ScrollBar pool handling
 */
SBPool::SBPool(void)
:mapper(this, "SBPool signal mapper")
{
	connect(&mapper, SIGNAL(mapped(int)), this, SLOT(sbUsed(int)));
}


void SBPool::create(GuiScrollbar * sb, int orient)
{
	switch(orient) {
		case SBAR_HORIZ:
			sb->w = new QScrollBar(QScrollBar::Horizontal, gui.w);
			break;
		case SBAR_VERT:
			sb->w = new QScrollBar(QScrollBar::Vertical, gui.w);
			break;
		default:
			sb->w = 0;
			return;
	}
 
	connect(sb->w, SIGNAL(valueChanged(int)), &mapper, SLOT(map()));    
	mapper.setMapping(sb->w, (int)sb);

}


void SBPool::sbUsed(int who)
{
	GuiScrollbar *sb = (GuiScrollbar*)who;
	gui_drag_scrollbar( sb, sb->w->value(), FALSE);
}


void SBPool::destroy(GuiScrollbar * sb)
{
	if (!sb->w) return;

	delete sb->w;
	sb->w = 0;      
}

static int kvim_x11_event_filter( XEvent* e)
{
	if (e->xproperty.type == PropertyNotify
		&& e->xproperty.atom == commProperty
		&& e->xproperty.window == commWindow 
		&& e->xproperty.state == PropertyNewValue ) {
		serverEventProc(qt_xdisplay(), e);
	}


	if (oldFilter) return oldFilter( e );
	return FALSE;
}
