/*  This file is part of the KDE Libraries
 *  Copyright (C) 1998 Thomas Tanghus (tanghus@earthling.net)
 *  Additions 1999-2000 by Espen Sand (espen@kde.org)
 *
 *  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 <kconfig.h>
#include <kapplication.h>
#include <kdialog.h>
#include <kwhatsthismanager_p.h>
#include <kdebug.h>
#include <kstaticdeleter.h>
#include <kiconloader.h>
#include <kglobalsettings.h>
#include <klocale.h>

#include <tqlayout.h>
#include <tqobjectlist.h>
#include <tqguardedptr.h>
#include <tqlineedit.h>
#include <tqvaluelist.h>
#include <tqtimer.h>
#include <tqcursor.h>
#include <tqlabel.h>
#include <tqstyle.h>
#include <tqimage.h>

#include "config.h"
#ifdef Q_WS_X11
#include <netwm.h> 
#endif

const int KDialog::mMarginSize = 11;
const int KDialog::mSpacingSize = 6;

template class TQPtrList<TQLayoutItem>;

KDialog::KDialog(TQWidget *parent, const char *name, bool modal, WFlags f)
  : TQDialog(parent, name, modal, f), d(0)
{
    KWhatsThisManager::init ();
}

//
// Grab QDialogs keypresses if non-modal.
//
void KDialog::keyPressEvent(TQKeyEvent *e)
{
  if ( e->state() == 0 )
  {
    switch ( e->key() )
    {
      case Key_Escape:
      case Key_Enter:
      case Key_Return:
      {
        if(testWFlags((WFlags)(WType_Dialog | WShowModal)))
	{
          TQDialog::keyPressEvent(e);
	}
        else
        {
   	  e->ignore();
        }
      }
      break;
      default:
	e->ignore();
	return;
    }
  }
  else
  {
      // accept the dialog when Ctrl-Return is pressed
      if ( e->state() == ControlButton &&
           (e->key() == Key_Return || e->key() == Key_Enter) )
      {
          e->accept();
          accept();
      }
      else
      {
          e->ignore();
      }
  }
}


int KDialog::marginHint()
{
  return mMarginSize;
}


int KDialog::spacingHint()
{
  return mSpacingSize;
}

// KDE4: Remove me
void KDialog::polish()
{
  TQDialog::polish();
}


void KDialog::setCaption( const TQString &_caption )
{
  TQString caption = kapp ? kapp->makeStdCaption( _caption ) : _caption;
  setPlainCaption( caption );
}


void KDialog::setPlainCaption( const TQString &caption )
{
  TQDialog::setCaption( caption );

#ifdef Q_WS_X11
  NETWinInfo info( qt_xdisplay(), winId(), qt_xrootwin(), 0 );
  info.setName( caption.utf8().data() );
#endif
}


void KDialog::resizeLayout( TQWidget *w, int margin, int spacing )
{
  if( w->layout() )
  {
    resizeLayout( TQT_TQLAYOUTITEM(w->layout()), margin, spacing );
  }

  if( !w->childrenListObject().isEmpty() )
  {
    const TQObjectList l = w->childrenListObject();
    TQObjectListIterator itr(l);
    TQObject *o;
    while ((o = itr.current()) != 0) {
      if( o->isWidgetType() )
      {
	resizeLayout( (TQWidget*)o, margin, spacing );
      }
      ++itr;
    }
  }
}


void KDialog::resizeLayout( TQLayoutItem *lay, int margin, int spacing )
{
  TQLayoutIterator it = lay->iterator();
  TQLayoutItem *child;
  while ( (child = it.current() ) )
  {
    resizeLayout( child, margin, spacing );
    ++it;
  }
  if( lay->layout() )
  {
    lay->layout()->setMargin( margin );
    lay->layout()->setSpacing( spacing );
  }
}

static TQRect screenRect( TQWidget *w, int screen )
{
  TQDesktopWidget *desktop = TQApplication::desktop();
  KConfig gc("kdeglobals", false, false);
  gc.setGroup("Windows");
  if (desktop->isVirtualDesktop() &&
      gc.readBoolEntry("XineramaEnabled", true) &&
      gc.readBoolEntry("XineramaPlacementEnabled", true)) {
    if ( screen < 0 || screen >= desktop->numScreens() ) {
      if ( screen == -1 ) {
        screen = desktop->primaryScreen();
      } else if ( screen == -3 ) {
        screen = desktop->screenNumber( TQCursor::pos() );
      } else {
        screen = desktop->screenNumber( w );
      }
    }
    return desktop->availableGeometry(screen);
  } else {
    return desktop->geometry();
  }
}

void KDialog::centerOnScreen( TQWidget *w, int screen )
{
  if ( !w )
    return;
  TQRect r = screenRect( w, screen );

  w->move( r.center().x() - w->width()/2,
           r.center().y() - w->height()/2 );
}

bool KDialog::avoidArea( TQWidget *w, const TQRect& area, int screen )
{
  if ( !w )
    return false;
  TQRect fg = w->frameGeometry();
  if ( !fg.intersects( area ) )
    return true; // nothing to do.

  TQRect scr = screenRect( w, screen );
  TQRect avoid( area ); // let's add some margin
  avoid.moveBy( -5, -5 );
  avoid.rRight() += 10;
  avoid.rBottom() += 10;

  if ( QMAX( fg.top(), avoid.top() ) <= QMIN( fg.bottom(), avoid.bottom() ) )
  {
    // We need to move the widget up or down
    int spaceAbove = QMAX(0, avoid.top() - scr.top());
    int spaceBelow = QMAX(0, scr.bottom() - avoid.bottom());
    if ( spaceAbove > spaceBelow ) // where's the biggest side?
      if ( fg.height() <= spaceAbove ) // big enough?
        fg.setY( avoid.top() - fg.height() );
      else
        return false;
    else
      if ( fg.height() <= spaceBelow ) // big enough?
        fg.setY( avoid.bottom() );
      else
        return false;
  }

  if ( QMAX( fg.left(), avoid.left() ) <= QMIN( fg.right(), avoid.right() ) )
  {
    // We need to move the widget left or right
    int spaceLeft = QMAX(0, avoid.left() - scr.left());
    int spaceRight = QMAX(0, scr.right() - avoid.right());
    if ( spaceLeft > spaceRight ) // where's the biggest side?
      if ( fg.width() <= spaceLeft ) // big enough?
        fg.setX( avoid.left() - fg.width() );
      else
        return false;
    else
      if ( fg.width() <= spaceRight ) // big enough?
        fg.setX( avoid.right() );
      else
        return false;
  }
  //kdDebug() << "Moving window to " << fg.x() << "," << fg.y() << endl;
  w->move(fg.x(), fg.y());
  return true;
}

class KDialogQueuePrivate
{
public:
  TQValueList< TQGuardedPtr<TQDialog> > queue;
  bool busy;
};

static KStaticDeleter<KDialogQueue> ksdkdq;

KDialogQueue *KDialogQueue::_self=0;

KDialogQueue* KDialogQueue::self()
{
   if (!_self)
      _self = ksdkdq.setObject(_self, new KDialogQueue);
   return _self;
}

KDialogQueue::KDialogQueue() : d(new KDialogQueuePrivate)
{
   d->busy = false;
}

KDialogQueue::~KDialogQueue()
{
   delete d;
   _self = 0;
}

// static
void KDialogQueue::queueDialog(TQDialog *dialog)
{
   KDialogQueue *_this = self();
   _this->d->queue.append(dialog);
   TQTimer::singleShot(0, _this, TQT_SLOT(slotShowQueuedDialog()));
}

void KDialogQueue::slotShowQueuedDialog()
{
   if (d->busy)
      return;
   TQDialog *dialog;
   do {
       if(d->queue.isEmpty())
         return;
      dialog = d->queue.first();
      d->queue.pop_front();
   }
   while(!dialog);

   d->busy = true;
   dialog->exec();
   d->busy = false;
   delete dialog;

   if (!d->queue.isEmpty())
      TQTimer::singleShot(20, this, TQT_SLOT(slotShowQueuedDialog()));
   else
      ksdkdq.destructObject(); // Suicide.
}

void KDialog::virtual_hook( int, void* )
{ /*BASE::virtual_hook( id, data );*/ }

KSMModalDialogHeader::KSMModalDialogHeader(TQWidget* parent)
  : TQWidget( parent, "", Qt::WDestructiveClose )
{
	TQVBoxLayout* vbox = new TQVBoxLayout( this );

	TQFrame* frame = new TQFrame( this );
	frame->setFrameStyle( TQFrame::NoFrame );
	frame->setLineWidth( 0 );
	// we need to set the minimum size for the window
	frame->setMinimumWidth(400);
	vbox->addWidget( frame );
	TQGridLayout* gbox = new TQGridLayout( frame, 1, 1, 0, KDialog::spacingHint() );
	TQHBoxLayout* centerbox = new TQHBoxLayout( frame, 0, KDialog::spacingHint() );
	TQHBoxLayout* seperatorbox = new TQHBoxLayout( frame, 0, 0 );

	TQWidget* ticon = new TQWidget( frame );
	KIconLoader * ldr = KGlobal::iconLoader();
	TQPixmap trinityPixmap = ldr->loadIcon("kmenu", KIcon::Panel, KIcon::SizeLarge, KIcon::DefaultState, 0L, true);

	// Manually draw the alpha portions of the icon onto the widget background color...
	TQRgb backgroundRgb = ticon->paletteBackgroundColor().rgb();
	TQImage correctedImage = trinityPixmap.convertToImage();
	correctedImage = correctedImage.convertDepth(32);
	correctedImage.setAlphaBuffer(true);
	int w = correctedImage.width();
	int h = correctedImage.height();
	for (int y = 0; y < h; ++y) {
		TQRgb *ls = (TQRgb *)correctedImage.scanLine( y );
		for (int x = 0; x < w; ++x) {
			TQRgb l = ls[x];
			float alpha_adjust = tqAlpha( l )/255.0;
			int r = int( (tqRed( l ) * alpha_adjust) + (tqRed( backgroundRgb ) * (1.0-alpha_adjust)) );
			int g = int( (tqGreen( l ) * alpha_adjust) + (tqGreen( backgroundRgb ) * (1.0-alpha_adjust)) );
			int b = int( (tqBlue( l ) * alpha_adjust) + (tqBlue( backgroundRgb ) * (1.0-alpha_adjust)) );
			int a = int( 255 );
			ls[x] = tqRgba( r, g, b, a );
		}
	}
	trinityPixmap.convertFromImage(correctedImage);

	ticon->setBackgroundPixmap(trinityPixmap);
	ticon->setMinimumSize(trinityPixmap.size());
	ticon->setMaximumSize(trinityPixmap.size());
	ticon->resize(trinityPixmap.size());
	centerbox->addWidget( ticon, AlignCenter );

	TQWidget* swidget = new TQWidget( frame );
	swidget->resize(2, frame->sizeHint().width());
	swidget->setBackgroundColor(Qt::black);
	seperatorbox->addWidget( swidget, AlignCenter );

	TQLabel* label = new TQLabel( i18n("Trinity Desktop Environment"), frame );
	TQFont fnt = label->font();
	fnt.setBold( true );
	fnt.setPointSize( fnt.pointSize() * 3 / 2 );
	label->setFont( fnt );
	centerbox->addWidget( label, AlignCenter );

	gbox->addLayout(centerbox, 0, 0);
	gbox->addLayout(seperatorbox, 1, 0);

	setFixedSize( sizeHint() );
}

KSMModalDialogHeader::~KSMModalDialogHeader()
{
}

KSMModalDialog::KSMModalDialog(TQWidget* parent)
  : TQWidget( 0, "systemmodaldialogclass", Qt::WStyle_Customize | Qt::WType_Dialog | Qt::WStyle_Title | Qt::WStyle_StaysOnTop | Qt::WDestructiveClose ), m_keepOnTopTimer(NULL), m_allowClose(false)

{
	// Signal that we do not want any window controls to be shown at all
	Atom kde_wm_system_modal_notification;
	kde_wm_system_modal_notification = XInternAtom(qt_xdisplay(), "_KDE_WM_MODAL_SYS_NOTIFICATION", False);
	XChangeProperty(qt_xdisplay(), winId(), kde_wm_system_modal_notification, XA_INTEGER, 32, PropModeReplace, (unsigned char *) "TRUE", 1L);

	TQVBoxLayout* vbox = new TQVBoxLayout( this );
	
	TQFrame* frame = new TQFrame( this );
	frame->setFrameStyle( TQFrame::NoFrame );
	frame->setLineWidth( style().pixelMetric( TQStyle::PM_DefaultFrameWidth, frame ) );
	// we need to set the minimum size for the window
	frame->setMinimumWidth(400);
	vbox->addWidget( frame );
	TQGridLayout* gbox = new TQGridLayout( frame, 1, 1, KDialog::marginHint(), KDialog::spacingHint() );
	TQHBoxLayout* centerbox = new TQHBoxLayout( frame, 0, KDialog::spacingHint() );

	m_statusLabel = new TQLabel( i18n("Pondering what to do next").append("..."), frame );
	TQFont fnt = m_statusLabel->font();
	fnt.setBold( false );
	fnt.setPointSize( fnt.pointSize() * 1 );
	m_statusLabel->setFont( fnt );
	gbox->addMultiCellWidget( m_statusLabel, 2, 2, 0, 0, AlignLeft | AlignVCenter );

	KSMModalDialogHeader *theader = new KSMModalDialogHeader(this);
	centerbox->addWidget( theader, AlignCenter );

	gbox->addLayout(centerbox, 0, 0);

	setFixedSize( sizeHint() );
	setCaption( i18n("Please wait...") );

	// Center the dialog
	TQSize sh = sizeHint();
	TQRect rect = KGlobalSettings::desktopGeometry(TQCursor::pos());
	move(rect.x() + (rect.width() - sh.width())/2, rect.y() + (rect.height() - sh.height())/2);

	show();
	keepMeOnTop();
}

void KSMModalDialog::keepMeOnTop()
{
	if (!m_keepOnTopTimer) {
		m_keepOnTopTimer = new TQTimer();
		connect(m_keepOnTopTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(keepMeOnTop()));
		m_keepOnTopTimer->start(100, FALSE);
	}
	setActiveWindow();
	raise();
	setFocus();
}

KSMModalDialog::~KSMModalDialog()
{
	m_keepOnTopTimer->stop();
	delete m_keepOnTopTimer;
}

void KSMModalDialog::setStatusMessage(TQString message)
{
    if (message == "") {
        m_statusLabel->setText(i18n("Pondering what to do next").append("..."));
    }
    else {
        m_statusLabel->setText(message);
    }
}

void KSMModalDialog::closeSMDialog()
{
	m_allowClose = true;
	close();
}

void KSMModalDialog::closeEvent(TQCloseEvent *e)
{
	//---------------------------------------------
	// Don't call the base function because
	// we want to ignore the close event
	//---------------------------------------------

	if (m_allowClose)
		TQWidget::closeEvent(e);
}

void KSMModalDialog::setStartupPhase(TQString msg)
{
	if (msg == TQString("dcop")) setStatusMessage(i18n("Starting DCOP").append("..."));
	if (msg == TQString("kded")) setStatusMessage(i18n("Starting TDE daemon").append("..."));
	if (msg == TQString("kcminit")) setStatusMessage(i18n("Starting services").append("..."));
	if (msg == TQString("ksmserver")) setStatusMessage(i18n("Starting session").append("..."));
	if (msg == TQString("wm started")) setStatusMessage(i18n("Initializing window manager").append("..."));
	if (msg == TQString("kdesktop")) setStatusMessage(i18n("Loading desktop").append("..."));
	if (msg == TQString("kicker")) setStatusMessage(i18n("Loading panels").append("..."));
	if (msg == TQString("session ready")) setStatusMessage(i18n("Restoring applications").append("..."));
}

#include "kdialog.moc"