// This module implements the specialisation of TQListBox that handles the
// Scintilla double-click callback.
//
// Copyright (c) 2006
// 	Riverbank Computing Limited <info@riverbankcomputing.co.uk>
// 
// This file is part of TQScintilla.
// 
// This copy of TQScintilla 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, or (at your option) any
// later version.
// 
// TQScintilla is supplied 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
// TQScintilla; see the file LICENSE.  If not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


#include <stdlib.h>
#include <string.h>

#include <tqapplication.h>
#include <tqmap.h>
#include <tqpixmap.h>

#include "SciListBox.h"


// The platform specific specialisation of the ListBox abstract class.

class ListBoxX : public ListBox
{
public:
	ListBoxX();
	virtual ~ListBoxX();

	CallBackAction cb_action;
	void *cb_data;

	virtual void SetFont(Font &font);
	virtual void Create(Window &parent,int,Point,int,bool);
	virtual void SetAverageCharWidth(int);
	virtual void SetVisibleRows(int);
	virtual int GetVisibleRows() const;
	virtual PRectangle GetDesiredRect();
	virtual int CaretFromEdge();
	virtual void Clear();
	virtual void Append(char *s,int type = -1);
	virtual int Length();
	virtual void Select(int n);
	virtual int GetSelection();
	virtual int Find(const char *prefix);
	virtual void GetValue(int n,char *value,int len);
	virtual void Sort();
	virtual void RegisterImage(int type,const char *xpm_data);
	virtual void ClearRegisteredImages();
	virtual void SetDoubleClickAction(CallBackAction action,void *data);
	virtual void SetList(const char *list,char separator,char typesep);

private:
	SciListBox *slb;

	typedef TQMap<int,TQPixmap> xpmMap;
	xpmMap xset;
};


ListBoxX::ListBoxX() : cb_action(0), cb_data(0), slb(0)
{
}


ListBoxX::~ListBoxX()
{
}


void ListBoxX::SetFont(Font &font)
{
	TQFont *f = reinterpret_cast<TQFont *>(font.GetID());

	if (f)
		slb -> setFont(*f);
}


void ListBoxX::Create(Window &parent,int,Point,int,bool)
{
	// The parent we want is the QextScintillaBase, not the text area.
	id = slb = new SciListBox(reinterpret_cast<TQWidget *>(parent.GetID()) -> parentWidget(),this);
}


void ListBoxX::SetAverageCharWidth(int)
{
	// We rely on TQListBox::sizeHint() for the size of the list box rather
	// than make calculations based on the average character width and the
	// number of visible rows.
}


void ListBoxX::SetVisibleRows(int)
{
}


int ListBoxX::GetVisibleRows() const
{
	return slb -> numItemsVisible();
}


PRectangle ListBoxX::GetDesiredRect()
{
	PRectangle rc(0,0,100,100);

	if (slb)
	{
		TQSize sh = slb -> sizeHint();

		rc.right = sh.width();
		rc.bottom = sh.height();
	}

	return rc;
}


int ListBoxX::CaretFromEdge()
{
	int dist = 0;

	// Find the width of the biggest image.
	for (xpmMap::Iterator it = xset.begin(); it != xset.end(); ++it)
	{
		int w = it.data().width();

		if (dist < w)
			dist = w;
	}

	if (slb)
		dist += slb -> frameWidth();

	// Fudge factor - adjust if required.
	dist += 3;

	return dist;
}


void ListBoxX::Clear()
{
	slb -> clear();
}


void ListBoxX::Append(char *s,int type)
{
	xpmMap::ConstIterator it;

	if (type < 0 || (it = xset.find(type)) == xset.end())
		slb -> insertItem(s);
	else
		slb -> insertItem(it.data(),s);
}


int ListBoxX::Length()
{
	return (slb ? slb -> numRows() : 0);
}


void ListBoxX::Select(int n)
{
	slb -> setSelected(n,TRUE);
}


int ListBoxX::GetSelection()
{
	return slb -> currentItem();
}


int ListBoxX::Find(const char *prefix)
{
	return slb -> index(slb -> findItem(prefix,TQt::CaseSensitive|TQt::BeginsWith));
}


void ListBoxX::GetValue(int n,char *value,int len)
{
	TQString s = slb -> text(n);

	if (s.isNull() || len <= 0)
		value[0] = '\0';
	else
	{
		strncpy(value,s.latin1(),len - 1);
		value[len - 1] = '\0';
	}
}


void ListBoxX::Sort()
{
	slb -> sort();
}


void ListBoxX::RegisterImage(int type,const char *xpm_data)
{
	xset.insert(type,*reinterpret_cast<const TQPixmap *>(xpm_data));
}


void ListBoxX::ClearRegisteredImages()
{
	xset.clear();
}


void ListBoxX::SetDoubleClickAction(CallBackAction action,void *data)
{
	cb_action = action;
	cb_data = data;
}


void ListBoxX::SetList(const char *list,char separator,char typesep)
{
	char *words;

	Clear();

	if ((words = strdup(list)) != NULL)
	{
		char *startword = words;
		char *numword = NULL;

		for (int i = 0; words[i] != '\0'; i++)
		{
			if (words[i] == separator)
			{
				words[i] = '\0';

				if (numword)
					*numword = '\0';

				Append(startword,numword ? atoi(numword + 1) : -1);

				startword = words + i + 1;
				numword = NULL;
			}
			else if (words[i] == typesep)
			{
				numword = words + i;
			}
		}

		if (startword)
		{
			if (numword)
				*numword = '\0';

			Append(startword,numword ? atoi(numword + 1) : -1);
		}

		free(words);
	}
}


// The ListBox methods that need to be implemented explicitly.

ListBox::ListBox()
{
}


ListBox::~ListBox()
{
}


ListBox *ListBox::Allocate()
{
	return new ListBoxX();
}


SciListBox::SciListBox(TQWidget *parent,ListBoxX *lbx_)
	: TQListBox(parent,0,WType_Popup|WStyle_Customize|WStyle_NoBorder|WStaticContents), lbx(lbx_)
{
	setFocusProxy(parent);

	setFrameShape(StyledPanel);
	setFrameShadow(Plain);
	setHScrollBarMode(AlwaysOff);

	connect(this,TQT_SIGNAL(doubleClicked(TQListBoxItem *)),
		TQT_SLOT(handleDoubleClick(TQListBoxItem *)));

	connect(this,TQT_SIGNAL(highlighted(TQListBoxItem *)),
		TQT_SLOT(ensureCurrentVisible()));
}


SciListBox::~SciListBox()
{
	// Ensure that the main widget doesn't get a focus out event when this
	// is destroyed.
	setFocusProxy(0);
}


void SciListBox::handleDoubleClick(TQListBoxItem *)
{
	if (lbx && lbx -> cb_action)
		lbx -> cb_action(lbx -> cb_data);
}
