/* This file is part of the KDE project
   Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#include "kexisharedactionhost.h"
#include "kexisharedactionhost_p.h"
#include "kexiactionproxy.h"
#include "kexidialogbase.h"

#include <kexiutils/utils.h>

#include <kiconloader.h>
#include <kguiitem.h>
#include <kdebug.h>

KexiSharedActionHostPrivate::KexiSharedActionHostPrivate(KexiSharedActionHost *h)
: TQObject(0,"KexiSharedActionHostPrivate")
, actionProxies(401)
, actionMapper( this )
, volatileActions(401)
, enablers(401, false)
, host(h)
{
	volatileActions.setAutoDelete(true);
	connect(&actionMapper, TQT_SIGNAL(mapped(const TQString &)), this, TQT_SLOT(slotAction(const TQString &)));
}

void KexiSharedActionHostPrivate::slotAction(const TQString& act_id)
{
	TQWidget *w = host->focusWindow(); //focusWidget();
//	while (w && !w->inherits("KexiDialogBase") && !w->inherits("KexiDockBase"))
//		w = w->parentWidget();

	KexiActionProxy *proxy = w ? actionProxies[ w ] : 0;

	if (!proxy || !proxy->activateSharedAction(act_id.latin1())) {
		//also try to find previous enabler
		w = enablers[act_id.latin1()];
		if (!w)
			return;
		proxy = actionProxies[ w ];
		if (!proxy)
			return;
		proxy->activateSharedAction(act_id.latin1());
	}
}

//--------------------------------------------------

//! dummy host to avoid crashes
KexiSharedActionHost KexiSharedActionHost_dummy = KexiSharedActionHost(0);

//! default host
KexiSharedActionHost* KexiSharedActionHost_defaultHost = &KexiSharedActionHost_dummy;

KexiSharedActionHost& KexiSharedActionHost::defaultHost()
{
	return *KexiSharedActionHost_defaultHost;
}

void KexiSharedActionHost::setAsDefaultHost()
{
	KexiSharedActionHost_defaultHost = this;
}

//--------------------------------------------------

KexiSharedActionHost::KexiSharedActionHost(TDEMainWindow* mainWin)
: d( new KexiSharedActionHostPrivate(this) )
{
	d->mainWin = mainWin;
}

KexiSharedActionHost::~KexiSharedActionHost()
{
	if (KexiSharedActionHost_defaultHost == this) {
		//default host is destroyed! - restore dummy
		KexiSharedActionHost_defaultHost = &KexiSharedActionHost_dummy;
	}
	delete d;
	d=0; //! to let takeActionProxyFor() know that we are almost dead :)
}

void KexiSharedActionHost::setActionAvailable(const char *action_name, bool avail)
{
	TDEAction *act = d->mainWin->actionCollection()->action(action_name);
	if (act) {
		act->setEnabled(avail);
	}
}

void KexiSharedActionHost::updateActionAvailable(const char *action_name, bool avail, TQObject *obj)
{
/*test	if (qstrcmp(action_name, "tablepart_toggle_pkey")==0) {
		kdDebug() << "tablepart_toggle_pkey" << endl;
	}*/
	if (!d)
		return; //sanity
	TQWidget *fw = d->mainWin->focusWidget();
	while (fw && TQT_BASE_OBJECT(obj)!=TQT_BASE_OBJECT(fw))
		fw = fw->parentWidget();
	if (!fw)
		return;

	setActionAvailable(action_name, avail);
	if (avail) {
		d->enablers.replace(action_name, fw);
	}
	else {
		d->enablers.take(action_name);
	}
}

void KexiSharedActionHost::plugActionProxy(KexiActionProxy *proxy)
{
//	kdDebug() << "KexiSharedActionHost::plugActionProxy():" << proxy->receiver()->name() << endl;
	d->actionProxies.insert( proxy->receiver(), proxy );
}

TDEMainWindow* KexiSharedActionHost::mainWindow() const
{
	return d->mainWin;
}

void KexiSharedActionHost::invalidateSharedActions(TQObject *o)
{
	if (!d)
		return;
	bool insideDialogBase = o && (o->inherits("KexiDialogBase") || 0!=KexiUtils::findParent<KexiDialogBase>(o, "KexiDialogBase"));

	KexiActionProxy *p = o ? d->actionProxies[ o ] : 0;
	for (TDEActionPtrList::ConstIterator it=d->sharedActions.constBegin(); it!=d->sharedActions.constEnd(); ++it) {
//			setActionAvailable((*it)->name(),p && p->isAvailable((*it)->name()));
		TDEAction *a = *it;
		if (!insideDialogBase && d->mainWin->actionCollection()!=a->parentCollection()) {
			//o is not KexiDialogBase or its child:
			// only invalidate action if it comes from mainwindow's TDEActionCollection
			// (thus part-actions are untouched when the focus is e.g. in the Property Editor)
			continue;
		}
		const bool avail = p && p->isAvailable(a->name());
		KexiVolatileActionData *va = d->volatileActions[ a ];
		if (va != 0) {
			if (p && p->isSupported(a->name())) {
				TQPtrList<TDEAction> actions_list;
				actions_list.append( a );
				if (!va->plugged) {
					va->plugged=true;
	//				d->mainWin->unplugActionList( a->name() );
					d->mainWin->plugActionList( a->name(), actions_list );
				}
			}
			else {
				if (va->plugged) {
					va->plugged=false;
					d->mainWin->unplugActionList( a->name() );
				}
			}
		}
//		a->setEnabled(p && p->isAvailable(a->name()));
		a->setEnabled(avail);
//		kdDebug() << "Action " << a->name() << (avail ? " enabled." : " disabled.") << endl;
	}
}

KexiActionProxy* KexiSharedActionHost::actionProxyFor(TQObject *o) const
{
	return d->actionProxies[ o ];
}

KexiActionProxy* KexiSharedActionHost::takeActionProxyFor(TQObject *o)
{
	if (d)
		return d->actionProxies.take( o );
	return 0;
}

bool KexiSharedActionHost::acceptsSharedActions(TQObject *)
{
	return false;
}

TQWidget* KexiSharedActionHost::focusWindow()
{
	TQWidget *fw;
	if (dynamic_cast<KMdiMainFrm*>(d->mainWin)) {
		fw = dynamic_cast<KMdiMainFrm*>(d->mainWin)->activeWindow();
	}
	else {
		TQWidget *aw = TQT_TQWIDGET(tqApp->activeWindow());
		if (!aw)
			aw = d->mainWin;
		fw = aw->focusWidget();
	}
	while (fw && !acceptsSharedActions(TQT_TQOBJECT(fw)))
		fw = fw->parentWidget();
	return fw;
}

TDEAction* KexiSharedActionHost::createSharedActionInternal( TDEAction *action )
{
	TQObject::connect(action,TQT_SIGNAL(activated()), &d->actionMapper, TQT_SLOT(map()));
	d->actionMapper.setMapping(action, action->name());
	d->sharedActions.append( action );
	return action;
}

TDEActionPtrList KexiSharedActionHost::sharedActions() const
{
	return d->sharedActions;
}

/*class KexiAction : public TDEAction
{
	public:
		KexiAction(const TQString &text, const TQIconSet &pix,
			const TDEShortcut &cut, const TQObject *receiver,
			const char *slot, TDEActionCollection *parent, const char *name)
		 : TDEAction(text,pix,cut,receiver,slot,parent,name)
		{
		}

	TQPtrDict<TQWidget> unplugged;
};*/

TDEAction* KexiSharedActionHost::createSharedAction(const TQString &text, const TQString &pix_name,
	const TDEShortcut &cut, const char *name, TDEActionCollection* col, const char *subclassName)
{
	if (subclassName==0)
		return createSharedActionInternal(
			new TDEAction(text, pix_name,
			cut, 0/*receiver*/, 0/*slot*/, col ? col : d->mainWin->actionCollection(), name)
		);
	else if (tqstricmp(subclassName,"TDEToggleAction")==0)
		return createSharedActionInternal(
			new TDEToggleAction(text, pix_name,
			cut, 0/*receiver*/, 0/*slot*/, col ? col : d->mainWin->actionCollection(), name)
		);
	else if (tqstricmp(subclassName,"TDEActionMenu")==0)
		return createSharedActionInternal(
			new TDEActionMenu(text, pix_name, col ? col : d->mainWin->actionCollection(), name)
		);
//TODO: more TDEAction subclasses

	return 0;
}

TDEAction* KexiSharedActionHost::createSharedAction( KStdAction::StdAction id, const char *name,
	TDEActionCollection* col)
{
	return createSharedActionInternal(
		KStdAction::create( id, name, 0/*receiver*/, 0/*slot*/, col ? col : d->mainWin->actionCollection() )
	);
}

TDEAction* KexiSharedActionHost::createSharedAction(const KGuiItem& guiItem, const TDEShortcut &cut, 
	const char *name, TDEActionCollection* col)
{
	return createSharedActionInternal(
		new TDEAction(guiItem, cut, 0/*receiver*/, 0/*slot*/, 
			col ? col : d->mainWin->actionCollection(), name));
}

void KexiSharedActionHost::setActionVolatile( TDEAction *a, bool set )
{
	if (!set) {
		d->volatileActions.remove( a );
		return;
	}
	if (d->volatileActions[ a ])
		return;
	d->volatileActions.insert( a, new KexiVolatileActionData() );
}

#include "kexisharedactionhost_p.moc"

