//=============================================================================
//
//   File : kvi_window.cpp
//   Creation date : Tue Jul 6 1999 14:52:11 by Szymon Stefanek
//
//   This file is part of the KVirc irc client distribution
//   Copyright (C) 1999-2007 Szymon Stefanek (pragma at kvirc dot net)
//
//   This program 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
//   of the License, or (at your opinion) any later version.
//
//   This program 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 General Public License for more details.
//
//   You should have received a copy of the GNU General Public License
//   along with this program. If not, write to the Free Software Foundation,
//   Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
//=============================================================================

#define __KVIRC__
#define KVI_WINDOW_MIN_WIDTH 100
#define KVI_WINDOW_MIN_HEIGHT 100

#define _KVI_WINDOW_CPP_

#define _KVI_DEBUG_CHECK_RANGE_

#include "kvi_debug.h"
#include "kvi_app.h"
#include "kvi_window.h"
#include "kvi_frame.h"
#include "kvi_taskbar.h"
#include "kvi_iconmanager.h"
#include "kvi_mdichild.h"
#include "kvi_locale.h"
#include "kvi_ircview.h"
#include "kvi_out.h"
#include "kvi_malloc.h"
#include "kvi_input.h"
#include "kvi_fileutils.h"
#include "kvi_options.h"
#include "kvi_config.h"
#include "kvi_irccontext.h"
#include "kvi_console.h"
#include "kvi_ircconnectionserverinfo.h"
#include "kvi_mirccntrl.h"
#include "kvi_toolwindows_container.h"
#include "kvi_styled_controls.h"
#include "kvi_kvs_script.h"

#include <tqpixmap.h>
#include "kvi_tal_popupmenu.h"
#include <tqcursor.h>
#include <tqtimer.h>
#include <tqsplitter.h>
#include <tqmetaobject.h>
#include <tqdatetime.h>
#include <tqtextcodec.h>
#include <tqevent.h>

// it looks they can't decide :D
        #include <tqobjectlist.h>


#include <tqvariant.h>
#include <tqtoolbutton.h>
#include "kvi_tal_tooltip.h"
#include <tqmessagebox.h>

#ifdef COMPILE_CRYPT_SUPPORT
	#include "kvi_crypt.h"
	#include "kvi_cryptcontroller.h"
#endif

#ifdef COMPILE_TDE_SUPPORT
	#include <twin.h>
#endif

#ifdef COMPILE_ON_WINDOWS
	#include <windows.h>
#endif

KVIRC_API KviWindow * g_pActiveWindow = 0;

static KviTalPopupMenu * g_pMdiWindowSystemMainPopup = 0;
static KviTalPopupMenu * g_pMdiWindowSystemTextEncodingPopup = 0;
static KviTalPopupMenu * g_pMdiWindowSystemTextEncodingPopupStandard = 0;
static KviTalPopupMenu * g_pMdiWindowSystemTextEncodingPopupSmart = 0;
static KviTalPopupMenu * g_pMdiWindowSystemTextEncodingPopupSmartUtf8 = 0;

unsigned long int g_uUniqueWindowId = 1;

// FIXME: #warning "Mouse wheel support"
KviWindow::KviWindow(int type,KviFrame * lpFrm,const TQString &name,KviConsole * lpConsole)
		: TQWidget(0)
{
	m_uId = g_uUniqueWindowId;
	g_uUniqueWindowId++;

	m_szName = name;

	g_pApp->registerWindow(this);

	m_iType                 = type;
	m_pFocusHandler         = 0;

	m_pFrm = lpFrm; // FIXME: Should disappear!
	m_pIrcView              = 0;
	m_pInput                = 0;
	m_pSplitter             = 0;
	m_pButtonBox            = 0;
	m_pConsole              = lpConsole;
	m_pContext              = lpConsole ? lpConsole->context() : 0;
	m_pLastFocusedChild     = 0;
	m_pTextCodec            = 0; // will be set by loadProperties
	m_pTextEncodingButton   = 0;
	m_pHideToolsButton	= 0;
//	m_pEditorsContainer     = 0;

#ifdef COMPILE_CRYPT_SUPPORT

	m_pCryptControllerButton = 0;
	m_pCryptController = 0;
	m_pCryptSessionInfo = 0;
#endif

	m_pAccel = 0;

	m_pTaskBarItem = 0;

	setMinimumSize(KVI_WINDOW_MIN_WIDTH,KVI_WINDOW_MIN_HEIGHT);
	setBackgroundMode(NoBackground);
	setFocusPolicy(TQWidget::StrongFocus);
	
	connect(g_pApp,TQ_SIGNAL(reloadImages()),this,TQ_SLOT(reloadImages()));
}

KviWindow::~KviWindow()
{
	//g_pFrame->childWindowDestroyed(this);
	destroyTaskBarItem();
	g_pApp->unregisterWindow(this);
	if(g_pApp->windowCount() == 0)
	{
		// this is the last window!
		if(g_pMdiWindowSystemMainPopup)
			delete g_pMdiWindowSystemMainPopup;
		if(g_pMdiWindowSystemTextEncodingPopup)
			delete g_pMdiWindowSystemTextEncodingPopup;
		if(g_pMdiWindowSystemTextEncodingPopupStandard)
			delete g_pMdiWindowSystemTextEncodingPopupStandard;
		if(g_pMdiWindowSystemTextEncodingPopupSmart)
			delete g_pMdiWindowSystemTextEncodingPopupSmart;
		if(g_pMdiWindowSystemTextEncodingPopupSmartUtf8)
			delete g_pMdiWindowSystemTextEncodingPopupSmartUtf8;
	}
#ifdef COMPILE_CRYPT_SUPPORT
	if(m_pCryptSessionInfo)
		KviCryptController::destroyCryptSessionInfo(&m_pCryptSessionInfo);
#endif
}

void KviWindow::setWindowName(const TQString &szName)
{
	m_szName = szName;
	emit windowNameChanged();
}

void KviWindow::toggleButtonContainer()
{
	TQFrame *pContainer=buttonContainer();
	if(pContainer)
	{
		pContainer->setHidden(!pContainer->isHidden());
	}
}

void KviWindow::setName(const TQString &name)
{
	m_szName = name;
	TQWidget::setName(name.utf8().data());
}

KviIrcConnection * KviWindow::connection()
{
	return m_pContext ? m_pContext->connection() : 0;
}

void KviWindow::reloadImages()
{
	updateIcon();
}

bool KviWindow::hasAttention()
{
	if(((TQApplication *)g_pApp)->activeWindow() == 0)return false; // no application window has the focus atm

	if(mdiParent())
	{
		if(frame()->isActiveWindow())return true;
		// This frame is not the active window but the
		// active window still belongs to KVIrc.
		// When the active window is derived from TQDialog
		// then it is probably a KVIrc's option dialog
		// or something similar.
		// In this case we assume that the user has the
		// KVIrc window just below and can see it.

		// Handle the special case of the dialogs then
		TQWidget * w = ((TQApplication *)g_pApp)->activeWindow();
		if(w->inherits("TQDialog"))
		{
			// but make sure that the frame is visible at all!
			if(!frame()->isVisible())return false;
			return true;
		}
		// any other class is so unfrequent that we ignore it
	} else {
		// when the window is undocked, instead
		// it is likely to be covered by KVIrc or other windows...
		if(isActiveWindow())return true;
	}
	return false;
}

void KviWindow::demandAttention()
{
	if(mdiParent())
	{
		if(frame()->isActiveWindow())return;
#ifdef COMPILE_ON_WINDOWS
		FLASHWINFO fwi;
		fwi.cbSize = sizeof(fwi);
		fwi.hwnd = (HWND)(frame()->winId());
		fwi.dwFlags = FLASHW_TRAY | FLASHW_TIMERNOFG;
		fwi.uCount = 20;
		fwi.dwTimeout = 500;
		FlashWindowEx(&fwi);
#else
	#ifdef COMPILE_TDE_SUPPORT
		KWin::demandAttention(frame()->winId(),true);
	#endif
#endif
	} else {
		if(isActiveWindow())return;
#ifdef COMPILE_ON_WINDOWS
		FLASHWINFO fwi;
		fwi.cbSize = sizeof(fwi);
		fwi.hwnd = (HWND)winId();
		fwi.dwFlags = FLASHW_TRAY | FLASHW_TIMERNOFG;
		fwi.uCount = 20;
		fwi.dwTimeout = 500;
		FlashWindowEx(&fwi);
#else
	#ifdef COMPILE_TDE_SUPPORT
		KWin::demandAttention(winId(),true);
	#endif
#endif
	}
}

bool KviWindow::focusNextPrevChild(bool next)
{
	TQWidget * w = focusWidget();
	if(w)
	{
		if(w->focusPolicy() == TQWidget::StrongFocus)return false;
		//TQVariant v = w->property("KviProperty_FocusOwner");
		//if(v.isValid())return false; // Do NOT change the focus widget!
		
		if(w->parent())
		{
			if(w->parent()->metaObject()->findProperty("KviProperty_ChildFocusOwner") == -1)
				return false; // Do NOT change the focus widget!
		}
	}

	return TQWidget::focusNextPrevChild(next);
}

void KviWindow::forceTextCodec(TQTextCodec * c)
{
	if(!c)return;
	m_pTextCodec = c;
	TQTextCodec * dc = defaultTextCodec();
	if(dc != c)
		m_szTextEncoding = c->name();
	else
		m_szTextEncoding = ""; // this is the default anyway
}

bool KviWindow::setTextEncoding(const TQString &szTextEncoding)
{
	if(!szTextEncoding.isEmpty())
	{
		m_pTextCodec = KviLocale::codecForName(szTextEncoding.latin1());
		if(m_pTextCodec)
		{
			m_szTextEncoding = szTextEncoding;
			return true;
		}
		// this is an error because we specified an encoding
		// and we couldn't find a codec for this
	} // else it is empty : this means : guess from locale
	// either empty or not found...
	m_pTextCodec = 0;
	m_szTextEncoding = ""; // empty: we're using the default
	return false;
}

TQTextCodec * KviWindow::defaultTextCodec()
{
	// if we have a connection try to inherit from there...
	if(connection())
	{
		TQTextCodec * c = connection()->textCodec();
		if(c)return c;
	}
	return KviApp::defaultTextCodec();
}

KviTQCString KviWindow::encodeText(const TQString &szText)
{
	if(!m_pTextCodec)return defaultTextCodec()->fromUnicode(szText);
	return m_pTextCodec->fromUnicode(szText);
}

TQString KviWindow::decodeText(const char * szText)
{
	if(!m_pTextCodec)return defaultTextCodec()->toUnicode(szText);
	return m_pTextCodec->toUnicode(szText);
}

bool KviWindow::activityMeter(unsigned int *,unsigned int *)
{
	return false;
}


const char * KviWindow::m_typeTable[KVI_WINDOW_NUM_TYPES + 1]=
{
	"console",
	"channel",
	"query",
	"help",
	"terminal",
	"editor",
	"dccchat",
	"dccsend",
	"socketspy",
	"links",
	"tool",
	"gnutella",
	"dirbrowser",
	"dcccanvas",
	"dccvoice",
	"list",
	"offer",
	"logview",
	"deadchannel",
	"deadquery",
	"scripteditor",
	"scriptobject",
	"userwindow",
	"debug",
	// <------ NEW TYPES GO HERE!
	"unknown"
};

const char * KviWindow::typeString()
{
	if(m_iType < KVI_WINDOW_NUM_TYPES)
	{
		return m_typeTable[m_iType];
	}
	return m_typeTable[KVI_WINDOW_NUM_TYPES];
}

void KviWindow::setType(int iType)
{
	m_iType = iType;
}


void KviWindow::createTaskBarItem()
{
	if(m_pTaskBarItem)return;
	m_pTaskBarItem = g_pFrame->m_pTaskBar->addItem(this);
}

void KviWindow::destroyTaskBarItem()
{
	if(!m_pTaskBarItem)return;
	g_pFrame->m_pTaskBar->removeItem(m_pTaskBarItem);
	//	m_pTaskBarItem = 0; // actually the taskBarItem destructor sets it
}

BUTTON_CLASS * KviWindow::createToolButton(TQWidget * par,const char * nam,int pixon,int pixoff,const TQString & tooltip,bool bOn)
{
	BUTTON_CLASS * b = new BUTTON_CLASS(par,nam);
	b->setToggleButton(true);
	b->setUsesBigPixmap(false);
	TQIconSet is1;
	is1.setPixmap(*(g_pIconManager->getSmallIcon(pixon)),TQIconSet::Small,TQIconSet::Normal,TQIconSet::On);
	is1.setPixmap(*(g_pIconManager->getSmallIcon(pixoff)),TQIconSet::Small,TQIconSet::Normal,TQIconSet::Off);
	b->setIconSet(is1);


	KviTalToolTip::add
		(b,tooltip);
	b->setOn(bOn);
	return b;
}

// This is always defined...
void KviWindow::createCryptControllerButton(TQWidget * par)
{
#ifdef COMPILE_CRYPT_SUPPORT
	m_pCryptControllerButton = new KviWindowToolPageButton(KVI_SMALLICON_UNLOCKEDOFF,KVI_SMALLICON_UNLOCKED,__tr2qs("Crypting"),buttonContainer(),false,"crypt_controller_button");
	connect(m_pCryptControllerButton,TQ_SIGNAL(clicked()),this,TQ_SLOT(toggleCryptController()));
#endif // COMPILE_CRYPT_SUPPORT
}

void KviWindow::createTextEncodingButton(TQWidget * par)
{
	if(m_pTextEncodingButton)delete m_pTextEncodingButton;
	m_pTextEncodingButton = createToolButton(par,"text_encoding_button",KVI_SMALLICON_TEXTENCODING,KVI_SMALLICON_TEXTENCODING,__tr2qs("Private Text Encoding"),false);
	connect(m_pTextEncodingButton,TQ_SIGNAL(clicked()),this,TQ_SLOT(textEncodingButtonClicked()));
}

void KviWindow::textEncodingButtonClicked()
{
	createSystemTextEncodingPopup();
	g_pMdiWindowSystemTextEncodingPopup->popup(m_pTextEncodingButton->mapToGlobal(TQPoint(0,m_pTextEncodingButton->height())));
	m_pTextEncodingButton->setOn(false);
}

const TQString & KviWindow::lastLineOfText()
{
	if(m_pIrcView)
		return m_pIrcView->lastLineOfText();
	return KviTQString::empty;
}

const TQString & KviWindow::lastMessageText()
{
	if(m_pIrcView)
		return m_pIrcView->lastMessageText();
	return KviTQString::empty;
}

// The following three have to be here even if the crypt support is disabled...moc does not support conditional compilations
void KviWindow::toggleCryptController()
{
#ifdef COMPILE_CRYPT_SUPPORT
	if(!m_pCryptControllerButton->isOn())
	{
		if(m_pCryptController)
		{
			delete m_pCryptController;
			m_pCryptController = 0;
			if(!m_pCryptControllerButton)
				return;
			if(m_pCryptControllerButton->isOn())
				m_pCryptControllerButton->setOn(false);
		}
	} else {
		if(m_pSplitter && m_pInput)
		{
			m_pCryptController = new KviCryptController(m_pSplitter,m_pCryptControllerButton,"crypt_controller",this,m_pCryptSessionInfo);
			connect(m_pCryptController,TQ_SIGNAL(done()),this,TQ_SLOT(cryptControllerFinished()));
			//setFocusHandlerNoClass(m_pInput,m_pCryptController,"TQLineEdit"); //link it!
			m_pCryptController->show();
			if(!m_pCryptControllerButton)
				return;
			if(!(m_pCryptControllerButton->isOn()))
				m_pCryptControllerButton->setOn(true);
		}
	}
#endif // COMPILE_CRYPT_SUPPORT
}

#ifdef COMPILE_CRYPT_SUPPORT
void KviWindow::setCryptSessionInfo(KviCryptSessionInfo * inf)
{
	if(m_pCryptSessionInfo)
		KviCryptController::destroyCryptSessionInfo(&m_pCryptSessionInfo);
	m_pCryptSessionInfo = inf;
	if(m_pCryptSessionInfo)
	{
		connect(m_pCryptSessionInfo->pEngine,TQ_SIGNAL(destroyed()),this,TQ_SLOT(cryptSessionInfoDestroyed()));
	}
	if(m_pCryptControllerButton)
	{
		TQIconSet is;
		is.setPixmap(*(g_pIconManager->getSmallIcon(m_pCryptSessionInfo ? KVI_SMALLICON_LOCKEDOFF : KVI_SMALLICON_UNLOCKEDOFF)),TQIconSet::Small,TQIconSet::Normal,TQIconSet::Off);
		is.setPixmap(*(g_pIconManager->getSmallIcon(m_pCryptSessionInfo ? KVI_SMALLICON_LOCKED : KVI_SMALLICON_UNLOCKED)),TQIconSet::Small,TQIconSet::Normal,TQIconSet::On);
		m_pCryptControllerButton->setIconSet(is);

		if(m_pCryptControllerButton->isOn())
			m_pCryptControllerButton->setOn(false);
	}
}
#endif // COMPILE_CRYPT_SUPPORT

void KviWindow::cryptControllerFinished()
{
#ifdef COMPILE_CRYPT_SUPPORT
	KviCryptSessionInfo * inf = m_pCryptController->getNewSessionInfo();
	setCryptSessionInfo(inf);
	delete m_pCryptController;
	m_pCryptController = 0;
#endif
}

void KviWindow::cryptSessionInfoDestroyed()
{
#ifdef COMPILE_CRYPT_SUPPORT
	output(KVI_OUT_SYSTEMERROR,__tr2qs("Ops...I've accidentally lost the crypting engine..."));
	m_pCryptSessionInfo->pEngine = 0;
	delete m_pCryptSessionInfo;
	m_pCryptSessionInfo = 0;
#endif
}



void KviWindow::setProgress(int progress)
{
	m_pTaskBarItem->setProgress(progress);
}

void KviWindow::listWindowTypes()
{
	outputNoFmt(KVI_OUT_SYSTEMMESSAGE,__tr2qs("List of window types available in this release of KVIrc:"));
	for(int i=0;i< KVI_WINDOW_NUM_TYPES;i++)
		outputNoFmt(KVI_OUT_SYSTEMMESSAGE,m_typeTable[i]);
}

void KviWindow::getConfigGroupName(TQString &buf)
{
	buf = typeString();
}


void KviWindow::getDefaultLogFileName(TQString &buffer)
{
	// FIXME: #warning "Make it configurable ?"
	TQString date;
	TQDate dt(TQDate::currentDate());
	date=dt.toString("yyyy.MM.dd");
	TQString base;
	getBaseLogFileName(base);
	kvi_encodeFileName(base);
	base.replace("%%2e","%2e");
	base=base.lower();
	TQString tmp;
	if(KVI_OPTION_BOOL(KviOption_boolGzipLogs))
		KviTQString::sprintf(tmp,"%s_%s_%s.log.gz",typeString(),base.utf8().data(),date.utf8().data());
	else
		KviTQString::sprintf(tmp,"%s_%s_%s.log",typeString(),base.utf8().data(),date.utf8().data());
	g_pApp->getLocalKvircDirectory(buffer,KviApp::Log,tmp);
}

/*void KviWindow::getBaseLogFileName(KviStr &buffer)
{
	buffer = m_szName;
}*/

void KviWindow::getBaseLogFileName(TQString &buffer)
{
	buffer = m_szName;
}


void KviWindow::saveProperties(KviConfig *cfg)
{
	// store only the non-default text encoding.
	TQString szCodec = m_szTextEncoding;
	TQTextCodec * c = defaultTextCodec();
	if(c && m_pTextCodec)
	{
		if(KviTQString::equalCI(szCodec,c->name()))szCodec = KviTQString::empty; // store "default"
	}
	TQString szKey = "TextEncoding_";
	szKey += m_szName;
	cfg->writeEntry(szKey,szCodec);
	if(m_pInput) {
		cfg->writeEntry("inputToolButtonsHidden",m_pInput->isButtonsHidden());
		cfg->writeEntry("commandLineIsUserFriendly",m_pInput->isUserFriendly());
	}

	//
	
		/*if(m_pIrcView && m_iType==KVI_WINDOW_TYPE_CHANNEL)
		if(m_pIrcView->isLogging())
			cfg->writeEntry("LoggingEnabled",m_pIrcView->isLogging());*/
}

void KviWindow::loadProperties(KviConfig *cfg)
{
	TQString szKey = "TextEncoding_";
	szKey += m_szName;
	setTextEncoding(cfg->readTQStringEntry(szKey,KviTQString::empty).utf8().data());
	if(m_pInput) {
		m_pInput->setButtonsHidden(cfg->readBoolEntry("inputToolButtonsHidden",KVI_OPTION_BOOL(KviOption_boolHideInputToolButtons)));
		m_pInput->setUserFriendly(cfg->readBoolEntry("commandLineIsUserFriendly",KVI_OPTION_BOOL(KviOption_boolCommandlineInUserFriendlyModeByDefault)));
	}
/*	if(m_pIrcView && m_iType==KVI_WINDOW_TYPE_CHANNEL)
	{
		bool bEnableLogs=cfg->readBoolEntry("LoggingEnabled",0);
		if(!m_pIrcView->isLogging() && bEnableLogs)
		{
			TQString szTmp;
			getBaseLogFileName(szTmp);
			m_pIrcView->startLogging();
		}
	}*/
}

TQPixmap * KviWindow::myIconPtr()
{
	return g_pIconManager->getSmallIcon(KVI_SMALLICON_DEFAULTICON);
}

void KviWindow::getTaskBarTipText(TQString &buffer)
{
	buffer = m_szPlainTextCaption;
}

void KviWindow::setFixedCaption(const TQString &szCaption)
{
	m_szPlainTextCaption = szCaption;
}

void KviWindow::fillCaptionBuffers()
{
	TQString szCaption = m_szPlainTextCaption;
	if(szCaption.isEmpty())
		szCaption = m_szName;

	fillSingleColorCaptionBuffers(szCaption);
}

void KviWindow::fillSingleColorCaptionBuffers(const TQString &szName)
{
	static TQString p1("<nobr><font color=\"");
	static TQString p2("\"><b>");
	static TQString p3("</b></font></nobr>");

	m_szPlainTextCaption = szName;

	m_szHtmlActiveCaption = p1;
	m_szHtmlActiveCaption += KVI_OPTION_COLOR(KviOption_colorCaptionTextActive).name();
	m_szHtmlActiveCaption += p2;
	m_szHtmlActiveCaption += szName;
	m_szHtmlActiveCaption += p3;

	m_szHtmlInactiveCaption = p1;
	m_szHtmlInactiveCaption += KVI_OPTION_COLOR(KviOption_colorCaptionTextInactive).name();
	m_szHtmlInactiveCaption += p2;
	m_szHtmlInactiveCaption += szName;
	m_szHtmlInactiveCaption += p3;
}

void KviWindow::updateCaption()
{
	fillCaptionBuffers();
	if(mdiParent())
		mdiParent()->setCaption(plainTextCaption(),htmlActiveCaption(),htmlInactiveCaption());
	else
		setCaption(plainTextCaption());
	if(m_pTaskBarItem)m_pTaskBarItem->captionChanged();
	if(mdiParent() && isMaximized() && (g_pActiveWindow == this))
		g_pFrame->updateCaption();
}

void KviWindow::createSystemTextEncodingPopup()
{
	if(!g_pMdiWindowSystemTextEncodingPopup)
		g_pMdiWindowSystemTextEncodingPopup = new KviTalPopupMenu();
	else
	{
		g_pMdiWindowSystemTextEncodingPopup->clear();
	}
	
	if(!g_pMdiWindowSystemTextEncodingPopupStandard)
		g_pMdiWindowSystemTextEncodingPopupStandard = new KviTalPopupMenu();
	else
	{
		g_pMdiWindowSystemTextEncodingPopupStandard->clear();
		disconnect(g_pMdiWindowSystemTextEncodingPopupStandard,TQ_SIGNAL(activated(int)),0,0);
	}

	if(!g_pMdiWindowSystemTextEncodingPopupSmart)
		g_pMdiWindowSystemTextEncodingPopupSmart = new KviTalPopupMenu();
	else
	{
		g_pMdiWindowSystemTextEncodingPopupSmart->clear();
		disconnect(g_pMdiWindowSystemTextEncodingPopupSmart,TQ_SIGNAL(activated(int)),0,0);
	}

	if(!g_pMdiWindowSystemTextEncodingPopupSmartUtf8)
		g_pMdiWindowSystemTextEncodingPopupSmartUtf8 = new KviTalPopupMenu();
	else
	{
		g_pMdiWindowSystemTextEncodingPopupSmartUtf8->clear();
		disconnect(g_pMdiWindowSystemTextEncodingPopupSmartUtf8,TQ_SIGNAL(activated(int)),0,0);
	}

	TQTextCodec * c = defaultTextCodec();
	TQString tmp = __tr2qs("Use Default Encoding");
	if(c)
	{
		tmp += " (";
		tmp += c->name();
		tmp += ")";
	}

	int id = g_pMdiWindowSystemTextEncodingPopup->insertItem(tmp,this,TQ_SLOT(systemTextEncodingPopupDefault()));
	if(m_szTextEncoding.isEmpty())g_pMdiWindowSystemTextEncodingPopup->setItemChecked(id,true);
	g_pMdiWindowSystemTextEncodingPopup->insertSeparator();

	g_pMdiWindowSystemTextEncodingPopup->insertItem(__tr2qs("Standard"),g_pMdiWindowSystemTextEncodingPopupStandard);
	g_pMdiWindowSystemTextEncodingPopup->insertItem(__tr2qs("Smart (Send Local)"),g_pMdiWindowSystemTextEncodingPopupSmart);
	g_pMdiWindowSystemTextEncodingPopup->insertItem(__tr2qs("Smart (Send UTF-8)"),g_pMdiWindowSystemTextEncodingPopupSmartUtf8);
	
	int i = 0;
	KviLocale::EncodingDescription * d = KviLocale::encodingDescription(i);
	while(d->szName)
	{
		KviTQString::sprintf(tmp,"%s (%s)",d->szName,d->szDescription);
		KviTalPopupMenu * ppp = d->bSmart ? (d->bSendUtf8 ? g_pMdiWindowSystemTextEncodingPopupSmartUtf8 : g_pMdiWindowSystemTextEncodingPopupSmart) : g_pMdiWindowSystemTextEncodingPopupStandard;
		id = ppp->insertItem(tmp);
		if(KviTQString::equalCI(m_szTextEncoding,d->szName))
			ppp->setItemChecked(id,true);
		i = i + 1;
		d = KviLocale::encodingDescription(i);
	}

	connect(g_pMdiWindowSystemTextEncodingPopupSmart,TQ_SIGNAL(activated(int)),this,TQ_SLOT(systemTextEncodingPopupSmartActivated(int)));
	connect(g_pMdiWindowSystemTextEncodingPopupSmartUtf8,TQ_SIGNAL(activated(int)),this,TQ_SLOT(systemTextEncodingPopupSmartUtf8Activated(int)));
	connect(g_pMdiWindowSystemTextEncodingPopupStandard,TQ_SIGNAL(activated(int)),this,TQ_SLOT(systemTextEncodingPopupStandardActivated(int)));
}


void KviWindow::systemPopupRequest(const TQPoint &pnt)
{
	if(!g_pMdiWindowSystemMainPopup)
		g_pMdiWindowSystemMainPopup = new KviTalPopupMenu();
	else
	{
		g_pMdiWindowSystemMainPopup->clear();
		g_pMdiWindowSystemMainPopup->disconnect();
	}

	if(mdiParent())
		g_pMdiWindowSystemMainPopup->insertItem(*(g_pIconManager->getSmallIcon(KVI_SMALLICON_UNDOCK)),
		                                        __tr2qs("&Undock"),this,TQ_SLOT(undock()));
	else
		g_pMdiWindowSystemMainPopup->insertItem(*(g_pIconManager->getSmallIcon(KVI_SMALLICON_DOCK)),
		                                        __tr2qs("&Dock"),this,TQ_SLOT(dock()));

	g_pMdiWindowSystemMainPopup->insertSeparator();

	int id = g_pMdiWindowSystemMainPopup->insertItem(*(g_pIconManager->getSmallIcon(KVI_SMALLICON_MINIMIZE)),
		                                        __tr2qs("Mi&nimize"),this,TQ_SLOT(minimize()));
	g_pMdiWindowSystemMainPopup->setItemEnabled(id,!isMinimized());
	id = g_pMdiWindowSystemMainPopup->insertItem(*(g_pIconManager->getSmallIcon(KVI_SMALLICON_MAXIMIZE)),
		                                        __tr2qs("Ma&ximize"),this,TQ_SLOT(maximize()));
	g_pMdiWindowSystemMainPopup->setItemEnabled(id,!isMaximized());
	id = g_pMdiWindowSystemMainPopup->insertItem(*(g_pIconManager->getSmallIcon(KVI_SMALLICON_RESTORE)),
		                                        __tr2qs("&Restore"),this,TQ_SLOT(restore()));
	g_pMdiWindowSystemMainPopup->setItemEnabled(id,isMinimized()||isMaximized());

	g_pMdiWindowSystemMainPopup->insertSeparator();

	g_pMdiWindowSystemMainPopup->insertItem(*(g_pIconManager->getSmallIcon(KVI_SMALLICON_CLOSE)),
	                                        __tr2qs("Close"),this,TQ_SLOT(close()));

	g_pMdiWindowSystemMainPopup->insertSeparator();

	if(m_pTextEncodingButton)
	{
		createSystemTextEncodingPopup();
		g_pMdiWindowSystemMainPopup->insertItem(__tr2qs("Text &Encoding"),g_pMdiWindowSystemTextEncodingPopup);
	} // else we don't support setting private encoding anyway


	g_pMdiWindowSystemMainPopup->insertItem(*(g_pIconManager->getSmallIcon(KVI_SMALLICON_XY)),
	                                        __tr2qs("Sa&ve Window Properties"),this,TQ_SLOT(savePropertiesAsDefault()));

	fillContextPopup(g_pMdiWindowSystemMainPopup);

	g_pMdiWindowSystemMainPopup->popup(pnt);
}

void KviWindow::systemTextEncodingPopupDefault()
{
	// default
	setTextEncoding("");
}

void KviWindow::systemTextEncodingPopupSmartActivated(int id)
{
	if(!g_pMdiWindowSystemTextEncodingPopupSmart)
		return;
	TQString tmp = g_pMdiWindowSystemTextEncodingPopupSmart->text(id);
	KviTQString::cutFromFirst(tmp," (");
	setTextEncoding(tmp);
}

void KviWindow::systemTextEncodingPopupSmartUtf8Activated(int id)
{
	if(!g_pMdiWindowSystemTextEncodingPopupSmartUtf8)
		return;
	TQString tmp = g_pMdiWindowSystemTextEncodingPopupSmartUtf8->text(id);
	KviTQString::cutFromFirst(tmp," (");
	setTextEncoding(tmp);
}

void KviWindow::systemTextEncodingPopupStandardActivated(int id)
{
	if(!g_pMdiWindowSystemTextEncodingPopupStandard)
		return;
	TQString tmp = g_pMdiWindowSystemTextEncodingPopupStandard->text(id);
	KviTQString::cutFromFirst(tmp," (");
	setTextEncoding(tmp);
}

void KviWindow::savePropertiesAsDefault()
{
	TQString group;
	getConfigGroupName(group);

	if(!kvi_strEqualCI(group.utf8(),typeString()))
	{
		// save also the settings for THIS specialized window
		g_pFrame->saveWindowProperties(this,group);
	}

	g_pFrame->saveWindowProperties(this,typeString());
}

void KviWindow::contextPopup()
{
	systemPopupRequest(TQCursor::pos());
}

void KviWindow::fillContextPopup(KviTalPopupMenu *)
{
	// nothing here
}

void KviWindow::undock()
{
	g_pFrame->undockWindow(this);
}

void KviWindow::dock()
{
	g_pFrame->dockWindow(this);
}

void KviWindow::delayedAutoRaise()
{
	TQTimer::singleShot(0,this,TQ_SLOT(autoRaise()));
}

void KviWindow::autoRaise()
{
	if(!mdiParent())
	{
		raise();
		setActiveWindow();
	}
	if(m_pFocusHandler)
		m_pFocusHandler->setFocus();
	else
		setFocus();
}

void KviWindow::delayedClose()
{
	TQTimer::singleShot(0,this,TQ_SLOT(close()));
}

void KviWindow::closeEvent(TQCloseEvent *e)
{
	e->ignore();
	g_pFrame->childWindowCloseRequest(this);
}

void KviWindow::updateIcon()
{
	if(parent())
	{
		((KviMdiChild *)parent())->setIcon(*myIconPtr());
	} else {
		setIcon(*myIconPtr());
	}
}

void KviWindow::youAreDocked()
{
	if(m_pAccel)
	{
		delete m_pAccel;
		m_pAccel = 0;
	}
	((KviMdiChild *)parent())->setIcon(*myIconPtr());
	updateCaption();
	connect(((KviMdiChild *)parent()),TQ_SIGNAL(systemPopupRequest(const TQPoint &)),this,TQ_SLOT(systemPopupRequest(const TQPoint &)));
}

void KviWindow::youAreUndocked()
{
	m_pAccel = g_pFrame->installAccelerators(this);
	setIcon(*myIconPtr());
	updateCaption();
}

#ifdef FocusIn
// Hack for X.h
#undef FocusIn
#endif

void KviWindow::activateSelf()
{
	if(mdiParent())
		mdiParent()->activate(false);

	g_pFrame->childWindowActivated(this);
	// this is now done by KviFrame in childWindowActivated
	//g_pFrame->m_pTaskBar->setActiveItem(m_pTaskBarItem);
}

void KviWindow::setFocus()
{
	// don't trigger the whole TQt focus mechanism..
	// just trigger directly our focusInEvent
	// so we'll redirect the focus to the m_pFocusHandler
	focusInEvent(0);
}

void KviWindow::focusInEvent(TQFocusEvent *)
{
	if(m_pLastFocusedChild)
	{
		if(m_pLastFocusedChild->hasFocus() && m_pLastFocusedChild->isVisible())
		{
			// the last focused child still has focus (ehm ???)
			if(g_pActiveWindow != this)activateSelf();
			return;
		}
	}

	if(!m_pFocusHandler)
	{
		// must find one NOW
		// we probably have no KviInput since it would have been grabbed anyway
		
		if(m_pIrcView)m_pFocusHandler = m_pIrcView;
		else {
			TQObjectList list = childrenListObject();
			if(!list.isEmpty())
			{
				for(TQObject * c = list.first();c;c = list.next())
				{
					if(c->isWidgetType())
					{
						m_pFocusHandler = (TQWidget *)c;
						break;
					}
				}
			}
		}
		if(m_pFocusHandler)m_pFocusHandler->setFocus();
		else {
			// else too bad :/
			tqDebug("No widget able to handle focus for window %s",name());
			return;
		}
	} else {
		m_pFocusHandler->setFocus();
	}

	// Setting the focus to the focus handler usually
	// triggers our filter for the children's focusInEvent.
	// This should call activateSelf() and thus
	// we should be already the active window at this point.
	// If we're not, then run activateSelf() to fix this.
	if(g_pActiveWindow != this)activateSelf();
	//else tqDebug("ACTIVE WINDOW IS ALREADY THIS");
	updateCaption();
}

bool KviWindow::eventFilter(TQObject *o,TQEvent *e)
{
	switch(e->type())
	{
	case TQEvent::FocusIn:
		m_pLastFocusedChild = (TQWidget *)o;
		if(g_pActiveWindow != this)activateSelf();
		break;
	case TQEvent::Enter:
		// this is a handler moved here from KviMdiChild::eventFilter
		if(TQApplication::overrideCursor())
			TQApplication::restoreOverrideCursor();
		break;
	case TQEvent::MouseButtonPress:
		if( (((TQWidget *)o)->focusPolicy() == TQWidget::NoFocus) ||
		        (((TQWidget *)o)->focusPolicy() == TQWidget::TabFocus))
		{
			// this will not focus our window
			// set the focus to the focus handler
			if(m_pLastFocusedChild)
			{
				if(m_pLastFocusedChild->hasFocus() && m_pLastFocusedChild->isVisible())
					return false;
			}

			if(m_pFocusHandler)
			{
				m_pFocusHandler->setFocus();
			} else {
				setFocus(); // we grab the focus (someone must do it , damn :D)
			}
		}
		break;
	case TQEvent::ChildInserted:
		if(((TQChildEvent *)e)->child()->isWidgetType())
			childInserted((TQWidget *)((TQChildEvent *)e)->child());
		break;
	case TQEvent::ChildRemoved:
		if(((TQChildEvent *)e)->child()->isWidgetType())
			childRemoved((TQWidget *)((TQChildEvent *)e)->child());
		break;
	default: /* make gcc happy */ break;
	}
	return false;
}


void KviWindow::childInserted(TQWidget * o)
{
	o->removeEventFilter(this); // ensure that we don't filter twice
	o->installEventFilter(this); // we filter its events
	connect(o,TQ_SIGNAL(destroyed()),this,TQ_SLOT(childDestroyed()));

	if(o->inherits("KviInput"))
		m_pFocusHandler = o;
	else
	{
		if(!m_pFocusHandler && (o->focusPolicy() == TQWidget::StrongFocus))
		{
			m_pFocusHandler = o;
		}
	}

	TQObjectList list = o->childrenListObject();
	if(!list.isEmpty())
	{
		for(TQObject * c = list.first();c;c = list.next())
		{
			if(c->isWidgetType())
				childInserted((TQWidget *)c);
		}
	}
}

void KviWindow::childDestroyed()
{
	TQWidget * s = (TQWidget *)sender();
	childRemoved(s);
}

void KviWindow::childRemoved(TQWidget * o)
{
	//tqDebug("CHILD REMOVED %d",o);
	o->removeEventFilter(this);
	if(o == m_pFocusHandler)
		m_pFocusHandler = 0;
	if(o == m_pLastFocusedChild)
		m_pLastFocusedChild = 0;

	TQObjectList list = o->childrenListObject();
	if(!list.isEmpty())
	{
		for(TQObject * c = list.first();c;c = list.next())
		{
			if(c->isWidgetType())
				childRemoved((TQWidget *)c);
		}
	} //else tqDebug("The removed object has no children");
}

void KviWindow::childEvent(TQChildEvent *e)
{
	if(e->child()->isWidgetType())
	{
		if(e->removed())
			childRemoved((TQWidget *)(e->child()));
		else
			childInserted((TQWidget *)(e->child()));
	}
	TQWidget::childEvent(e);
}

void KviWindow::wheelEvent(TQWheelEvent *e)
{
	/* NOTHING HERE FOR NOW (FIXME) */
}


void KviWindow::childrenTreeChanged(TQWidget * widgetAdded)
{
	//	if(widgetAdded && m_pFocusHandler)setFocusHandler(m_pFocusHandler,widgetAdded);
	// FIXME: This might be useless
	TQResizeEvent * e = new TQResizeEvent(size(),size());
	resizeEvent(e);
	delete e;
}


void KviWindow::updateBackgrounds(TQObject * obj)
{
	if(!obj)
		obj = this;
	TQObjectList list = obj->childrenListObject();
	if(!list.isEmpty())
	{
		for(unsigned int i=0;i<list.count();i++)
		{
			TQObject * child = list.at(i);
			if(child->metaObject()->findProperty("TransparencyCapable",true) != -1)
				((TQWidget *)child)->update();

			updateBackgrounds(child);
		}
	}
}

void KviWindow::moveEvent(TQMoveEvent *e)
{
#ifdef COMPILE_PSEUDO_TRANSPARENCY
	updateBackgrounds();
#endif

	TQWidget::moveEvent(e);
}

void KviWindow::minimize()
{
	if(mdiParent())
	{
		if(!isMinimized())
			mdiParent()->minimize();
	}
	else
		showMinimized();
}

void KviWindow::maximize()
{
	if(mdiParent())
	{
		if(!isMaximized())
			mdiParent()->maximize();
	}
	else
		showMaximized();
	autoRaise();
}

bool KviWindow::isMinimized()
{
	if(mdiParent())
		return (mdiParent()->state() == KviMdiChild::Minimized);
	else
		return TQWidget::isMinimized();
}

bool KviWindow::isMaximized()
{
	if(mdiParent())
		return (mdiParent()->state() == KviMdiChild::Maximized);
	// Heh...how to check it ?
	// Empirical check
	int wdth = (g_pApp->desktop()->width() * 75) / 100;
	int hght = (g_pApp->desktop()->height() * 75) / 100;

	return ((x() <= 1)&&(y() <= 1)&&(width() >= wdth)&&(height() >= hght));
}

void KviWindow::restore()
{
	if(mdiParent())
	{
		if(isMinimized()||isMaximized())
			mdiParent()->restore();
	}
	else
		showNormal();
	autoRaise();
}

TQRect KviWindow::externalGeometry()
{
#ifndef Q_OS_MACX
	return mdiParent() ? mdiParent()->restoredGeometry() : frameGeometry();
#else
	return mdiParent() ? mdiParent()->restoredGeometry() : geometry();
#endif
}

void KviWindow::applyOptions()
{
	updateCaption();
	if(m_pIrcView)m_pIrcView->applyOptions();
	if(m_pInput)m_pInput->applyOptions();

	// trick: relayout
	resize(width() - 1,height() - 1);
	resize(width() + 1,height() + 1);
}

KviWindow * KviWindow::outputProxy()
{
	return 0;
}

void KviWindow::lostUserFocus()
{
	if(!m_pIrcView)return;
	if(m_pIrcView->hasLineMark())m_pIrcView->clearLineMark(true);
}


void KviWindow::internalOutput(KviIrcView * pView,int msg_type,const kvi_wchar_t * pText,int iFlags)
{
	// all roads lead to Rome :)

	if(pView)
	{
		if((this != g_pActiveWindow) || (!isActiveWindow()))
		{
			if(!pView->hasLineMark())
			{
				iFlags |= KviIrcView::SetLineMark;
			}
		}
		pView->appendText(msg_type,pText,iFlags);
	} else {
		// Redirect to the output proxy
		KviWindow *wnd = outputProxy();
		if(wnd)wnd->outputNoFmt(msg_type,pText,iFlags);
	}

	if(!m_pTaskBarItem) {
		return;
	}

	// if this option is checked we dont highlight other than channel msg
	if(KVI_OPTION_BOOL(KviOption_boolHighlightOnlyNormalMsg))
	{
		if((msg_type != KVI_OUT_CHANPRIVMSG) && (msg_type != KVI_OUT_CHANPRIVMSGCRYPTED))
		{
			if(!(
					(
						KVI_OPTION_BOOL(KviOption_boolHighlightOnlyNormalMsgQueryToo) &&
						(
							(msg_type == KVI_OUT_QUERYPRIVMSG) || (msg_type == KVI_OUT_QUERYTRACE) ||
							(msg_type == KVI_OUT_QUERYPRIVMSGCRYPTED) || (msg_type == KVI_OUT_QUERYNOTICE) || (msg_type == KVI_OUT_QUERYNOTICECRYPTED)
						)
					)
					||
					(
						KVI_OPTION_BOOL(KviOption_boolHighlightOnlyNormalMsgHighlightInChanToo) && (msg_type == KVI_OUT_HIGHLIGHT)
					)
				)
			)
			return;
		}
	}

	if(KVI_OPTION_BOOL(KviOption_boolHighlightOnlyAtCostumHighlightLevel) &&
			(KVI_OPTION_MSGTYPE(msg_type).level() < ((int)(KVI_OPTION_UINT(KviOption_uintMinHighlightLevel)))))
	{
		return;
	}

	m_pTaskBarItem->highlight(KVI_OPTION_MSGTYPE(msg_type).level());
}

void KviWindow::output(int msg_type,const char *format,...)
{
	TQString szFmt(format);
	kvi_va_list l;
	kvi_va_start(l,format);
	TQString szBuf;
	KviTQString::vsprintf(szBuf,szFmt,l);
	kvi_va_end(l);
	preprocessMessage(szBuf);
	const TQChar * pC = KviTQString::nullTerminatedArray(szBuf);
	if(!pC)return;
	internalOutput(m_pIrcView,msg_type,(kvi_wchar_t *)pC);
}

void KviWindow::output(int msg_type,const TQString &szFmt,...)
{
	kvi_va_list l;
	kvi_va_start_by_reference(l,szFmt);
	TQString szBuf;
	KviTQString::vsprintf(szBuf,szFmt,l);
	kvi_va_end(l);
	preprocessMessage(szBuf);
	const TQChar * pC = KviTQString::nullTerminatedArray(szBuf);
	if(!pC)return;
	internalOutput(m_pIrcView,msg_type,(kvi_wchar_t *)pC);
}

void KviWindow::output(int msg_type,const kvi_wchar_t *format,...)
{
	TQString szFmt=TQString::fromUtf8(KviStr(format).ptr());
	kvi_va_list l;
	kvi_va_start(l,format);
	TQString szBuf;
	KviTQString::vsprintf(szBuf,szFmt,l);
	kvi_va_end(l);
	preprocessMessage(szBuf);
	const TQChar * pC = KviTQString::nullTerminatedArray(szBuf);
	if(!pC)return;
	internalOutput(m_pIrcView,msg_type,(kvi_wchar_t *)pC);
}

void KviWindow::outputNoFmt(int msg_type,const char * text,int iFlags)
{
	TQString szText(text);
	preprocessMessage(szText);
	const TQChar * pC = KviTQString::nullTerminatedArray(szText);
	if(!pC)return;
	internalOutput(m_pIrcView,msg_type,(kvi_wchar_t *)pC,iFlags);
}

void KviWindow::outputNoFmt(int msg_type,const TQString &szText,int iFlags)
{
	TQString szBuf(szText);
	preprocessMessage(szBuf);
	const TQChar * pC = KviTQString::nullTerminatedArray(szBuf);
	if(!pC)return;
	internalOutput(m_pIrcView,msg_type,(kvi_wchar_t *)pC,iFlags);
}

void KviWindow::unhighlight()
{
	if(!m_pTaskBarItem)return;
	m_pTaskBarItem->unhighlight();
}

/* This messes up a bit: for example it breaks the WHOIS output where
   escapes are already present (checking for them here would be an overkill).
   This should be eventually done ONLY for remote user message texts
   in the server parser.

	Fixed
*/

void KviWindow::preprocessMessage(TQString & szMessage)
{
	// slow
	TQStringList strings = TQStringList::split(" ",szMessage, true);
	for ( TQStringList::Iterator it = strings.begin(); it != strings.end(); ++it ) {
		TQString tmp(*it);
		if(tmp.contains('\r')) continue;
		tmp = KviMircCntrl::stripControlBytes(tmp);
		tmp.stripWhiteSpace();
		if(m_pConsole)
			if(m_pConsole->connection())
				if(m_pConsole->connection()->serverInfo()->supportedChannelTypes().contains(tmp[0]))
					if((*it)==tmp)
						*it=TQString("\r!c\r%1\r").arg(*it);
					else
					{
						*it=TQString("\r!c%1\r%2\r").arg(tmp).arg(*it);
					}	
	}
	szMessage=strings.join(" ");
}


#include "kvi_window.moc"
