/* vi:set ts=8 sts=4 sw=4:
 *
 * 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@freehackers.org>
 *
 *  Please visit http://freehackers.org/kvim for other vim- or
 *  kde-related coding. (URL currently doesn't work...)
 *
 *  $Id: gui_kde.cc,v 1.9 2005/07/08 22:17:19 vimboss Exp $
 *
 */
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <kmenubar.h>
#include <kfiledialog.h>
#include <kiconloader.h>

#include <qscrollbar.h>
#include <qcursor.h>
#include <qmessagebox.h>
#include <qiconset.h>
#include <qtextcodec.h>
#include "gui_kde_wid.h"

extern "C" {
#include "vim.h"
}

#undef dbf
#undef db
#undef mputs

#if 1
#define dbf(format, args...) { printf("%s" " : " format "\n" , __FUNCTION__ , ## args ); fflush(stdout); }
#define db()       { printf("%s\n", __FUNCTION__ );fflush(stdout); }
#else
#define dbf(format, args... )
#define db()
#endif


#ifdef FEAT_TOOLBAR
#ifndef FEAT_KDETOOLBAR
/*
 * Icons used by the toolbar code.
 *///{{{
#include "../pixmaps/tb_new.xpm"
#include "../pixmaps/tb_open.xpm"
#include "../pixmaps/tb_close.xpm"
#include "../pixmaps/tb_save.xpm"
#include "../pixmaps/tb_print.xpm"
#include "../pixmaps/tb_cut.xpm"
#include "../pixmaps/tb_copy.xpm"
#include "../pixmaps/tb_paste.xpm"
#include "../pixmaps/tb_find.xpm"
#include "../pixmaps/tb_find_next.xpm"
#include "../pixmaps/tb_find_prev.xpm"
#include "../pixmaps/tb_find_help.xpm"
#include "../pixmaps/tb_exit.xpm"
#include "../pixmaps/tb_undo.xpm"
#include "../pixmaps/tb_redo.xpm"
#include "../pixmaps/tb_help.xpm"
#include "../pixmaps/tb_macro.xpm"
#include "../pixmaps/tb_make.xpm"
#include "../pixmaps/tb_save_all.xpm"
#include "../pixmaps/tb_jump.xpm"
#include "../pixmaps/tb_ctags.xpm"
#include "../pixmaps/tb_load_session.xpm"
#include "../pixmaps/tb_save_session.xpm"
#include "../pixmaps/tb_new_session.xpm"
#include "../pixmaps/tb_blank.xpm"
#include "../pixmaps/tb_maximize.xpm"
#include "../pixmaps/tb_split.xpm"
#include "../pixmaps/tb_minimize.xpm"
#include "../pixmaps/tb_shell.xpm"
#include "../pixmaps/tb_replace.xpm"
#include "../pixmaps/tb_vsplit.xpm"
#include "../pixmaps/tb_maxwidth.xpm"
#include "../pixmaps/tb_minwidth.xpm"
//}}}
/*
 * These are the pixmaps used for the default buttons.
 * Order must exactly match toolbar_names[] in menu.c!
 *///{{{
static char **(built_in_pixmaps[]) =
{
	tb_new_xpm,
	tb_open_xpm,
	tb_save_xpm,
	tb_undo_xpm,
	tb_redo_xpm,
	tb_cut_xpm,
	tb_copy_xpm,
	tb_paste_xpm,
	tb_print_xpm,
	tb_help_xpm,
	tb_find_xpm,
	tb_save_all_xpm,
	tb_save_session_xpm,
	tb_new_session_xpm,
	tb_load_session_xpm,
	tb_macro_xpm,
	tb_replace_xpm,
	tb_close_xpm,
	tb_maximize_xpm,
	tb_minimize_xpm,
	tb_split_xpm,
	tb_shell_xpm,
	tb_find_prev_xpm,
	tb_find_next_xpm,
	tb_find_help_xpm,
	tb_make_xpm,
	tb_jump_xpm,
	tb_ctags_xpm,
	tb_vsplit_xpm,
	tb_maxwidth_xpm,
	tb_minwidth_xpm,
	tb_exit_xpm
};//}}}
#else
const char *kdeicons[] = {
	"filenew",
	"fileopen",
	"filesave",
	"undo",
	"redo",
	"editcut",
	"editcopy",
	"editpaste",
	"fileprint",
	"contents2",
	"filefind",
	"save_all",
	"fileexport",
	"filenew",
	"fileimport",
	"run",
	"edit",
	"fileclose",
	"",
	"",
	"split",
	"openterm",
	"previous",
	"next",
	"help",
	"make",
	"goto",
	"run",
	"vsplit",
	"maxwidth",
	"minwidth",
	"quit"
};
#endif
/*
 * creates a blank pixmap using tb_blank
 */
    QPixmap
pixmap_create_from_xpm(char **xpm)//{{{
{
    return (QPixmap((const char **)xpm));
}//}}}

/*
 * creates a pixmap by using a built-in number
 */
    QPixmap
pixmap_create_by_num(int pixmap_num)//{{{
{
#ifdef FEAT_KDETOOLBAR
    if (pixmap_num >= 0 && (unsigned)pixmap_num < (sizeof(kdeicons)
						   / sizeof(kdeicons[0])) - 1)
    {

	KIconLoader *il = kapp->iconLoader(); //new KIconLoader();
	QString icon;
	icon = QString(kdeicons[pixmap_num]);
	return il->loadIcon(icon, KIcon::MainToolbar);
    }
    return QPixmap();
#else
    if (pixmap_num >= 0 && (unsigned)pixmap_num < (sizeof(built_in_pixmaps)
					   / sizeof(built_in_pixmaps[0])) - 1)
	return pixmap_create_from_xpm(built_in_pixmaps[pixmap_num]);
    else
	return QPixmap();
#endif
}//}}}

/*
 * Creates a pixmap by using the pixmap "name" found in 'runtimepath'/bitmaps/
 */
    QPixmap
pixmap_create_by_dir(char_u *name)//{{{
{
    char_u full_pathname[MAXPATHL + 1];

    if (gui_find_bitmap(name, full_pathname, "xpm") == OK)
	return QPixmap((const char *)full_pathname);
    else
	return QPixmap();
}//}}}


    QPixmap
pixmap_create_from_file(char_u *file)
{
    return QPixmap((const char *)file);
}
#endif

    void
gui_mch_add_menu(vimmenu_T *menu, int idx)//{{{
{
#ifdef FEAT_MENU
    QPopupMenu *me;
    vimmenu_T *parent = menu->parent;

    if (menu_is_popup(menu->name))
    {
	menu->widget = new QPopupMenu(vmw , QSTR(menu->name));
	QObject::connect(menu->widget, SIGNAL(activated(int)), vmw,
						   SLOT(menu_activated(int)));
	return;
    }

    if (!menu_is_menubar(menu->name))
	return;

    if (parent)
    {
	idx++; // for tearoffs to be first in menus
	me = new QPopupMenu(parent->widget, QSTR(menu->name));
	parent->widget->insertItem(QSTR(menu->name), me, (long)me, idx);
    }
    else
    {
	me = new QPopupMenu(vmw->menuBar(), QSTR(menu->name));
	vmw->menuBar()->insertItem(QSTR(menu->name), me, (long)me, idx);
    }

    me->setCaption((const char *)(menu->dname));
    if (vmw->have_tearoff)
	me->insertTearOffHandle(0, 0);
    QObject::connect(me, SIGNAL(activated(int)), vmw,
						   SLOT(menu_activated(int)));
    menu->widget = me;
#endif
}//}}}


    void
gui_mch_add_menu_item(vimmenu_T *menu, int idx)//{{{
{
#ifdef FEAT_MENU
    vimmenu_T *parent = menu->parent;
#ifdef FEAT_TOOLBAR
    if (menu_is_toolbar(parent->name))
    {
	QPixmap pix;

	if (menu_is_separator(menu->name))
	{
	    vmw->toolBar()->insertSeparator();
	    return;
	}
	if (menu->iconfile != NULL)
	{
	    pix = pixmap_create_from_file(menu->iconfile);
	}
	if (!menu->icon_builtin)
	{
	    pix = pixmap_create_by_dir(menu->name);
	}
	if (pix.isNull() && menu->iconidx >= 0)
	{
	    pix = pixmap_create_by_num(menu->iconidx);
	}
#ifndef FEAT_KDETOOLBAR
	if (pix.isNull())
	{
	    pix = pixmap_create_from_xpm(tb_blank_xpm);
	}
#endif
	if (pix.isNull())
	    return; // failed
	vmw->toolBar()->insertButton(
		pix,
		(long)menu, // id
		true,
		QSTR(menu->strings[MENU_INDEX_TIP]), // tooltip or text
		idx);
	menu->parent=parent;
	return;
    }
#endif // FEAT_TOOLBAR

    idx++;
    if (menu_is_separator(menu->name))
    {
	parent->widget->insertSeparator();
	return;
    }
    parent->widget->insertItem(QSTR(menu->name), (long)menu, idx);
#endif
}//}}}


    void
gui_mch_set_text_area_pos(int x, int y, int w, int h)//{{{
{
    int X = 0;
    int Y = 0;

    if (vmw->menuBar()->isVisible() && vmw->menuBar()->isEnabled()
#if QT_VERSION>=300
	    && !vmw->menuBar()->isTopLevelMenu()
#endif
       )
	Y += vmw->menuBar()->height();
#ifdef FEAT_TOOLBAR
    if (vmw->toolBar()->isVisible() && vmw->toolBar()->isEnabled()
				   && vmw->toolBar()->barPos()==KToolBar::Top)
	Y += vmw->toolBar()->height();

    if (vmw->toolBar()->isVisible() && vmw->toolBar()->isEnabled()
				  && vmw->toolBar()->barPos()==KToolBar::Left)
	X += vmw->toolBar()->width();
#endif // FEAT_TOOLBAR

    gui.w->setGeometry(x + X, y + Y, w, h);
}//}}}


#if defined(FEAT_MENU) || defined(PROTO)
/*
 * Enable or disable mnemonics for the toplevel menus.
 */
    void
gui_gtk_set_mnemonics(int enable)//{{{ // TO BE REMOVED
{
}//}}}

    void
toggle_tearoffs(vimmenu_T *menu, int enable)//{{{
{
    while (menu != NULL)
    {
	if (!menu_is_popup(menu->name))
	{
	    if (menu->widget != 0)
	    {
		if (enable)
		    menu->widget->insertTearOffHandle(0,0);
		else
		    menu->widget->removeItem(0);
	    }
	    toggle_tearoffs(menu->children, enable);
	}
	menu = menu->next;
    }
}//}}}

	void
gui_mch_toggle_tearoffs(int enable)//{{{
{
    vmw->have_tearoff=enable;
    toggle_tearoffs(root_menu, enable);
}//}}}
#endif


#if defined(FEAT_MENU) || defined(PROTO)
/*
 * Destroy the machine specific menu widget.
 */
    void
gui_mch_destroy_menu(vimmenu_T *menu)//{{{
{
#ifdef FEAT_TOOLBAR
    if (menu->parent && menu_is_toolbar(menu->parent->name))
    {
	vmw->toolBar()->removeItem((long)menu);
	return;
    }
#endif
    if (menu->parent)
	menu->parent->widget->removeItem((long)menu);
    if (menu->widget)
	delete menu->widget;
    menu->widget = 0;
}//}}}
#endif /* FEAT_MENU */


/*
 * Scrollbar stuff.
 */

    void
gui_mch_set_scrollbar_thumb(scrollbar_T *sb, long val, long size, long max)//{{{
{
    if (!sb->w)
	return;

    sb->w->setRange(0, max + 1 - size);
    sb->w->setValue(val);

    sb->w->setLineStep(1);
    sb->w->setPageStep(size);
}//}}}

    void
gui_mch_set_scrollbar_pos(scrollbar_T *sb, int x, int y, int w, int h)//{{{
{
    if (!sb->w)
	return;

    //we add the menubar and toolbar height/width
    int X = 0;
    int Y = 0;

    if (vmw->menuBar()->isVisible() && vmw->menuBar()->isEnabled()
#if QT_VERSION>=300
					  && !vmw->menuBar()->isTopLevelMenu()
#endif
       )
	Y += vmw->menuBar()->height();
#ifdef FEAT_TOOLBAR
    if (vmw->toolBar()->isVisible() && vmw->toolBar()->isEnabled()
				   && vmw->toolBar()->barPos()==KToolBar::Top)
	Y += vmw->toolBar()->height();

    if (vmw->toolBar()->isVisible() && vmw->toolBar()->isEnabled()
				  && vmw->toolBar()->barPos()==KToolBar::Left)
	X += vmw->toolBar()->width();
#endif //FEAT_TOOLBAR
    if (sb->w->orientation() == Qt::Vertical)
    {
	bool leftscroll=gui.which_scrollbars[SBAR_LEFT];
	bool rightscroll=gui.which_scrollbars[SBAR_RIGHT];

	if (x < 20)
	    leftscroll = true;
	else
	    rightscroll = true;
	if (x < 20)
	    sb->w->setGeometry(X, y+Y, w, h);
	else
	    sb->w->setGeometry(vmw->width() - w - 1 + X, y + Y, w, h);
    }
    else
    {
	sb->w->setGeometry(x + X, y + Y, w, h);
    }
}//}}}

/* SBAR_VERT or SBAR_HORIZ */
    void
gui_mch_create_scrollbar(scrollbar_T *sb, int orient)//{{{
{
    sbpool->create(sb,orient);
    if (orient == SBAR_VERT)
	gui.scrollbar_width = sb->w->sizeHint().width();
    else
	gui.scrollbar_height = sb->w->sizeHint().height();
}//}}}

    void
gui_mch_destroy_scrollbar(scrollbar_T *sb)//{{{
{
    sbpool->destroy(sb);
}//}}}

#if defined(FEAT_BROWSE) || defined(PROTO)
/*
 * Implementation of the file selector related stuff
 */

/*
 * Convert the Vim-style filter specification 's' to the KDE-style
 * filter specification.
 *      Vim-style:      {label}\t{pattern1};{pattern2}\n
 *      KDE-style:      {pattern1} {pattern2}|{label}\n
 *
 * The newly constructed filter is returned in allocated memory and
 * must be freed by the calling program.
 */
    static char *
convert_filter(char_u *s)
{
    char	*res;
    unsigned	i;
    unsigned	pattern_len;
    char	*filter_label;
    char	*filter_pattern;

    // The conversion generates a string of equal length to the original
    // pattern, so allocate enough memory to hold the original string.
    res = new char[STRLEN(s) + 1];
    s = vim_strsave(s);
    if (res != NULL && s != NULL)
    {
	// Make sure the first byte is a NUL so that strcat()
	// will append at the beginning of the string.
	res[0] = '\0';
	filter_label = strtok((char *) s, "\t");
	while (filter_label != NULL)
	{
	    filter_pattern = strtok( 0L, "\n");
	    if (filter_pattern != NULL)
	    {
		pattern_len = (unsigned) STRLEN(filter_pattern);
		for (i = 0; i < pattern_len; ++i)
		    if (filter_pattern[i] == ';')
			filter_pattern[i] = ' ';

		strcat(res, filter_pattern);
		strcat(res, "|");
		strcat(res, filter_label);
		strcat(res, "\n");
	    }
	    filter_label = strtok(0L, "\t");
	}
    }
    if (s)
	vim_free(s);
    return res;
}

/*
 * Put up a file requester.
 * Returns the selected name in allocated memory, or NULL for Cancel.
 * saving,			select file to write
 * title			title for the window
 * dflt				default name
 * ext				not used (extension added)
 * initdir			initial directory, NULL for current dir
 * filter			not used (file name filter)
 */
/*ARGSUSED*/
    char_u *
gui_mch_browse(int saving,//{{{
		char_u *title,
		char_u *dflt,
		char_u *ext,
		char_u *initdir,
		char_u *filter)
{
    char *filt_glob;

    filt_glob = convert_filter(filter);

    gui_mch_mousehide(FALSE);

    QString s;
    if (!saving)
	s = KFileDialog::getOpenFileName(QSTR(initdir), QSTR(filt_glob),
							  vmw, QSTR(title));
    else
	s = KFileDialog::getSaveFileName();

    if (filt_glob)
	delete filt_glob;

    if (s.isNull())
	return NULL;
    QCString unistring = vmw->codec->fromUnicode(s);
    char_u *s2 = (char_u *)(const char *)unistring;
    if (s2)
	s2 = vim_strsave(s2);

    return s2;
}//}}}

#endif	/* FEAT_BROWSE */

#ifdef FEAT_GUI_DIALOG

/* ARGSUSED */
    int
gui_mch_dialog(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)
{
    gui_mch_mousehide(FALSE);
    VimDialog vd(type, title, message, buttons, def_but,textfield);
    int ret = vd.exec();
    return ret;
}//}}}


#endif	/* FEAT_GUI_DIALOG */

#if defined(FEAT_MENU) || defined(PROTO)
    void
gui_mch_show_popupmenu(vimmenu_T *menu)//{{{
{
    menu->widget->popup(QCursor::pos());
}//}}}

/* TODO: use mouse_pos */
void
gui_make_popup (char_u *pathname, int mouse_pos)//{{{
{
    vimmenu_T *menu = gui_find_menu(pathname);

    if (menu != NULL)
	menu->widget->popup(QCursor::pos());
}//}}}
#endif



/* Find and Replace implementations */
    void
gui_mch_find_dialog(exarg_T *eap)//{{{
{
    // char_u* entry_text;
    //int exact_word=FALSE;
    //    entry_text = get_find_dialog_text(eap->arg,&exact_word);

    vmw->finddlg->setCaseSensitive(true);

    /*    if (entry_text!=NULL)
     *    {
	  vmw->finddlg->setText(QString((char *)entry_text));
    // exact match should go there, hopefully KDE old KEdFind/KEdReplace will be replaced in KDE 4 as pple wanted KDE 3's Find/Replace to be kept
    }*/ // Don't use it, KDE keeps old search in memory and vim give \\Csearch, which is difficult to handle
    //   vim_free(entry_text);

    vmw->finddlg->show();
}//}}}

    void
gui_mch_replace_dialog(exarg_T *eap)//{{{
{
    //  char_u* entry_text;
    //int exact_word=FALSE;

    //    entry_text = get_find_dialog_text(eap->arg,&exact_word);

    /*    if (entry_text!=NULL)
     *    {
     vmw->repldlg->setText(QString((char *)entry_text));
    // exact match should go there, hopefully KDE old KEdFind/KEdReplace will be replaced in KDE 4 as pple wanted KDE 3's Find/Replace to be kept
    }*/
    //vim_free(entry_text);

    vmw->repldlg->show();
}//}}}

    void
ex_helpfind(exarg_T *eap)//{{{
{
    do_cmdline_cmd((char_u *)"emenu ToolBar.FindHelp");
}//}}}
