#include <tqcombobox.h>
#include <tqevent.h>
#include <tqfile.h>
#include <tqguardedptr.h>
#include <tqlayout.h>
#include <tqlineedit.h>
#include <tqmap.h>
#include <tqpushbutton.h>
#include <tqradiobutton.h>
#include <tqscrollview.h>
#include <tqsizepolicy.h>
#include <tqstring.h>
#include <tqstringlist.h>
#include <tqtextstream.h>
#include <tqtimer.h>
#include <tqtooltip.h>
#include <tqvaluelist.h>
#include <tqwhatsthis.h>
#include <tqwidget.h>

#include <tdeaccel.h>
#include <tdeaction.h>
#include <tdeconfig.h>
#include <kdebug.h>
#include <kedittoolbar.h>
#include <kdialog.h>
#include <tdefiledialog.h>
#include <tdeglobal.h>
#include <klineedit.h>
#include <tdelocale.h>
#include <kkeydialog.h>
#include <tdemainwindow.h>
#include <knotifyclient.h>
#include <tdestandarddirs.h>
#include <kstatusbar.h>
#include <kstdaction.h>
#include <tdetoolbar.h>

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "keypad.h"
#include "kparanoidline.h"
#include "mathemagics.h"

Mathemagics::Mathemagics(TQWidget *parent, const char *name, WFlags f)
	: TDEMainWindow(parent, name, f)
{
	noSave = false;
	enterMode = false;
	numStackLevels = 0;
	stackLevels.setAutoDelete(true);
	
	TQWidget *dummy = new TQWidget(this);
	setCentralWidget(dummy);
	
	TQVBoxLayout *topLayout = new TQVBoxLayout(dummy, 0, KDialog::spacingHint());

	topLevel = new TQScrollView(dummy);
	topLayout->addWidget(topLevel);
	
	boxParent = new TQWidget(topLevel->viewport());
	topLevel->addChild(boxParent);
	topLevel->setResizePolicy(TQScrollView::AutoOneFit);

	bigBox = new TQVBoxLayout(boxParent, KDialog::marginHint(), KDialog::spacingHint());

	LineEdit = new EditAction(i18n("Values"), 0, this, TQ_SLOT(slotEnter()), actionCollection(), "lineedit");
	HistoryBox = new ComboAction(i18n("History"), 0, 0, 0, actionCollection(), "history");
	
	keypadAct = new TDEToggleAction(i18n("Show Keypad"), "Ctrl+K", 0, 0, actionCollection(), "keypad");
	connect(keypadAct, TQ_SIGNAL(toggled(bool)), TQ_SLOT(toggleKeypad(bool)));

	keypad = new MathKeypad(dummy, "Keypad");
	topLayout->addWidget(keypad);

	connect(keypad, TQ_SIGNAL(closing()), this, TQ_SLOT(keypadClosing()));
	connect(keypad, TQ_SIGNAL(insertChar(const TQString &)), this, TQ_SLOT(insertChar(const TQString &)));
	connect(keypad, TQ_SIGNAL(add()), this, TQ_SLOT(slotAdd()));
	connect(keypad, TQ_SIGNAL(subtract()), this, TQ_SLOT(slotSubtract()));
	connect(keypad, TQ_SIGNAL(multiply()), this, TQ_SLOT(slotMultiply()));
	connect(keypad, TQ_SIGNAL(divide()), this, TQ_SLOT(slotDivide()));
	connect(keypad, TQ_SIGNAL(enter()), this, TQ_SLOT(slotEnter()));
	connect(keypad, TQ_SIGNAL(backspace()), this, TQ_SLOT(slotKeypadBackspace()));
	connect(keypad, TQ_SIGNAL(eex()), this, TQ_SLOT(slotEEX()));
	keypad->hide();

	TQStringList options(i18n("Degrees"));
	options.append(i18n("Radians"));
	options.append(i18n("Grads"));
	angGroup = new TDEListAction(i18n("Angle"), 0, 0, 0, actionCollection(), "angle");
	angGroup->setItems(options);

	options.clear();
	options.append(i18n("Hexadecimal"));
	options.append(i18n("Decimal"));
	options.append(i18n("Octal"));
	options.append(i18n("Binary"));
	baseGroup = new TDEListAction(i18n("Base"), 0, 0, 0, actionCollection(), "base");
	baseGroup->setItems(options);

	TQStringList defaultFormulae;
	formulae = new TDEListAction(i18n("&Formulae"), 0, 0, 0, actionCollection(), "formulae");
#include "formulae"
	formulae->setItems(defaultFormulae);
	formulae->setCurrentItem(-1);

	(void) KStdAction::quit(this, TQ_SLOT(close()), actionCollection());
	(void) KStdAction::open(this, TQ_SLOT(slotOpen()), actionCollection());

	(void) KStdAction::preferences(this, TQ_SLOT(slotConfigure()), actionCollection());
	(void) KStdAction::undo(this, TQ_SLOT(slotRestoreStack()), actionCollection())->setText(i18n("Restore stack levels"));

	(void) KStdAction::configureToolbars(this, TQ_SLOT(configureToolBars()), actionCollection());
	(void) KStdAction::keyBindings(this, TQ_SLOT(keyBindings()), actionCollection());

	(void) new TDEAction(i18n("+/-"), "Alt+-", this, TQ_SLOT(slotNegative()), actionCollection(), "+/-");
	(void) new TDEAction("x!", "Alt+!", this, TQ_SLOT(slotFactorial()), actionCollection(), "factorial");
	(void) new TDEAction("1/x", "Alt+i", this, TQ_SLOT(slotInverse()), actionCollection(), "1/x");
	(void) new TDEAction("10^x", 0, this, TQ_SLOT(slotRaiseTen()), actionCollection(), "10^x");
	(void) new TDEAction("e^x", "Alt+E", this, TQ_SLOT(slotRaiseE()), actionCollection(), "e^x");
	(void) new TDEAction("Mod", "Alt+M", this, TQ_SLOT(slotModulo()), actionCollection(), "modulo");
	(void) new TDEAction("Ln", "Alt+L", this, TQ_SLOT(slotLn()), actionCollection(), "ln");
	(void) new TDEAction("%", "Alt+%", this, TQ_SLOT(slotPercent()), actionCollection(), "percent");
	(void) new TDEAction("Sqrt", "Alt+R", this, TQ_SLOT(slotSqrt()), actionCollection(), "sqrt");
	(void) new TDEAction("x^2", "Alt+Shift+S", this, TQ_SLOT(slotSquared()), actionCollection(), "x^2");
	(void) new TDEAction("y^x", "Alt+^", this, TQ_SLOT(slotPower()), actionCollection(), "y^x");

	InvButton = new TDEToggleAction("Inv", "Ctrl+I", 0, 0, actionCollection(), "inverse");
	HypButton = new TDEToggleAction("Hyp", "Ctrl+H", 0, 0, actionCollection(), "hyperbolic");

	// bitwise
	(void) new TDEAction(i18n("And"), "Alt+A", this, TQ_SLOT(slotAnd()), actionCollection(), "bitwise_and");
	(void) new TDEAction(i18n("Or"), "Alt+O", this, TQ_SLOT(slotOr()), actionCollection(), "bitwise_or");
	(void) new TDEAction(i18n("XOr"), "Alt+X", this, TQ_SLOT(slotXOr()), actionCollection(), "bitwise_xor");
	(void) new TDEAction(i18n("Left Shift"), "back", 0, this, TQ_SLOT(slotLsh()), actionCollection(), "bitwise_lsh");
	(void) new TDEAction(i18n("Right Shift"), "forward", 0, this, TQ_SLOT(slotRsh()), actionCollection(), "bitwise_rsh");

	// trig
	(void) new TDEAction("Sin", "Alt+S", this, TQ_SLOT(slotSine()), actionCollection(), "sin");
	(void) new TDEAction("Cos", "Alt+C", this, TQ_SLOT(slotCosine()), actionCollection(), "cos");
	(void) new TDEAction("Tan", "Alt+T", this, TQ_SLOT(slotTangent()), actionCollection(), "tan");

	// edit
	(void) new TDEAction(i18n("&Revert Stack Changes"), 0, this, TQ_SLOT(slotRevert()), actionCollection(), "revert");
	(void) new TDEAction(i18n("&Drop"), 0, this, TQ_SLOT(slotDrop()), actionCollection(), "drop");

	setStandardToolBarMenuEnabled(true);
	statusBar();
	createGUI();

	resize(430, 500);
	applyMainWindowSettings(TDEGlobal::config(), "TopLevelWindow");

	// signals and slots connections
	connect(baseGroup, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotBaseChanged(int)));
	connect(angGroup, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotAngleChanged(int)));

	connect(formulae, TQ_SIGNAL(activated(const TQString &)), this, TQ_SLOT(runFormula(const TQString &)));

	connect(HistoryBox->combo(), TQ_SIGNAL(activated(const TQString&)), this, TQ_SLOT(slotPushHighlighted(const TQString&)));

	connect(LineEdit->edit(), TQ_SIGNAL(backspacePressed()), this, TQ_SLOT(slotBackspace()));

	pi = asin(1L) * 2L;
	variables["pi"] = pi;
	defVariables.append("pi");
	variables["e"] = exp(1);
	defVariables.append("e");
	variables["true"] = 1;
	defVariables.append("true");
	variables["false"] = 0;
	defVariables.append("false");
	variables["degkey"] = 0;
	defVariables.append("degkey");
	variables["radkey"] = 1;
	defVariables.append("radkey");
	variables["gradkey"] = 2;
	defVariables.append("gradkey");

	Stack = new TQValueList<double>;
	SavedStack = new TQValueList<double>;
	optionDialog = 0;

	// how long do status msgs stay up? in ms
	dispTime = 1500;

	tdeApp->config()->setGroup("App");

	bool showkeys = tdeApp->config()->readBoolEntry("show keypad", true);
	toggleKeypad(showkeys);
	keypadAct->setChecked(showkeys);

	slotUpdateConfiguration();
	
	tdeApp->config()->setGroup("Session");

	TQStringList stackList = tdeApp->config()->readListEntry("Stack", ',');
	int i;

	TQStringList historyList = tdeApp->config()->readListEntry("History", ',');
	int count = historyList.count();
	if (historyList.first() != "Nothing" && count > 0)
	{
		if (count > histNum)
			count = histNum;

		for (i = 0; i < count; i++)
			HistoryBox->combo()->insertItem(*historyList.at(i));

		HistoryBox->combo()->setCurrentItem(HistoryBox->combo()->count() - 1);
	}

	base = 10; // this necessary so we can
	           // setbase properly :P

	// default config choices
	runCommand("$degkey"); runCommand("setangle");
	runCommand("10"); runCommand("setbase");
	runCommand("$false"); runCommand("sethyp");
	updateStack();

	// load session file
	openFile(TDEGlobal::dirs()->saveLocation("appdata") + "session");

	saveStack();

	LineEdit->edit()->setFocus();

	statusBar()->message(i18n("Welcome to Mathemagics"), dispTime);
}

Mathemagics::~Mathemagics()
{
	delete Stack;
	delete SavedStack;
	delete optionDialog;
	delete keypad;
}

void Mathemagics::keypadClosing()
{
	keypadAct->setChecked(false);
}

void Mathemagics::insertChar(const TQString &s)
{
	LineEdit->insert(s);
}

void Mathemagics::updateStack()
{
	StackLevel *level;
	const int count = Stack->count();
	int i = 1;
	for (level = stackLevels.first(); level; level = stackLevels.next(), ++i)
	{
		if (i > count)
		{
			for (; level; level = stackLevels.next())
			{
				level->edit()->clear();
				level->setEnabled(false);
			}
			break;
		}

		level->setEnabled(true);
		level->edit()->setText(format(*Stack->at(i - 1)));
	}

	TQTimer::singleShot(100, this, TQ_SLOT(scrollToBottom()));
}

void Mathemagics::enter()
{
	const bool notDec = base != 10;
	bool noClear = false;

	saveStack();

	bool oldNoSave = noSave;
	noSave = true;

	TQStringList entryNums = this->entryNums;
	this->entryNums.clear();

	TQString oldLineText = LineEdit->edit()->text();
	LineEdit->clear();

	for (TQStringList::Iterator it = entryNums.begin(); it != entryNums.end(); ++it)
	{
		int eIndex;
		int eqIndex = (*it).find('=');
		int dolIndex = (*it).find('$');
		bool ok;
		double val;

		if (eqIndex >= 0 && (dolIndex < 0 || dolIndex > eqIndex)) // add equation
		{
			TQString formulaName = (*it).left(eqIndex);
			if (formulaName.isEmpty())
				continue;

			TQString formula = (*it).right((*it).length() - eqIndex - 1);

			for (++it; it != entryNums.end(); ++it)
			{
				formula.append(" ");
				formula.append(*it);
			}

			formulas[formulaName] = formula;

			TQStringList newList(formulae->items());
			newList.remove(formulaName);

			if (!formulaName.isEmpty())
				newList.append(formulaName);

			formulae->setItems(newList);

			statusBar()->message(i18n("Formula %1 added").arg(formulaName), dispTime);

			break;
		}
		else if ((eIndex = (*it).find('E')) != -1 && !notDec) // E found
		{
			TQString firstArg = (*it).left(eIndex);
			if (firstArg.isEmpty())
				continue;
			TQString secondArg = (*it).right((*it).length() - eIndex - 1);
			val = firstArg.toDouble(&ok) * pow(10, secondArg.toDouble(&ok));
			if (ok)
			{
				Stack->prepend(val);
				continue;
			}
			// else try something else below
		}

		// plain
		val = format(*it, &ok);
		if (ok)
		{
			Stack->prepend(val);
			continue;
		}

		if (enterMode)
			if (!runCommand((*it).lower()))
				break;
	}

	if (noClear)
		LineEdit->edit()->setText(oldLineText);

	noSave = oldNoSave;
}

void Mathemagics::slotEnter()
{
	enterMode = true;

	if (LineEdit->text().isEmpty() && Stack->count() >= 1)
		// dup
		Stack->prepend(Stack->first());
	else
		parseArgs(false, true, false);

	updateStack();

	enterMode = false;
}

bool Mathemagics::parseArgs(unsigned int reqArgs, bool autoEnter, bool save)
{
	int entryNumsCount = 0;

	if (!LineEdit->text().isEmpty())
	{
		entryNums = TQStringList::split(TQChar(' '), LineEdit->text());
		entryNumsCount = entryNums.count();
	}

	if (Stack->count() + entryNumsCount < reqArgs)
	{
		changeStatusError(i18n("At least %1 arguments required").arg(reqArgs));
		return false;
	}

	if (save)
		saveStack();

	if (autoEnter)
		enter();

	return true;
}

int Mathemagics::testArgs()
{
	int entryNumsCount = 0;

	if (!LineEdit->text().isEmpty())
	{
		entryNums = TQStringList::split(TQChar(' '), LineEdit->text());
		entryNumsCount = entryNums.count();
	}

	return entryNumsCount;
}

void Mathemagics::saveStack()
{
	if (noSave)
		return;

	*SavedStack = *Stack;
}

void Mathemagics::slotRestoreStack()
{
	// a simple swap
	TQValueList<double> *SavedStackPtr = Stack;
	Stack = SavedStack;
	SavedStack = SavedStackPtr;

	updateStack();
}

void Mathemagics::slotAdd()
{
	if (!parseArgs(2))
		return; 

	double theResult = (* Stack->at(0)) + (* Stack->at(1));
	changeStatus(& theResult, '+');
	Stack->pop_front();
	Stack->pop_front();
	Stack->prepend(theResult);
	updateStack();
}

void Mathemagics::slotSubtract()
{
	if (!parseArgs(2))
		return;
	
	double theResult = (* Stack->at(1)) - (* Stack->at(0));
	changeStatus(& theResult, '-');
	Stack->pop_front();
	Stack->pop_front();
	Stack->prepend(theResult);
	updateStack();
}

void Mathemagics::slotMultiply()
{
	if (!parseArgs(2))
		return;
	
	double theResult = (* Stack->at(0)) * (* Stack->at(1));
	changeStatus(& theResult, '*');
	Stack->pop_front();
	Stack->pop_front();
	Stack->prepend(theResult);
	updateStack();
}

void Mathemagics::slotDivide()
{
	getArgs(1);
	if (args.first() == 0)
	{
		error();
		return;
	}

	if (!parseArgs(2))
		return;
	
	double theResult = (* Stack->at(1)) / (* Stack->at(0));
	changeStatus(& theResult, '/');
	Stack->pop_front();
	Stack->pop_front();
	Stack->prepend(theResult);
	updateStack();
}

void Mathemagics::slotRaiseE()
{
	if (!parseArgs(1))
		return;
	
	double theResult;

	theResult = exp(Stack->first());
	changeStatus(& theResult, i18n("e ^ "), 1);

	Stack->pop_front();
	Stack->prepend(theResult);
	updateStack();
}

void Mathemagics::slotInverse()
{
	if (!parseArgs(1))
		return;
	
	double theResult;

	theResult = 1 / Stack->first();
	changeStatus(& theResult, i18n("1 / "), 1);

	Stack->pop_front();
	Stack->prepend(theResult);
	updateStack();
}

void Mathemagics::slotSquared()
{
	if (!parseArgs(1))
		return;

	double level1 = Stack->first();
	level1 *= level1;
	changeStatus(&level1, i18n(" ^ 2"));
	Stack->pop_front();
	Stack->prepend(level1);

	updateStack();
}

void Mathemagics::slotSqrt()
{
	getArgs(1);
	if (args.first() < 0)
	{
		changeStatusError(i18n("Complex number"));
		return;
	}

	if (!parseArgs(1))
		return;

	double theResult = sqrt(Stack->first());
	changeStatus(&theResult, i18n("Square root of "), 1);
	Stack->pop_front();
	Stack->prepend(theResult);

	updateStack();
}

void Mathemagics::slotSine()
{
	double theResult;

	if (InvButton->isChecked())
	{
		if (HypButton->isChecked())
		{
			if (!parseArgs(1))
				return;

			theResult = asinh(Stack->first());
			changeStatus(& theResult, i18n("Hyp ArcSine of "), 1);
		}
		else
		{
			if (!getArgs(1))
				return;

			double lev1 = args.first();
			if (lev1 < -1 || lev1 > 1)
			{
				error();
				return;
			}

			parseArgs(1);

			theResult = angOut(asin(Stack->first()));
			changeStatus(& theResult, i18n("ArcSine of "), 1);
		}

		InvButton->setChecked(false);
	}
	else
	{
		if (!parseArgs(1))
			return;

		if (HypButton->isChecked())
		{
			theResult = sinh(Stack->first());
			changeStatus(& theResult, i18n("Hyp Sine of "), 1);
		}
		else
		{
			theResult = sin(angConv(Stack->first()));
			changeStatus(& theResult, i18n("Sine of "), 1);
		}
	}

	Stack->pop_front();
	Stack->prepend(theResult);
	updateStack();
}

void Mathemagics::slotCosine()
{
	double theResult;

	if (InvButton->isChecked())
	{
		if (!getArgs(1))
			return;

		if (HypButton->isChecked())
		{
			if (args.first() < 1)
			{
				error();
				return;
			}

			parseArgs(1);

			theResult = acosh(Stack->first());
			changeStatus(& theResult, i18n("Hyp ArcCosine of "), 1);
		}
		else
		{
			double lev1 = args.first();
			if (lev1 < -1 || lev1 > 1)
			{
				error();
				InvButton->setChecked(false);
				return;
			}
			
			parseArgs(1);
	
			theResult = angOut(acos(Stack->first()));
			changeStatus(& theResult, i18n("ArcCosine of "), 1);
		}

		InvButton->setChecked(false);
	}
	else
	{
		if (!parseArgs(1))
			return;

		if (HypButton->isChecked())
		{
			theResult = cosh(Stack->first());
			changeStatus(& theResult, i18n("Hyp Cosine of "), 1);
		}
		else
		{
			theResult = cos(angConv(Stack->first()));
			changeStatus(& theResult, i18n("Cosine of "), 1);
		}
	}

	Stack->pop_front();
	Stack->prepend(theResult);
	updateStack();
}

void Mathemagics::slotTangent()
{
	double theResult;

	if (InvButton->isChecked())
	{
		if (HypButton->isChecked())
		{
			if (!getArgs(1))
				return;

			if (fabs(args.first()) > 1)
			{
				error();
				return;
			}

			parseArgs(1);

			theResult = atanh(Stack->first());
			changeStatus(& theResult, i18n("Hyp ArcTangent of "), 1);
		}
		else
		{
			if (!parseArgs(1))
				return;

			theResult = angOut(atan(Stack->first()));
			changeStatus(& theResult, i18n("ArcTangent of "), 1);
		}

		InvButton->setChecked(false);
	}
	else
	{
		if (!parseArgs(1))
			return;

		if (HypButton->isChecked())
		{
			theResult = tanh(Stack->first());
			changeStatus(& theResult, i18n("Hyp Tangent of "), 1);
		}
		else
		{
			theResult = tan(angConv(Stack->first()));
			changeStatus(& theResult, i18n("Tangent of "), 1);
		}
	}

	Stack->pop_front();
	Stack->prepend(theResult);
	updateStack();
}

void Mathemagics::slotLn()
{
	if (!getArgs(1))
		return;

	if (args.first() <= 0)
	{
		error();
		return;
	}
	
	double theResult;
	parseArgs(1);

	theResult = log(Stack->first());
	changeStatus(& theResult, i18n("ln "), 1);
	Stack->pop_front();
	Stack->prepend(theResult);

	updateStack();
}

void Mathemagics::slotFactorial()
{
	if (!getArgs(1))
		return;

	double lev1 = args.first();

	if ((int)lev1 != lev1 || lev1 <= 0)
	{
		changeStatusError(i18n("Not implemented"));
		return;
	}

	if (parseArgs(1))
	{
		int n = fact(Stack->first());
		double theDouble = (double)n;
		changeStatus(& theDouble, "!");
		Stack->first() = n;
		updateStack();
	}
}

int Mathemagics::fact(int n)
{
	if (n <= 0)
		return 1;
	else
		return n * fact(n-1);
}

void Mathemagics::slotRaiseTen()
{
	if (!parseArgs(1))
		return;

	double theResult = pow(10, Stack->first());

	changeStatus(&theResult, i18n("10 ^ "), 1);

	Stack->first() = theResult;

	updateStack();
}

void Mathemagics::slotEEX()
{
	if (base == 10 || base >= 15)
		LineEdit->insert(TQString("E"));
}

void Mathemagics::slotPercent()
{
	double theResult;

	if (!parseArgs(2))
		return;

	theResult = (*Stack->at(1) / Stack->first()) * 100;
	changeStatus(&theResult, '%');

	Stack->pop_front();
	Stack->first() = theResult;
	updateStack();
}

void Mathemagics::slotModulo()
{
	double theResult;

	if (!getArgs(1))
		return;
	if (args.first() == 0)
	{
		error();
		return;
	}

	if (!parseArgs(2))
		return;

	theResult = fmod(*Stack->at(1), Stack->first());
	changeStatus(&theResult, TQString(i18n("%1 mod ")).arg(*Stack->at(1)), 1);
	
	Stack->pop_front();
	Stack->first() = theResult;

	updateStack();
}

void Mathemagics::slotPower()
{
	double theResult;

	if (!getArgs(2))
		return;

	if (InvButton->isChecked())
	{
		if (*args.at(1) < 0)
		{
			changeStatusError(i18n("Complex number"));
			return;
		}

		parseArgs(2);

		theResult = pow(*Stack->at(1), 1 / Stack->first());
		changeStatus(&theResult, TQString(i18n("%1 root of ")).arg(format(*Stack->at(1))), true);

		InvButton->setChecked(false);
	}
	else
	{
		double lev1 = args.first();
		
		if (*args.at(1) < 0 && (int)lev1 != lev1)
		{
			changeStatusError(i18n("Complex number"));
			return;
		}

		parseArgs(2);

		theResult = pow(*Stack->at(1), Stack->first());
		changeStatus(&theResult, TQString(i18n("%1 ^ ")).arg(format(*Stack->at(1))), 1);
	}

	Stack->pop_front();
	Stack->first() = theResult;
	updateStack();
}

void Mathemagics::slotNegative()
{
	if (LineEdit->text().isEmpty() && Stack->count() >= 1)
	{
		saveStack();
		Stack->first() *= -1;
		updateStack();
	}
	else
	{
		TQString text = LineEdit->text();

		unsigned int cursPos = LineEdit->edit()->cursorPosition();
		unsigned int length = text.length();

		int eindex = text.findRev('E', cursPos - length - 1);
		int negIndex = text.findRev(' ', cursPos - length - 1) + 1;

		if (base == 10 && eindex != -1)
			negIndex = eindex + 1;

		if (text.at(negIndex) == TQChar('-'))
		{
			text.remove(negIndex, 1);
			LineEdit->edit()->setText(text);
			LineEdit->edit()->setCursorPosition(cursPos - 1);
		}
		else
		{
			text.insert(negIndex, '-');
			LineEdit->edit()->setText(text);
			LineEdit->edit()->setCursorPosition(cursPos + 1);
		}
	}
}

void Mathemagics::slotAnd()
{
	long double theResult;
	if (parseArgs(2))
	{
		theResult = (long int)Stack->first() & (long int)*Stack->at(1);
		double pass = (double)theResult;
		changeStatus(&pass, TQString(i18n("%1 AND ")).arg(format(*Stack->at(1))), 1);
		Stack->pop_front();
		Stack->pop_front();
		Stack->prepend(theResult);

		updateStack();
	}
}

void Mathemagics::slotXOr()
{
	if (!parseArgs(2))
		return;

	double theResult;
	theResult = (long int)Stack->first() ^ (long int)*Stack->at(1);
	changeStatus(&theResult, TQString(i18n("%1 XOR ")).arg(format(*Stack->at(1))), 1);
	Stack->pop_front();
	Stack->pop_front();
	Stack->prepend(theResult);
}

void Mathemagics::slotOr()
{
	if (!parseArgs(2))
		return;

	double theResult;
	theResult = (long int)Stack->first() | (long int)*Stack->at(1);
	changeStatus(&theResult, TQString(i18n("%1 OR ")).arg(format(*Stack->at(1))), 1);
	Stack->pop_front();
	Stack->pop_front();
	Stack->prepend(theResult);

	updateStack();
}

void Mathemagics::slotRsh()
{
	if (!parseArgs(2))
		return;

	double theResult;
	
	theResult = (long int)*Stack->at(1) >> (long int)Stack->first();
	changeStatus(&theResult, TQString(i18n("%1 RSH ")).arg(format(*Stack->at(1))), true);

	Stack->pop_front();
	Stack->pop_front();
	Stack->prepend(theResult);

	updateStack();
}

void Mathemagics::slotLsh()
{
	if (!parseArgs(2))
		return;

	double theResult;

	theResult = (long int)*Stack->at(1) << (long int)Stack->first();
	changeStatus(&theResult, TQString(i18n("%1 LSH ")).arg(format(*Stack->at(1))), true);

	Stack->pop_front();
	Stack->pop_front();
	Stack->prepend(theResult);

	updateStack();
}

void Mathemagics::slotDup2()
{
	if (!parseArgs(2))
		return;

	Stack->prepend(* Stack->at(1));
	Stack->prepend(* Stack->at(1));

	updateStack();
}

void Mathemagics::slotDrop()
{
	if (!parseArgs(1))
		return;

	Stack->pop_front();

	updateStack();
}

void Mathemagics::slotKeypadBackspace()
{
	slotBackspace();
	LineEdit->edit()->backspace();
}

void Mathemagics::slotBackspace()
{
	if (InvButton->isChecked())
	{
		saveStack();

		Stack->clear();

		updateStack();
		InvButton->setChecked(false);
		return;
	}

	if (LineEdit->text().isEmpty())
	{
		if (!Stack->isEmpty() && delDrops)
		{
			saveStack();
			Stack->pop_front();
			updateStack();
		}
	}
}

void Mathemagics::closeEvent(TQCloseEvent * /*e*/)
{
	TQString list;
	unsigned int i;

	tdeApp->config()->setGroup("Session");

	// save history for next time
	int count = HistoryBox->combo()->count();

	if (count != 0)
	{
		list = HistoryBox->combo()->text(0);
		for (i = 1; i < (unsigned int)count; i++)
		{
			list.append(',');
			list.append(HistoryBox->combo()->text(i));
		}
		tdeApp->config()->writeEntry("History", list);
	}
	else
		tdeApp->config()->writeEntry("History", "Nothing");


	tdeApp->config()->setGroup("App");
	tdeApp->config()->writeEntry("show keypad", keypadAct->isChecked());

	tdeApp->config()->sync();

	saveFile(TDEGlobal::dirs()->saveLocation("appdata") + "session");

	saveMainWindowSettings(TDEGlobal::config(), "TopLevelWindow");

	tdeApp->quit();
}

void Mathemagics::slotConfigure()
{
	if (optionDialog == 0)
	{
		optionDialog = new ConfigureDialog(topLevelWidget());

		if (optionDialog == 0) 
			return;

		connect(optionDialog, TQ_SIGNAL(hidden()),this,TQ_SLOT(slotConfigureHide()));
		connect(optionDialog, TQ_SIGNAL(valueChanged()), this, TQ_SLOT(slotUpdateConfiguration()));
		connect(optionDialog, TQ_SIGNAL(clearHistory()), this, TQ_SLOT(clearHistory()));
	}

	optionDialog->show();
}

void Mathemagics::slotConfigureHide()
{
	TQTimer::singleShot(0, this, TQ_SLOT(slotConfigureDestroy()));
}

void Mathemagics::slotConfigureDestroy()
{
	if (optionDialog != 0 && optionDialog->isVisible() == 0)
	{
		delete optionDialog;
		optionDialog = 0;
	}
}

void Mathemagics::slotBaseChanged(int id)
{
	switch (id)
	{
		case 0:
			base = 16;
			break;

		case 1:
			base = 10;
			break;

		case 2:
			base = 8;
			break;

		case 3:
			base = 2;
			break;
	}

	updateStack();

	statusBar()->message(i18n("Base changed to %1").arg(base), dispTime);
}

void Mathemagics::slotAngleChanged(int id)
{
	angle = id;

	statusBar()->message(i18n("Angle changed to %1").arg(theAngle()), dispTime);
}

void Mathemagics::recreateStackLevels()
{ 
	stackLevels.clear();

	for (int i = numStackLevels; i > 0; --i)
	{
		StackLevel *level = new StackLevel(i, boxParent);
		connect(level, TQ_SIGNAL(buttonPressed(int)), this, TQ_SLOT(slotRoll(int)));
		connect(level, TQ_SIGNAL(returnPressed(int)), this, TQ_SLOT(slotUpdateStackLevel(int)));

		bigBox->addWidget(level);
		stackLevels.prepend(level);
		level->show();
	}
}

void Mathemagics::scrollToBottom()
{
	topLevel->ensureVisible(1, boxParent->height() - 1);
}

void Mathemagics::slotUpdateConfiguration()
{
	tdeApp->config()->setGroup("App");

	int oldNum = numStackLevels;
	numStackLevels = tdeApp->config()->readNumEntry("numStackLevels", 12);
	if (oldNum != numStackLevels)
		recreateStackLevels();

	fixedPrec = tdeApp->config()->readBoolEntry("fixedPrec", false);
	toSaveStack = tdeApp->config()->readBoolEntry("saveStack", true);
	showPeriod = tdeApp->config()->readBoolEntry("showPeriod", false);
	formatPrec = tdeApp->config()->readNumEntry("formatPrec", 8);
	histNum = tdeApp->config()->readNumEntry("histNum", 15);
	delDrops = tdeApp->config()->readBoolEntry("delDrops", true);
	histDetail = tdeApp->config()->readBoolEntry("histDetail", false);
	beep = tdeApp->config()->readBoolEntry("beep", true);

	updateStack();

	while (histNum < HistoryBox->combo()->count())
		HistoryBox->combo()->removeItem(0);

	HistoryBox->combo()->setCurrentItem(HistoryBox->combo()->count() - 1);
}

void Mathemagics::slotUpdateStackLevel(int level)
{
	saveStack();

	const TQString stackText(stackLevels.at(level - 1)->edit()->text());
	if (stackText.isEmpty())
	{
		Stack->remove(Stack->at(level - 1));
		updateStack();
		return;
	}
	
	bool ok;
	double val = format(stackText.section(' ', 0, 0), &ok);

	if (ok)
	{
		(*Stack->at(level - 1)) = val;
		stackLevels.at(level - 1)->edit()->setText(format(val));
		statusBar()->message(i18n("Change to level %1 applied").arg(level), dispTime);
	}
	else
		changeStatusError(i18n("Bad number"));
}

void Mathemagics::slotRevert()
{
	updateStack();
	statusBar()->message(i18n("Changes destroyed"), dispTime);
}

double Mathemagics::format(TQString theString, bool *ok)
{
	return (base != 10 ? (double)theString.toInt(ok, base) : theString.toDouble(ok));
}

TQString Mathemagics::format(double theDouble)
{
	if (base != 10) 
	{
		TQString convStr;
		convStr.setNum((int)theDouble, base);
		if (showPeriod)
			convStr.append('.');
		return convStr;
	}

	TQString decimal = TQString::number(theDouble, 'f', formatPrec);

	// leave zeroes on
	if (fixedPrec)
		return decimal;

	//this algorithm will find the last non-zero digits's index
	int i;
	for (i = decimal.length() - 1; i >= 0; i--)
	{
		if (decimal.at(i) != '0')
		{
			if (decimal.at(i) == '.')
			{
				if (!showPeriod) // get rid of the period
					i--;
			}
			break;
		}
	}

	// return the stuff that has no zeroes
	return decimal.mid(0, i + 1);
}

double Mathemagics::angConv(const double theDouble)
{
	switch (angle) 
	{
		case 0: // deg2rad
			return (((2L*pi)/360L) * theDouble);

		case 1: // rad2rad
			return (theDouble);

		case 2: // grad2rad
			return ((pi/200L) * theDouble);
	}

	return (theDouble);
}

double Mathemagics::angOut(const double theDouble)
{
	switch (angle) 
	{
		case 0: // rad2deg
			return ((360L/(2L*pi)) * theDouble);

		case 1: // rad2rad
			return (theDouble);

		case 2: // rad2grad
			return ((200L/pi) * theDouble);
	}

	return (theDouble);
}

bool Mathemagics::getArgs(unsigned int num)
{
	args.clear();
	unsigned int i;
	unsigned int lineArgs = testArgs();
	unsigned int stackArgs = Stack->count();
	if (lineArgs + stackArgs < num)
	{
		changeStatusError(i18n("Too few arguments"));
		return false;
	}

	for (i = lineArgs; i > 0; i--)
	{
		args.prepend(format(*entryNums.at(i - 1)));
		if (args.count() == num) return true;
	}

	for (i = 0; i < (num - lineArgs); i++)
	{
		args.prepend(*Stack->at(i));
		if (args.count() == num) return true;
	}

	return false; // won't get here
}

void Mathemagics::slotRoll(int level)
{
	saveStack();

	if (level <= 1)
		return;
	
	if (InvButton->isChecked())
	{
		rolld(level);
		InvButton->setChecked(false);
	}
	else
		roll(level);
}

void Mathemagics::roll(unsigned int index)
{
	if (Stack->count() < index || index <= 1)
		return;

	Stack->prepend(* Stack->at(index - 1));
	Stack->remove(Stack->at(index));

	updateStack();
}

void Mathemagics::rolld(unsigned int index)
{
	if (Stack->count() < index || index <= 1)
		return;

	Stack->insert(Stack->at(index), Stack->first());
	Stack->pop_front();

	updateStack();
}

void Mathemagics::changeStatus(TQString text)
{
	const unsigned int maxLength = 30;

	// keep hisNnum history spots, should never go over histNum
	// this removes last item..
	if (HistoryBox->combo()->count() >= histNum) HistoryBox->combo()->removeItem(0);

	if (histDetail)
		text = TQString(text + i18n("Base: %2; %3")).arg(base).arg(theAngle());

	if (text.length() > maxLength)
	{
		text = text.right(maxLength - 4);
		text.prepend("... ");
	}

	HistoryBox->combo()->insertItem(text, -1);
	HistoryBox->combo()->setCurrentItem(HistoryBox->combo()->count() - 1);
}

void Mathemagics::clearHistory()
{
	HistoryBox->combo()->clear();
}

TQString Mathemagics::theAngle()
{
	switch (angle)
	{
		case (0):
			return "Deg";

		case (1):
			return "Rad";

		case (2):
			return "Grad";
	}

	return "Deg";
}

void Mathemagics::slotPushHighlighted(const TQString& text)
{
	saveStack();

	int pipeIndex = text.findRev('|') - 1;
	int spaceIndex = text.findRev(' ', pipeIndex);

	if (pipeIndex == -2) // no pipe
	{
		Stack->prepend(format(text.mid(spaceIndex, text.length() - spaceIndex)));
	}
	else
	{
		int precSpaceIndex = text.findRev(' ', spaceIndex - 1);
		Stack->prepend(format(text.mid(precSpaceIndex, spaceIndex - precSpaceIndex)));
	}

	updateStack();
}

void Mathemagics::error()
{
	changeStatusError("Bad arguments");
}

void Mathemagics::changeStatusError(TQString text)
{
	text.prepend(i18n("Error: "));
	statusBar()->message(text, dispTime);

	if (beep)
		KNotifyClient::beep("Generic Error");
}

void Mathemagics::changeStatus(double * res, char op)
{
	changeStatus(TQString(i18n("%1 %2 %3 = %4")).arg(format(*Stack->at(1))).arg(op).arg(format(Stack->first())).arg(format(*res)));
}

void Mathemagics::changeStatus(double * res, TQString op, bool prepend)
{
	if (prepend)
		changeStatus(TQString(i18n("%1%2 = %3")).arg(op).arg(format(Stack->first())).arg(format(*res)));
	else
		changeStatus(TQString(i18n("%1%2 = %3")).arg(format(Stack->first())).arg(op).arg(format(*res)));
}

void Mathemagics::toggleKeypad(bool on)
{
	if (on)
		keypad->show();
	else
		keypad->hide();
}

void Mathemagics::slotOpen()
{
	TQString filename = KFileDialog::getOpenFileName();
	if (filename.isNull())
		return;
	
	openFile(filename);
}

void Mathemagics::openFile(const TQString &filename)
{
	TQFile f(filename);
	if (!f.open(IO_ReadOnly))
		return;

	enterMode = true;

	TQTextStream t(&f);
	while (!t.eof())
	{
		TQString s = t.readLine();

		// comments
		if (s.at(0) == '#')
			continue;

		if (!s.isEmpty())
		{
			entryNums = TQStringList::split(TQChar(' '), s);
			enter();
		}
	}

	enterMode = false;
	updateStack();
}

void Mathemagics::saveFile(const TQString &filename)
{
	TQFile f(filename);
	if (!f.open(IO_WriteOnly))
		return;

	TQTextStream t(&f);

	t << "# Saved by mathemagics" << endl;

	t.precision(15);

	if (toSaveStack)
	{
		// this is the reverse

		t << "# stack" << endl;

		bool already = false;

		TQValueList<double>::Iterator it = Stack->end();
		it--;

		while (1)
		{
			if (already)
				t << " ";
			t << *it;

			already = true;

			if (it == Stack->begin())
				break;
			else
				it--;
		}
	}
	t << endl;

	t << "# functions" << endl;
	for (TQMap<TQString, TQString>::Iterator it = formulas.begin(); it != formulas.end(); ++it)
	{
		if (defFormulas.contains(it.key()) <= 0)
			t << it.key() << "=" << it.data() << endl;
	}

	t << "# variables" << endl;
	for (TQMap<TQString, double>::Iterator it = variables.begin(); it != variables.end(); ++it)
	{
		if (defVariables.contains(it.key()) <= 0)
			t << it.data() << " $" << it.key() << "=" << endl;;
	}

	t << "# settings" << endl;
	t << base << " setbase" << endl;
	t << (angle == 0? "$degkey" : angle == 1? "$radkey" : "$gradkey")  << " setangle" << endl;
	t << (HypButton->isChecked() ? "$true" : "$false") << " sethyp" << endl;
}

void Mathemagics::runFormula(const TQString &name)
{
	formulae->setCurrentItem(-1);
	TQString s = formulas[name];

	saveStack();
	
	bool oldNoSave = noSave;
	noSave = true;

	TQStringList l = TQStringList::split(' ', s);
	for (TQStringList::Iterator it = l.begin(); it != l.end(); ++it)
	{
		TQString command = (*it);
		bool ok;
		double num = format(command, &ok);

		if (ok)
		{
			Stack->prepend(num);
			continue;
		}

		if (!runCommand(command))
			break;
	}

	noSave = oldNoSave;
}

// tests and returns startswith, and removes the search string from string if matches
bool removeStartsWith(TQString &s, const TQString &search)
{
	if (s.startsWith(search))
	{
		s = s.right(s.length() - search.length());
		return true;
	}
	else
		return false;
}

bool Mathemagics::runCommand(const TQString &command)
{
	// case insensitive
	TQString operateOn = command.lower();

	// allows operators to be embedded in numbers
	// this finds a number at beginning of command

	while (!operateOn.isEmpty())
	{
		TQChar firstChar(operateOn.at(0));
		if (firstChar.isNumber())
		{
			for (int i = operateOn.length(); i > 0; --i)
			{
				bool ok;
				double num = format(operateOn.left(i), &ok);

				if (ok)
				{
					Stack->prepend(num);
					operateOn = operateOn.right(operateOn.length() - i);
					continue;
				}
			}
		}

		if (firstChar == '$')
		{
			TQString varName = operateOn.right(operateOn.length() - 1);
			if (varName.isEmpty())
				return false;

			int eqIndex = varName.find('=');

			if (eqIndex >= 0)
			{
				// assign
				if (Stack->count() <= 0)
					return false;

				varName = varName.left(eqIndex);
	
				const double val = Stack->first();
				variables[varName] = val;
				Stack->pop_front();
	
				statusBar()->message(i18n("Variable %1 set to %2").arg(varName).arg(val), dispTime);

				operateOn = operateOn.right(operateOn.length() - eqIndex - 2);
			}
			else
			{
				if (variables.contains(varName))
				{
					const double val = variables[varName];
					Stack->prepend(val);
				}
				else
				{
					changeStatusError(i18n("Undefined variable %1").arg(varName));
					return false;
				}

				break;
			}
		}
		else if (removeStartsWith(operateOn, "reqargs"))
		{
			if (Stack->count() < 1)
				return false;
			double first = Stack->first();
			Stack->pop_front();
			if (!parseArgs(first))
				return false;
		}
		else if (removeStartsWith(operateOn, "stopif"))
		{
			if (Stack->count() <= 0)
				return false;
			
			double first = Stack->first();
			Stack->pop_front();

			if (first == 1)
				return false;
		}
		else if (removeStartsWith(operateOn, "+")) slotAdd();
		else if (removeStartsWith(operateOn, "-")) slotSubtract();
		else if (removeStartsWith(operateOn, "*")) slotMultiply();
		else if (removeStartsWith(operateOn, "/")) slotDivide();
		else if (removeStartsWith(operateOn, "mod")) slotModulo();
		else if (removeStartsWith(operateOn, "inverse")) slotInverse();
		else if (removeStartsWith(operateOn, "e^")) slotRaiseE();
		else if (removeStartsWith(operateOn, "sqrt")) slotSqrt();
		else if (removeStartsWith(operateOn, "^2")) slotSquared();
		else if (removeStartsWith(operateOn, "sin")) slotSine();
		else if (removeStartsWith(operateOn, "cos")) slotCosine();
		else if (removeStartsWith(operateOn, "tan")) slotTangent();
		else if (removeStartsWith(operateOn, "10^")) slotRaiseTen();
		else if (removeStartsWith(operateOn, "ln")) slotLn();
		else if (removeStartsWith(operateOn, "!")) slotFactorial();
		else if (removeStartsWith(operateOn, "^")) slotPower();
		else if (removeStartsWith(operateOn, "and")) slotAnd();
		else if (removeStartsWith(operateOn, "xor")) slotXOr();
		else if (removeStartsWith(operateOn, "or")) slotOr();
		else if (removeStartsWith(operateOn, "lsh") || removeStartsWith(operateOn, "<<")) slotLsh();
		else if (removeStartsWith(operateOn, "rsh") || removeStartsWith(operateOn, ">>")) slotRsh();
		else if (removeStartsWith(operateOn, "at"))
		{
			if (Stack->count() < 1)
				return false;

			double index = Stack->first();
			Stack->pop_front();

			if (index < 0 || index > Stack->count() - 1)
				return false;

			Stack->prepend(*Stack->at(index));
		}
		else if (removeStartsWith(operateOn, "level"))
		{
			if (Stack->count() < 1)
				return false;

			double index = Stack->first() - 1;
			Stack->pop_front();

			if (index < 0 || index > Stack->count() - 1)
				return false;

			Stack->prepend(*Stack->at(index));
		}
		else if (removeStartsWith(operateOn, "curbase"))
			Stack->prepend((double)base);
		else if (removeStartsWith(operateOn, "curangle"))
			Stack->prepend((double)angle);
		else if (removeStartsWith(operateOn, "curangle"))
			Stack->prepend((double)(HypButton->isChecked()? 1 : 0));
		else if (removeStartsWith(operateOn, "clear")) Stack->clear();
		else if (removeStartsWith(operateOn, "drop")) Stack->pop_front();
		else if (removeStartsWith(operateOn, "swap")) roll(2);
		else if (removeStartsWith(operateOn, "rolld"))
		{
			if (Stack->count() < 1)
				return false;

			double first = Stack->first();
			Stack->pop_front();
			rolld(first);
		}
		else if (removeStartsWith(operateOn, "roll"))
		{
			if (Stack->count() < 1)
				return false;

			double first = Stack->first();
			Stack->pop_front();
			roll(first);
		}
		else if (removeStartsWith(operateOn, "setbase"))
		{
			if (Stack->count() <= 0)
				return false;

			base = (int)Stack->first();
			switch (base)
			{
				case 16:
					baseGroup->setCurrentItem(0);
					slotBaseChanged(0);
					break;

				case 10:
					baseGroup->setCurrentItem(1);
					slotBaseChanged(1);
					break;

				case 8:
					baseGroup->setCurrentItem(2);
					slotBaseChanged(2);
					break;

				case 2:
					baseGroup->setCurrentItem(3);
					slotBaseChanged(3);
					break;
			}

			Stack->pop_front();
		}
		else if (removeStartsWith(operateOn, "setangle"))
		{
			if (Stack->count() <= 0)
				return false;

			angle = (int)Stack->first();
			angGroup->setCurrentItem(angle);
			
			Stack->pop_front();
		}
		else if (removeStartsWith(operateOn, "sethyp"))
		{
			if (Stack->count() <= 0)
				return false;

			HypButton->setChecked(Stack->first() == 1);

			Stack->pop_front();
		}
		else if (removeStartsWith(operateOn, "dup2"))
			slotDup2();
		else if (removeStartsWith(operateOn, "dup"))
		{
			if (Stack->count() > 0)
				Stack->prepend(Stack->first());
		}
		else
		{
			bool found = false;
			// go through commands
			for (TQMap<TQString, TQString>::Iterator it = formulas.begin(); it != formulas.end() && !found; ++it)
			{
				TQString name = it.key();
				if (removeStartsWith(operateOn, name))
				{
					runFormula(name);
					found = true;
				}
			}

			if (!found)
			{
				changeStatusError(i18n("Unknown command %1").arg(operateOn));
				return false;
			}
		}
	}

	return true;
}

void Mathemagics::keyBindings()
{
	KKeyDialog::configure(actionCollection());
}

void Mathemagics::configureToolBars()
{
	saveMainWindowSettings(TDEGlobal::config(), "TopLevelWindow");

	KEditToolbar dlg(actionCollection());
	connect(&dlg, TQ_SIGNAL(newToolbarConfig()), TQ_SLOT(newToolBarConfig()));

	if (dlg.exec())
		createGUI();
}

void Mathemagics::newToolBarConfig()
{
	applyMainWindowSettings(TDEGlobal::config(), "TopLevelWindow");
}

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

EditAction::EditAction(const TQString& text, int accel, const TQObject *receiver, const char *member, TQObject* parent, const char* name)
	: TDEAction(text, accel, parent, name)
{
	m_receiver = receiver;
	m_member = member;
}

EditAction::~EditAction()
{
}

int EditAction::plug(TQWidget *w, int index)
{
	TDEToolBar *toolBar = (TDEToolBar *)w;
	int id = TDEAction::getToolButtonID();

	KParanoidLine *comboBox = new KParanoidLine(toolBar, "search edit");
	toolBar->insertWidget(id, 70, comboBox, index);
	if (m_receiver)
		connect(comboBox, TQ_SIGNAL(returnPressed()), m_receiver, m_member);

	addContainer(toolBar, id);
	connect(toolBar, TQ_SIGNAL(destroyed()), this, TQ_SLOT(slotDestroyed()));
	toolBar->setItemAutoSized(id, true);
	m_combo = comboBox;
	emit plugged();
	return containerCount() - 1;
}

void EditAction::unplug(TQWidget *w)
{
	TDEToolBar *toolBar = (TDEToolBar *)w;
	int idx = findContainer(w);
	toolBar->removeItem(menuId(idx));
	removeContainer(idx);
	m_combo = 0L;
}

void EditAction::clear()
{
	m_combo->clear();
}

void EditAction::append(TQString text)
{
	m_combo->setText(this->text() + text);
}

void EditAction::insert(TQString text)
{
	m_combo->insert(text);
}

TQGuardedPtr<KParanoidLine> EditAction::edit()
{
	return m_combo;
}

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

ComboAction::ComboAction(const TQString& text, int accel, const TQObject *receiver, const char *member, TQObject* parent, const char* name)
	: TDEAction(text, accel, parent, name)
{
	m_receiver = receiver;
	m_member = member;
}

ComboAction::~ComboAction()
{
}

int ComboAction::plug(TQWidget *w, int index)
{
	TDEToolBar *toolBar = (TDEToolBar *)w;

	int id = TDEAction::getToolButtonID();

	TQComboBox *comboBox = new TQComboBox(toolBar, "search edit");
	toolBar->insertWidget(id, 70, comboBox, index);
	if (m_receiver)
		connect(comboBox, TQ_SIGNAL(returnPressed()), m_receiver, m_member);

	addContainer(toolBar, id);
	connect(toolBar, TQ_SIGNAL(destroyed()), this, TQ_SLOT(slotDestroyed()));
	toolBar->setItemAutoSized(id, true);
	m_combo = comboBox;
	emit plugged();
	return containerCount() - 1;
}

void ComboAction::unplug(TQWidget *w)
{
	TDEToolBar *toolBar = (TDEToolBar *)w;
	int idx = findContainer(w);
	toolBar->removeItem(menuId(idx));

	removeContainer(idx);
	m_combo = 0L;
}

TQGuardedPtr<TQComboBox> ComboAction::combo()
{
	return m_combo;
}

#include "mathemagics.moc"
