/*
 *   componentPage.cpp
 *
 *   Copyright (C) 2004 Waldo Bastian <bastian@kde.org>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License version 2 as
 *   published by the Free Software Foundation.
 *
 *   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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include "componentPage.h"

#include <qcursor.h>
#include <qfileinfo.h>
#include <qlabel.h>
#include <qstylesheet.h>
#include <qtextedit.h>
#include <qpushbutton.h>

#include <dcopref.h>

#include <kapplication.h>
#include <kdebug.h>
#include <klistview.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kprocess.h>
#include <kstdguiitem.h>

#include "component.h"
#include "kioskdata.h"
#include "kioskrun.h"

ComponentPage::ComponentPage( ComponentData *data, Component *component, QWidget* parent, const char* name, WFlags fl )
 : ComponentPageUI(parent, name, fl), PageWidget(this), m_data(data), m_component(component)
{
  m_process = 0;
  connect(pbSetup, SIGNAL(clicked()), this, SLOT(slotSetup()));
  connect(pbPreview, SIGNAL(clicked()), this, SLOT(slotPreview()));

  pbSetup->setText(i18n("&Setup %1").arg(m_data->caption));
  pbPreview->setText(i18n("&Preview %1").arg(m_data->caption));
  
  if (m_data->preview.exec.isEmpty())
     pbPreview->hide();
  
  if (m_data->setup.exec.isEmpty())
     pbSetup->hide();
     
  if (!pbPreview->isHidden() && !pbSetup->isHidden())
  {
     static bool firstTime = true;
       
     if (firstTime)
     {
        firstTime = false;
        QTimer::singleShot(0, this, SLOT(slotShowNotice()));
     }
  }

  fillActionList(listComponentConfig, m_data);
  
  connect(listComponentConfig, SIGNAL(currentChanged(QListViewItem *)),
          this, SLOT(slotShowAction(QListViewItem *)));
  slotShowAction(listComponentConfig->currentItem());          
}

ComponentPage::~ComponentPage()
{
   delete m_component;
}

void ComponentPage::slotShowNotice()
{
   KMessageBox::information(this, 
         i18n("Selecting the Setup or Preview option may cause the panel and/or the desktop to be temporarily shut down. "
              "To prevent data loss please make sure you are not actively using these components."),
         i18n("Attention"), "shutdown_notice");
}

void ComponentPage::load()
{
}

bool ComponentPage::save()
{
   return saveActionListChanges(listComponentConfig);
}
   
void ComponentPage::setFocus()
{
   listComponentConfig->setFocus();
}

QString ComponentPage::subCaption()
{
  return i18n("Setup %1").arg(m_data->caption);
}

void ComponentPage::slotSetup()
{
   if (m_process)
   {
      m_process->kill();
      delete m_process;
   }
   QCString dcopApp = m_data->setup.dcop.utf8();
   QCString dcopObj = "qt/" + dcopApp;
   if (!dcopApp.isEmpty() && m_data->setup.hasOption("restart"))
      DCOPRef(dcopApp, dcopObj).call("quit");

   QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
   if (!KioskRun::self()->prepare())
   {
      QApplication::restoreOverrideCursor();
      KMessageBox::sorry(this, 
          i18n("<qt>There was an unexpected problem with the runtime environment.</qt>"));
      return;
   }
   KioskRun::self()->makeMutable(true);
   if (!save())
   {
      QApplication::restoreOverrideCursor();
      return;
   }
   if (m_component)
      m_component->slotSetupPrepare();
   KioskRun::self()->updateSycoca();
   QApplication::restoreOverrideCursor();

   if (!dcopApp.isEmpty())
   {
      KioskRun::self()->dcopClient()->setNotifications(true);
      connect(KioskRun::self()->dcopClient(), SIGNAL(applicationRegistered( const QCString& )),
           this, SLOT(slotSetupAppRegistered( const QCString& )));
   }

   QStringList args;
   if (m_data->setup.hasOption("nofork"))
      args << "--nofork";

   args += m_data->setup.args;

   m_process = KioskRun::self()->run(m_data->setup.exec, args);
   int result = KMessageBox::questionYesNo(this, 
         i18n("<qt>You can now configure %1. "
              "When you are finished click <b>Save</b> to make the new configuration permanent.")
              .arg(m_data->caption), i18n("%1 Setup").arg(m_data->caption),
              KStdGuiItem::save(), KStdGuiItem::discard());
   m_saveSettings = (result == KMessageBox::Yes);
   if (!dcopApp.isEmpty())
      KioskRun::self()->dcopRef(dcopApp, dcopObj).call("quit");

   if (m_process->isRunning())
   {
      connect(m_process, SIGNAL(processExited(KProcess *)), this, SLOT(slotPreviewDone()));
   }
   else
   {
      slotSetupDone();
   }
}

void ComponentPage::slotSetupDone()
{
   delete m_process;
   m_process = 0;

   KioskRun::self()->dcopClient()->setNotifications(false);
   disconnect(KioskRun::self()->dcopClient(), SIGNAL(applicationRegistered( const QCString& )),
              this, SLOT(slotSetupAppRegistered( const QCString& )));

   KioskRun::self()->makeMutable(false);
   if (m_saveSettings)
   {
      bool result = true;
      if (m_component)
         result = m_component->setupFinished();
      
      if (!result) return;

      // Find new config files.
      QStringList newFiles = KioskRun::self()->newConfigFiles();
      for(QStringList::ConstIterator it = newFiles.begin();
          it != newFiles.end(); ++it)
      {
         if (m_data->ignoreFiles.contains(*it))
         {
            kdDebug() << "Ignoring new config file " << (*it) << endl;
            continue;
         }
         KioskRun::self()->mergeConfigFile(*it);
      }
   }
   KioskRun::self()->flushConfigCache();

   if (m_data->setup.hasOption("restart"))
      KApplication::kdeinitExec(m_data->setup.exec);
}

void ComponentPage::slotSetupAppRegistered( const QCString &appid)
{
   QCString dcopApp = m_data->setup.dcop.utf8();
   if (dcopApp == appid)
   {
      kdDebug() << appid << " is up and running" << endl;
      if (m_component)
         m_component->slotSetupStarted();
   }
}

void ComponentPage::slotPreview()
{
   if (m_process)
   {
      m_process->kill();
      delete m_process;
   }
   QCString dcopApp = m_data->preview.dcop.utf8();
   QCString dcopObj = "qt/" + dcopApp;
   if (!dcopApp.isEmpty() && m_data->preview.hasOption("restart"))
      DCOPRef(dcopApp, dcopObj).call("quit");

   QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
   KioskRun::self()->prepare();
   save();
   KioskRun::self()->updateSycoca();
   QApplication::restoreOverrideCursor();

   if (!dcopApp.isEmpty())
   {
      KioskRun::self()->dcopClient()->setNotifications(true);
      connect(KioskRun::self()->dcopClient(), SIGNAL(applicationRegistered( const QCString& )),
           this, SLOT(slotPreviewAppRegistered( const QCString& )));
   }

   QStringList args;
   if (m_data->preview.hasOption("nofork"))
      args << "--nofork";

   args += m_data->preview.args;

   m_process = KioskRun::self()->run(m_data->preview.exec, args);
   KMessageBox::information(this, 
         i18n("<qt>This is how %1 will behave and look with the new settings. "
              "Any changes you now make to the settings will not be saved.<p>"
              "Click <b>Ok</b> to return to your own personal %2 configuration.")
              .arg(m_data->caption, m_data->caption), i18n("%1 Preview").arg(m_data->caption));
   if (!dcopApp.isEmpty())
      KioskRun::self()->dcopRef(dcopApp, dcopObj).call("quit");

   if (m_process->isRunning())
   {
      connect(m_process, SIGNAL(processExited(KProcess *)), this, SLOT(slotPreviewDone()));
   }
   else
   {
      slotPreviewDone();
   }
}

void ComponentPage::slotPreviewAppRegistered( const QCString &appid)
{
   QCString dcopApp = m_data->preview.dcop.utf8();
   if (dcopApp == appid)
   {
      kdDebug() << appid << " is up and running" << endl;
      if (m_component)
         m_component->slotPreviewStarted();
   }
}

void ComponentPage::slotPreviewDone()
{
   KioskRun::self()->dcopClient()->setNotifications(false);
   disconnect(KioskRun::self()->dcopClient(), SIGNAL(applicationRegistered( const QCString& )),
              this, SLOT(slotPreviewAppRegistered( const QCString& )));

   delete m_process;
   m_process = 0;
   if (m_data->preview.hasOption("restart"))
      KApplication::kdeinitExec(m_data->preview.exec);
}

void ComponentPage::slotShowAction(QListViewItem *item)
{
   ComponentActionItem *actionItem = dynamic_cast<ComponentActionItem*>(item);
   QString description;
   if (actionItem)
   {
      description = "<h2>"+QStyleSheet::escape(actionItem->action()->caption)+"</h2>\n";
      description += actionItem->action()->description;
   }
   componentDescription->setText(description);
}

#include "componentPage.moc"
