/*-*-c++-*-
 * $Id: csearchlistdialog.cpp,v 1.1 2002/01/28 15:38:32 holzheu Exp $
 *
 * This file is part of qlcrash, a GUI for the dump-analysis tool lcrash.
 *
 * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
 *
 * Authors:
 * Michael Geselbracht (let@users.sourceforge.net)
 * Fritz Elfert (elfert@de.ibm.com)
 * Michael Holzheu (holzheu@de.ibm.com)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version. See the file COPYING for more
 * information.
 */
#include "osdep.h"
#include "csearchlistdialog.h"
#include "crashtypes.h"

#include <qlabel.h>
#include <qcombobox.h>
#include <qlistbox.h>
#include <qlineedit.h>
#include <qregexp.h>

#include <assert.h>
#include <ctype.h>

#include "clistview.h"
#include "resourceadapter.h"

class SearchListItem : public QListBoxText {
public:
	SearchListItem(const QString& str) : QListBoxText(str) {
	}
	~SearchListItem() {
	}
	
	QListViewItem* listViewItem() {
		return oItem;
	}
	void setListViewItem(QListViewItem* item) {
		oItem = item;
	}
	
private:
	QListViewItem* oItem;
};

CSearchListDialog::CSearchListDialog(CListView* parent, int findCol, const char* name)
	: QDialog(0, name, false, Qt::WDestructiveClose)
	, oParent(parent)
	, oFindCol(findCol)
{
	setIcon(Resource::getBitmap(IDR_PNG7));
	setCaption(stdCaption(tr("Find member") + "..."));
	oLabel = new QLabel(tr("Member") + ":", this);
	oLabel->setAutoResize(true);
	oLabel->update();
	
	oEdit = new QComboBox(this);
	oEdit->setFocus();
	
	oFilterLabel = new QLabel(tr("Filter") + ":", this);
	oFilterLabel->setAutoResize(true);
	oFilterLabel->update();
	oLastFilter = "*";
	oFilter = new QLineEdit(this);
	oFilter->setText(oLastFilter);
	oFilter->installEventFilter(this);
	connect(oFilter, SIGNAL(returnPressed()), SLOT(slotFilterChanged()));
	
	setFixedHeight(5 + 20 + 5 + 20 + 5);
	setMinimumWidth(200);
	resize(250, 30);
	
	initComboBox();
}

CSearchListDialog::~CSearchListDialog()
{
}

bool
CSearchListDialog::event(QEvent* e)
{
	raise();
	
	return QDialog::event(e);
}

void
CSearchListDialog::resizeEvent(QResizeEvent*)
{
	oEdit->resize(width() - oLabel->width() - 5 - 5 - 5, 20);
	oEdit->move(5 + oLabel->width() + 5, 5);
	oLabel->move(5, 5 + oEdit->height()/2 - oLabel->height()/2);
	
	int x = (oFilterLabel->width() > oLabel->width()) ? oFilterLabel->width() : oLabel->width();
	oFilter->resize(width() - x - 5 - 5 - 5, 20);
	oFilter->move(5 + x + 5, oEdit->y() + oEdit->height() + 5);
	oFilterLabel->move(5, oFilter->y() + oFilter->height()/2 - oFilterLabel->height()/2);
}

bool
CSearchListDialog::eventFilter(QObject* obj, QEvent* e)
{
	if (obj == oEdit->lineEdit()) {
		if (e->type() == QEvent::Accel || e->type() == QEvent::KeyPress) {
			QKeyEvent* ke = static_cast<QKeyEvent*>(e);
			if (ke->key() == Key_Return) {
				close();
				
				return true;
			}
		}
	}
	else if (obj == oFilter) {
		if (e->type() == QEvent::FocusOut) {
			slotFilterChanged();
		}
	}
	
	return false;
}

/**** The next three slots are somewhat tricky/awfull */

void
CSearchListDialog::slotHighlighted(int item)
{
	bool blocked = oEdit->signalsBlocked();
	oEdit->blockSignals(true);
	
	// I think that QComboBox should do this
	oEdit->listBox()->setCurrentItem(item);
	
	// take care of duplicate entries since QComboBox tends to ignore them
	QString str = oEdit->lineEdit()->text();
	oEdit->setCurrentItem(item);
	oEdit->lineEdit()->setText(str);
	oEdit->lineEdit()->setCursorPosition(str.length());
	oEdit->blockSignals(blocked);
}

void
CSearchListDialog::slotSelectionChanged()
{
	bool blocked = oEdit->signalsBlocked();
	oEdit->blockSignals(true);
	// show entry
	SearchListItem* item = dynamic_cast<SearchListItem*>(oEdit->listBox()->item(oEdit->listBox()->currentItem()));
	if (item != 0) {
		oParent->ensureItemVisible(item->listViewItem());
		oParent->setCurrentItem(item->listViewItem());
	}
	oEdit->blockSignals(blocked);
}

void
CSearchListDialog::slotTextChanged(const QString& str)
{
	if (!isdigit(str.at(0).latin1())) {
		if (!str.isEmpty()) {
			bool blocked = oEdit->signalsBlocked();
			oEdit->blockSignals(true);
			int pos = 0;
			QString cStr = str;
			for (pos = 0; pos < oEdit->count(); pos++) {
				if (oEdit->text(pos).left(str.length()) == str) {
					break;
				}
			}
			
			// found ?
			if (pos < oEdit->count()) { // yes
				oEdit->setCurrentItem(pos);
				oEdit->setEditText(cStr);
				oLastStr = cStr;
				
				oEdit->listBox()->setCurrentItem(pos);
			}
			else { // no, not found
				oEdit->setEditText(oLastStr);
				oEdit->lineEdit()->setCursorPosition(oLastStr.length());
			}
			oEdit->blockSignals(blocked);
		}
	}
}

/***** End tricky. */

void
CSearchListDialog::slotFilterChanged()
{
	if (oLastFilter != oFilter->text()) {
		oLastFilter = oFilter->text();
		updateList();
		oEdit->setFocus();
		
		if (oEdit->count() > 0) {
			oEdit->setCurrentItem(0);
		}
	}
}

void
CSearchListDialog::initComboBox()
{
	if (oParent->firstChild() != 0) {
		oEdit->setEditable(true);
		oEdit->setAutoCompletion(false);
		
		oEdit->lineEdit()->installEventFilter(this);
		oEdit->setEditText("");
		
		connect(oEdit, SIGNAL(textChanged(const QString&)), SLOT(slotTextChanged(const QString&)));
		connect(oEdit, SIGNAL(highlighted(int)), SLOT(slotHighlighted(int)));
		connect(oEdit->listBox(), SIGNAL(selectionChanged()), SLOT(slotSelectionChanged()));
		
		updateList();
	}
}


void
CSearchListDialog::updateList()
{
	if (oParent->firstChild() == 0) {
		return;
	}
	
	oEdit->clear();
	
	if (oFilter->text() == "*" || oFilter->text().isEmpty()) {
		for (QListViewItemIterator it = oParent->firstChild(); it.current() != 0; ++it) {
			if (!isdigit(it.current()->text(oFindCol).at(0).latin1())) {
				SearchListItem* item = new SearchListItem(it.current()->text(oFindCol));
				item->setListViewItem(it.current());
				oEdit->listBox()->insertItem(item);
			}
		}
	}
	else {
		QString f = oFilter->text();
		if (f.find("*") == -1 && f.find("?") == -1) { // force globbing
			f += "*";
		}
		
		QRegExp reg(
			f,			// pattern
			false,		// case sensitive
			true		// wildcard
		);
		
		for (QListViewItemIterator it = oParent->firstChild(); it.current() != 0; ++it) {
			if (it.current()->text(oFindCol).find(reg) != -1) {
				SearchListItem* item = new SearchListItem(it.current()->text(oFindCol));
				item->setListViewItem(it.current());
				oEdit->listBox()->insertItem(item);
			}
		}
	}
	
	oEdit->listBox()->sort();
}
