/*********
*
* This file is part of BibleTime's source code, http://www.bibletime.info/.
*
* Copyright 1999-2006 by the BibleTime developers.
* The BibleTime source code is licensed under the GNU General Public License version 2.0.
*
**********/



#include "cswordsetupdialog.h"
#include "cswordsetupmodulelistview.h"
#include "cswordsetupinstallsourcesdialog.h"

#include "backend/cswordbackend.h"
#include "backend/cswordmoduleinfo.h"
// #include "btinstallmgr.h"

#include "cmanageindiceswidget.h"

#include "util/cresmgr.h"
#include "util/ctoolclass.h"
#include "util/scoped_resource.h"

//QT includes
#include <tqdir.h>
#include <tqlayout.h>
#include <tqlabel.h>
#include <tqcombobox.h>
#include <tqwidgetstack.h>
#include <tqfileinfo.h>
#include <tqpushbutton.h>
#include <tqlineedit.h>
#include <tqdict.h>

//KDE includes
#include <tdeapplication.h>
#include <tdeconfig.h>
#include <kdirselectdialog.h>
#include <keditlistbox.h>
#include <tdelocale.h>
#include <kstandarddirs.h>
#include <kiconloader.h>
#include <tdemessagebox.h>
#include <kprogress.h>
#include <kurl.h>

//Sword includes
#include <installmgr.h>
#include <swmodule.h>
#include <swversion.h>

using namespace sword;

namespace BookshelfManager {

	CSwordSetupDialog::CSwordSetupDialog(TQWidget *parent, const char *name )
: KDialogBase(IconList, i18n("Bookshelf Manager"), Ok, Ok, parent, name, true, true, TQString(), TQString(), TQString()),
	m_removeModuleListView(0),
	m_installModuleListPage(0),
	m_installModuleListView(0),
	m_progressDialog(0),
	m_refreshedRemoteSources(false) {
		setIconListAllVisible(true);
		m_swordSetupChanged = false;

		initSwordConfig();
		initInstall();
		initRemove();
		initManageIndices();
	}

	void CSwordSetupDialog::initSwordConfig() {
		TQFrame* page = m_swordConfigPage = addPage(i18n("Bookshelf path(s)"), TQString(), SmallIcon("bt_swordconfig",32));
		page->setMinimumSize(500,400);

		TQGridLayout* layout = new TQGridLayout(page, 6, 4);
		layout->setMargin(5);

		layout->setSpacing(10);
		layout->setColStretch(0,1);
		layout->setRowStretch(5,1);

		TQLabel* mainLabel = CToolClass::explanationLabel(page,
							i18n("Configure bookshelf path(s)"),
							i18n("You can store your bookshelfs in one or more directories, which you can specify here.")
														);
		layout->addMultiCellWidget(mainLabel, 0, 0, 0, 3);


		TQString swordConfPath = BTInstallMgr::Tool::LocalConfig::swordConfigFilename();
		TQLabel* confPathLabel = new TQLabel(i18n("Your bookshelf configuration file is <b>%1</b>").arg(swordConfPath), page);
		layout->addMultiCellWidget(confPathLabel, 1,1,0,3);

		m_swordPathListBox = new TQListView(page);
		//   m_swordPathListBox->setFullWidth(true);
		m_swordPathListBox->addColumn(i18n("Path to bookshelf"));
		connect(m_swordPathListBox, TQT_SIGNAL(selectionChanged()), this, TQT_SLOT(slot_swordPathSelected()));
		layout->addMultiCellWidget(m_swordPathListBox, 2,5,0,1);

		m_swordEditPathButton = new TQPushButton(i18n("Edit Entry"), page);
		m_swordEditPathButton->setIconSet(SmallIcon("edit", 16));
		connect(m_swordEditPathButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slot_swordEditClicked()));
		layout->addWidget(m_swordEditPathButton, 2, 3);

		m_swordAddPathButton = new TQPushButton(i18n("Add Entry"), page);
		m_swordAddPathButton->setIconSet(SmallIcon("edit_add", 16));
		connect(m_swordAddPathButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slot_swordAddClicked()));
		layout->addWidget(m_swordAddPathButton, 3,3);

		m_swordRemovePathButton = new TQPushButton(i18n("Remove Entry"), page);
		m_swordRemovePathButton->setIconSet(SmallIcon("edit-delete", 16));
		connect(m_swordRemovePathButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slot_swordRemoveClicked()));
		layout->addWidget(m_swordRemovePathButton, 4,3);

		setupSwordPathListBox();
	}

	void CSwordSetupDialog::initInstall() {
		m_installPage = addPage(i18n("Install/Update works"), TQString(), SmallIcon("bt_bible",32));

		TQVBoxLayout* vboxlayout = new TQVBoxLayout(m_installPage);
		TQHBoxLayout* hboxlayout = new TQHBoxLayout();
		hboxlayout->setAutoAdd( true );

		vboxlayout->addLayout(hboxlayout);

		m_installWidgetStack = new TQWidgetStack(m_installPage);
		hboxlayout->addWidget(m_installWidgetStack);

		m_installSourcePage = new TQWidget(0);
		m_installWidgetStack->addWidget(m_installSourcePage);

		//  m_installSourcePage->setMinimumSize(500,400);

		TQGridLayout* layout = new TQGridLayout(m_installSourcePage, 7, 3);
		layout->setMargin(5);
		layout->setSpacing(10);
		layout->setRowStretch(6,5);
		layout->setColStretch(0,5);

		TQLabel* installLabel = CToolClass::explanationLabel(m_installSourcePage,
							   i18n("Install/update works - Step 1"),
							   i18n("Please choose a (local or remote) library and a bookshelf path to install the work(s) to. \
After that step click on the connect button.<br/>\
<b>WARNING: If you live in a persecuted country and do not wish to risk detection you should NOT use \
the module remote installation feature!</b>")
														   );
		layout->addMultiCellWidget(installLabel, 0,0,0,2);

		TQLabel* sourceHeadingLabel = new TQLabel(TQString("<b>%1</b>").arg(i18n("Select library")), m_installSourcePage);
		layout->addMultiCellWidget(sourceHeadingLabel, 1,1,0,1);

		m_sourceCombo = new TQComboBox(m_installSourcePage);
		layout->addWidget(m_sourceCombo, 2, 0);

		TQPushButton* deleteSourceButton = new TQPushButton(i18n("Delete library"), m_installSourcePage);
		deleteSourceButton->setIconSet(SmallIcon("remove", 16));
		connect(deleteSourceButton, TQT_SIGNAL(clicked()), TQT_SLOT(slot_installDeleteSource()));
		layout->addWidget(deleteSourceButton, 2, 1, TQt::AlignLeft);

		TQPushButton* addSourceButton = new TQPushButton(i18n("Add library"), m_installSourcePage);
		addSourceButton->setIconSet(SmallIcon("folder-new", 16));
		connect(addSourceButton, TQT_SIGNAL(clicked()), TQT_SLOT(slot_installAddSource()));
		layout->addWidget(addSourceButton, 2, 2, TQt::AlignLeft);

		m_sourceLabel = new TQLabel(m_installSourcePage);
		layout->addMultiCellWidget(m_sourceLabel, 3,3,0,1);

		TQLabel* targetHeadingLabel = new TQLabel(TQString("<b>%1</b>").arg(i18n("Select bookshelf path")), m_installSourcePage);
		layout->addMultiCellWidget(targetHeadingLabel, 4,4,0,1);

		m_targetCombo = new TQComboBox(m_installSourcePage);
		layout->addWidget(m_targetCombo, 5, 0);

		m_targetLabel = new TQLabel(m_installSourcePage);
		layout->addMultiCellWidget(m_targetLabel, 6,6,0,0,TQt::AlignTop);

		//part beloew main layout with the back/next buttons
		TQHBoxLayout* myHBox = new TQHBoxLayout();
		vboxlayout->addLayout(myHBox);

		m_installBackButton = new TQPushButton(i18n("Back"), m_installPage);
		m_installBackButton->setIconSet(SmallIcon("back",16));
		myHBox->addWidget(m_installBackButton);

		myHBox->addSpacing(10);
		myHBox->addStretch(5);

		m_installContinueButton = new TQPushButton(i18n("Connect to library"), m_installPage);
		m_installContinueButton->setIconSet(SmallIcon("forward",16));
		connect(m_installContinueButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slot_connectToSource()));
		myHBox->addWidget(m_installContinueButton);

		m_installBackButton->setEnabled(false);

		connect(m_sourceCombo, TQT_SIGNAL( highlighted(const TQString&) ), TQT_SLOT( slot_sourceSelected( const TQString&) ));
		connect(m_targetCombo, TQT_SIGNAL( highlighted(const TQString&) ), TQT_SLOT( slot_targetSelected( const TQString&) ));
		populateInstallCombos();

		slot_sourceSelected( m_sourceCombo->currentText() );
	}

	void CSwordSetupDialog::initRemove() {
		TQFrame* page = m_removePage = addPage(i18n("Remove works"), TQString(), SmallIcon("edittrash",32));

		page->setMinimumSize(500,400);

		TQGridLayout* layout = new TQGridLayout(page, 4, 4);
		layout->setMargin(5);

		layout->setSpacing(10);
		layout->setColStretch(1,1);
		layout->setRowStretch(2,1);

		TQLabel* mainLabel= CToolClass::explanationLabel(page,
						   i18n("Remove installed work(s)"),
						   i18n("This dialog lets you remove installed works from your system. Choose the modules and then click on the remove button.")
													   );
		layout->addMultiCellWidget(mainLabel, 0, 0, 0, 3);

		TQLabel* headingLabel = new TQLabel(TQString("<b>%1</b>").arg(i18n("Select works to be uninstalled")), page);
		layout->addMultiCellWidget(headingLabel, 1, 1, 0, 3);

		m_removeModuleListView = new CSwordSetupModuleListView(page, false);
		layout->addMultiCellWidget( m_removeModuleListView, 2,2,0,3);

		m_removeRemoveButton = new TQPushButton(i18n("Remove selected work(s)"), page);
		m_removeRemoveButton->setIconSet( SmallIcon("edittrash", 16) );
		layout->addWidget(m_removeRemoveButton, 3, 3, TQt::AlignRight);

		connect(m_removeRemoveButton, TQT_SIGNAL(clicked()),
				this, TQT_SLOT(slot_doRemoveModules()));

		populateRemoveModuleListView();
	}

	void CSwordSetupDialog::initManageIndices()
	{
		TQFrame* page = m_manageIndiciesPage = addPage(i18n("Manage search indicies"),
			TQString(), SmallIcon("filefind",32));

		page->setMinimumSize(500,400);
		TQVBoxLayout* box = new TQVBoxLayout(page, 4, 4);
		CManageIndicesWidget* mi = new CManageIndicesWidget(page);
		box->addWidget(mi);
	}

	void CSwordSetupDialog::slotOk() {
		writeSwordConfig();
		KDialogBase::slotOk();
		emit signalSwordSetupChanged( );
	}

	void CSwordSetupDialog::writeSwordConfig() {
		if (m_swordSetupChanged && m_swordPathListBox->childCount()) {
			TQStringList targets;
			TQListViewItemIterator it( m_swordPathListBox );
			while ( it.current() ) {
				TQListViewItem *item = it.current();
				if (!item->text(0).isEmpty()) {
					targets << item->text(0);
				}
				++it;
			}

			BTInstallMgr::Tool::LocalConfig::setTargetList(targets); //creates new Sword config
		}
	}

	const bool CSwordSetupDialog::showPart( CSwordSetupDialog::Parts ID ) {
		bool ret = false;
		switch (ID) {
			case CSwordSetupDialog::Sword:
			showPage( pageIndex(m_swordConfigPage) );
			break;
			case CSwordSetupDialog::Install:
			showPage( pageIndex(m_installPage) );
			break;
			case CSwordSetupDialog::Remove:
			showPage( pageIndex(m_removePage) );
			break;
			default:
			break;
		}
		return ret;
	}


	void CSwordSetupDialog::populateInstallCombos() {
		m_sourceCombo->clear();

		BTInstallMgr::Tool::RemoteConfig::initConfig();

		TQStringList list;
		{
			BTInstallMgr mgr;
			list = BTInstallMgr::Tool::RemoteConfig::sourceList(&mgr);
		}
		if (!list.count()) { //add Crosswire entry
			InstallSource is("FTP");   //default return value
			is.caption = "Crosswire";
			is.source = "ftp.crosswire.org";
			is.directory = "/pub/sword/raw";
			BTInstallMgr::Tool::RemoteConfig::addSource(&is);

			BTInstallMgr mgr; //make sure we're uptodate
			list = BTInstallMgr::Tool::RemoteConfig::sourceList(&mgr);

			Q_ASSERT( list.count() > 0 );
		}

		BTInstallMgr mgr;
		for (TQStringList::iterator it = list.begin(); it != list.end(); ++it) {
			sword::InstallSource is = BTInstallMgr::Tool::RemoteConfig::source(&mgr, *it);

			if (BTInstallMgr::Tool::RemoteConfig::isRemoteSource(&is)) {
				m_sourceCombo->insertItem( i18n("[Remote]") + " " + *it ); //remote source
			}
			else { // local source
				TQFileInfo fi( is.directory.c_str() );
				if (fi.isDir() && fi.isReadable()) {
					m_sourceCombo->insertItem( i18n("[Local]") + " " + *it );
				}
			}
		}

		//Fill in the targets in the targets combobox
		//list = (m_targetCombo->count()) ? m_swordPathListBox : BTInstallMgr::Tool::LocalConfig::targetList();
		if (m_targetCombo->count()) { //we already read in the list once, we have to use the Sword paths list items now because this list is newer
			list.clear();
			TQListViewItemIterator it2( m_swordPathListBox );
			while (it2.current()) {
				list << it2.current()->text(0);

				++it2;
			}
		}
		else {
			list = BTInstallMgr::Tool::LocalConfig::targetList();
		}

		m_targetCombo->clear();
		for (TQStringList::iterator it = list.begin(); it != list.end(); ++it) {
			TQFileInfo fi(*it);
			if (fi.isDir() && fi.isWritable()) {
				m_targetCombo->insertItem( *it );
			}
		}

		//init widget states
		m_targetCombo->setEnabled( (m_targetCombo->count() > 0) );
		m_installContinueButton->setEnabled(
			(m_sourceCombo->count() > 0) && (m_targetCombo->count() > 0)
		);

		slot_sourceSelected( m_sourceCombo->currentText() );
	}


	void CSwordSetupDialog::slot_sourceSelected(const TQString &sourceName) {
		//remove status parta
		TQString source = sourceName;

		TQString rep = i18n("[Local]") + " ";
		int i = source.find(rep);
		if (i>=0) {
			source.remove(i, rep.length());
		}
		rep = i18n("[Remote]") + " ";
		i = source.find(rep);
		if (i>=0) {
			source.remove(i, rep.length());
		}

		BTInstallMgr mgr;
		TQString url;
		sword::InstallSource is = BTInstallMgr::Tool::RemoteConfig::source(&mgr, source) ;

		if (BTInstallMgr::Tool::RemoteConfig::isRemoteSource(&is)) {
			url = TQString("ftp://%1%2").arg(is.source.c_str()).arg(is.directory.c_str());
		}
		else {
			url = TQString("%1").arg(is.directory.c_str());
		}
		m_sourceLabel->setText( url );

		m_refreshedRemoteSources = false;
	}


	void CSwordSetupDialog::slot_targetSelected(const TQString &targetName) {
		m_targetLabel->setText( m_targetMap[targetName] );
		target = m_targetMap[targetName];
	}


	void CSwordSetupDialog::slot_doRemoveModules() {

		TQStringList moduleList =  m_removeModuleListView->selectedModules();

		if ( moduleList.empty() ) {
			return; //no message, just do nothing
		}

		const TQString message = i18n("You selected the following work(s): %1.\n\n"
									 "Do you really want to remove them from your system?").arg(moduleList.join(", "));

		if ((KMessageBox::warningYesNo(0, message, i18n("Warning")) == KMessageBox::Yes)) {  //Yes was pressed.
			sword::InstallMgr installMgr;
			TQDict<sword::SWMgr> mgrDict; //maps config paths to SWMgr objects

			for ( TQStringList::Iterator it = moduleList.begin(); it != moduleList.end(); ++it ) {
				if (CSwordModuleInfo* m = backend()->findModuleByName(*it)) { //module found?
					TQString prefixPath = m->config(CSwordModuleInfo::AbsoluteDataPath) + "/";
					TQString dataPath = m->config(CSwordModuleInfo::DataPath);

					if (dataPath.left(2) == "./") {
						dataPath = dataPath.mid(2);
					}

					if (prefixPath.contains(dataPath)) { //remove module part to get the prefix path
						prefixPath = prefixPath.remove( prefixPath.find(dataPath), dataPath.length() );
					}
					else { //fall back to default Sword config path
						prefixPath = TQString::fromLatin1(backend()->prefixPath);
					}

					sword::SWMgr* mgr = mgrDict[ prefixPath ];
					if (!mgr) { //create new mgr if it's not yet available
						mgrDict.insert(prefixPath, new sword::SWMgr(prefixPath.local8Bit()));
						mgr = mgrDict[ prefixPath ];
					}

					installMgr.removeModule(mgr, m->name().latin1());
				}
			}

			CPointers::backend()->reloadModules();
			populateRemoveModuleListView(); //rebuild the tree
			populateInstallModuleListView( currentInstallSource() ); //rebuild the tree

			//delete all mgrs
			mgrDict.setAutoDelete(true);
			mgrDict.clear();
		}
	}

	void CSwordSetupDialog::populateRemoveModuleListView() {
		CSwordBackend myBackend;
		TDEApplication::kApplication()->processEvents();
		myBackend.initModules();

		m_removeModuleListView->clear();

		ListCSwordModuleInfo list = myBackend.moduleList();
		int mod = 0;
		sword::SWConfig moduleConfig("");

		mod = 1;
		ListCSwordModuleInfo::iterator end_it = list.end();

		for (ListCSwordModuleInfo::iterator it(list.begin()); it != end_it; ++it, ++mod) {
			m_removeModuleListView->addModule(
				(*it),
				(*it)->config(CSwordModuleInfo::ModuleVersion)
			);
		}

		m_removeModuleListView->finish();
	}

	const bool CSwordSetupDialog::refreshRemoteModuleCache( const TQString& sourceName ) {
		if (m_refreshedRemoteSources) { //the module info is up-to-date
			return true;
		}

		BTInstallMgr iMgr;
		m_currentInstallMgr = &iMgr; //for the progress dialog
		sword::InstallSource is = BTInstallMgr::Tool::RemoteConfig::source(&iMgr, sourceName);
		bool success = false;

		m_progressDialog = new KProgressDialog(this, 0, i18n("Download"), TQString(), true);
		m_progressDialog->progressBar()->setTotalSteps(100);
		m_progressDialog->setLabel( i18n("Downloading library information...") );
		m_progressDialog->setMinimumDuration(0); //show immediately
		m_progressDialog->setAutoClose(false);
		m_progressDialog->show();
		TDEApplication::kApplication()->processEvents();

		connect(
			m_progressDialog, TQT_SIGNAL(cancelClicked()),
			TQT_SLOT(slot_moduleRefreshProgressCancelClicked())
		);
		connect(
			&iMgr, TQT_SIGNAL(completed(const int, const int)),
			TQT_SLOT(slot_moduleRefreshCompleted(const int, const int))
		);


		if (BTInstallMgr::Tool::RemoteConfig::isRemoteSource(&is)) {
			//   int errorCode = 0;
			if (!m_refreshedRemoteSources) {
				bool successful = iMgr.refreshRemoteSource( &is );
				if (!successful ) { //make sure the sources were updated sucessfully
					m_refreshedRemoteSources = true;
					success = true;
				}
				else { //an error occurres, the TDEIO library should display an error message
					tqWarning("InstallMgr: refreshRemoteSources returned an error.");
					m_refreshedRemoteSources = false;
					success = false;
				}
			}
		}
		else {
			// Local source
			success = true;
		}

		m_progressDialog->close();
		delete m_progressDialog;
		m_progressDialog = 0;

		return success;
	}

	bool CSwordSetupDialog::populateInstallModuleListView( const TQString& sourceName ) {
		TDEApplication::kApplication()->processEvents();
		Q_ASSERT(m_installModuleListView);
		if (!m_installModuleListView) { // this may be an update after removing modules
			return false;
		}

		m_installModuleListView->clear();

		BTInstallMgr iMgr;
		sword::InstallSource is = BTInstallMgr::Tool::RemoteConfig::source(&iMgr, sourceName);

		if (BTInstallMgr::Tool::RemoteConfig::isRemoteSource(&is)
				&& !refreshRemoteModuleCache(sourceName)) {
			//   tqWarning("finish");
			m_installModuleListView->finish();
			return false;
		}

		//kind of a hack to provide a pointer to mgr next line
		//   tqWarning("createing remote_backend");
		util::scoped_ptr<CSwordBackend> remote_backend( BTInstallMgr::Tool::backend(&is) );
		//  tqWarning("config path1 is %s", remote_backend->configPath);
		//  tqWarning("config path2 is %s", BTInstallMgr::Tool::backend(&is)->configPath ); //mem leak
		//   tqWarning("after creating remote_backend");
		Q_ASSERT(remote_backend);
		Q_ASSERT( BTInstallMgr::Tool::RemoteConfig::isRemoteSource(&is) );
		if (!remote_backend) {
			m_installModuleListView->finish();
			return false;
		}

		CSwordBackend* local_backend = CPointers::backend();
		Q_ASSERT(local_backend);
		//  tqWarning("local backend has path %s", local_backend->);
		TDEApplication::kApplication()->processEvents();
		//local_backend.initModules();

		//  tqWarning("config path3 is %s", remote_backend->configPath);
		ListCSwordModuleInfo mods = remote_backend->moduleList();
		Q_ASSERT(mods.count() > 0);

		ListCSwordModuleInfo::iterator end_it = mods.end();
		for (ListCSwordModuleInfo::iterator it(mods.begin()); it != end_it; ++it) {
			//   tqWarning("adding module %s (%s)", (*it)->name().latin1(), (*it)->config(CSwordModuleInfo::AbsoluteDataPath).latin1());
			bool isUpdate = false;

			CSwordModuleInfo* const installedModule = local_backend->findModuleByName((*it)->name());
			if (installedModule) {
				//    tqWarning("module is already installed in %s", installedModule->config(CSwordModuleInfo::AbsoluteDataPath).latin1());
			}
			//     Q_ASSERT(installedModule);

			if (installedModule) { //module already installed?
				//check whether it's an uodated module or just the same
				const SWVersion installedVersion(
					installedModule->config(CSwordModuleInfo::ModuleVersion).latin1()
				);

				const SWVersion newVersion(
					(*it)->config(CSwordModuleInfo::ModuleVersion).latin1()
				);

				isUpdate = (newVersion > installedVersion);
				if (!isUpdate) {
					//     tqWarning("    mod %s is not an update", (*it)->name().latin1());
					continue;
				}
			}

			//   Q_ASSERT(installedModule);
			m_installModuleListView->addModule(
				(*it),
				installedModule
				? installedModule->config(CSwordModuleInfo::ModuleVersion)
				: TQString()
			);
		}
		m_installModuleListView->finish();
		return true;
	}

	void CSwordSetupDialog::slot_connectToSource() {
		if (!m_installModuleListPage) { //the widgets are not yet created
			m_installModuleListPage = new TQWidget(0);

			TQGridLayout* layout = new TQGridLayout(m_installModuleListPage, 7, 2);
			layout->setMargin(5);
			layout->setSpacing(10);

			TQLabel* installLabel = CToolClass::explanationLabel(m_installModuleListPage,
								   i18n("Install/update works - Step 2"),
								   i18n("Please choose the works which should be installed and/or updated and click the install button.")
															   );
			layout->addMultiCellWidget(installLabel, 0,0,0,1);
			layout->setRowStretch(0,0);

			m_installWidgetStack->addWidget(m_installModuleListPage);
			m_installModuleListPage->setMinimumSize(500,400);

			//insert a list box which contains all available remote modules
			BTInstallMgr iMgr;
			sword::InstallSource is = BTInstallMgr::Tool::RemoteConfig::source(&iMgr, currentInstallSource());

			m_installModuleListView = new CSwordSetupModuleListView(m_installModuleListPage, true, &is);
			layout->addMultiCellWidget( m_installModuleListView, 1,6,0,1);
			layout->setColStretch(0,5);
			layout->setRowStretch(1,5);

			connect(m_installModuleListView, TQT_SIGNAL(selectedModulesChanged()), TQT_SLOT(slot_installModulesChanged()));
		}

		if (populateInstallModuleListView( currentInstallSource() ) ){

			//code valid for already existing and newly created widgets
			disconnect( m_installContinueButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slot_connectToSource()));
			connect( m_installContinueButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slot_installModules()));
	
			m_installContinueButton->setText(i18n("Install works"));
			m_installContinueButton->setEnabled(false);
	
			m_installWidgetStack->raiseWidget(m_installModuleListPage);
	
			connect( m_installBackButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slot_showInstallSourcePage()));
			m_installBackButton->setEnabled(true);
		}
	}

	void CSwordSetupDialog::slot_installAddSource() {

		sword::InstallSource newSource = CSwordSetupInstallSourcesDialog::getSource();

		if ( !((TQString)newSource.type.c_str()).isEmpty() ) { // we have a valid source to add
			BTInstallMgr::Tool::RemoteConfig::addSource( &newSource );
		}

		populateInstallCombos(); //make sure the items are updated
	}

	void CSwordSetupDialog::slot_installDeleteSource() {

		BTInstallMgr iMgr;
		sword::InstallSource is = BTInstallMgr::Tool::RemoteConfig::source( &iMgr, currentInstallSource() );
		BTInstallMgr::Tool::RemoteConfig::removeSource( &iMgr, &is );

		populateInstallCombos();
	}

	void CSwordSetupDialog::slot_installModulesChanged() {
		// This function enabled the Install modules button if modules are chosen
		// If an item was clicked to be not chosen look if there are other selected items
		// If the item was clicked to be chosen enable the button without looking at the other items

		const int moduleCount = m_installModuleListView->selectedModules().count();
		m_installContinueButton->setEnabled(moduleCount > 0);
	}

	void CSwordSetupDialog::slot_installModules() {
		tqWarning("CSwordSetupDialog::slot_installModules()");
		//   m_installContinueButton->setEnabled(false);
		//   m_installBackButton->setEnabled(false);

		//first get all chosen modules
		TQStringList moduleList = m_installModuleListView->selectedModules();
		Q_ASSERT(moduleList.count() != 0);
		if (moduleList.count() == 0) { // no modules selected
			return;
		}

		const TQString message = i18n("You selected the following works: %1.\n\n\
 Do you really want to install them on your system?").arg(moduleList.join(", "));

		if ((KMessageBox::warningYesNo(0, message, i18n("Warning")) == KMessageBox::Yes)) {  //Yes was pressed.
			BTInstallMgr iMgr;
			m_currentInstallMgr = &iMgr;
			sword::InstallSource is = BTInstallMgr::Tool::RemoteConfig::source(&iMgr, currentInstallSource());

			tqWarning("installing from %s/%s", is.source.c_str(), is.directory.c_str());
			TQString target = m_targetCombo->currentText();

			//make sure target/mods.d and target/modules exist
			TQDir dir(target.latin1());
			if (!dir.exists()) {
				dir.mkdir(target, true);
			}
			if (!dir.exists("modules")) {
				dir.mkdir("modules");
			}
			if (!dir.exists("mods.d")) {
				dir.mkdir("mods.d");
			}

			sword::SWMgr lMgr( target.latin1() );

			//module are removed in this section of code
			m_installedModuleCount = 0;
			m_progressDialog = new KProgressDialog(this, 0, i18n("Download of work(s)"), TQString(), true);
			m_progressDialog->progressBar()->setTotalSteps(100 * moduleList.count());
			m_progressDialog->setMinimumDuration(0); //show immediately
			m_progressDialog->setAutoClose(false);
			m_progressDialog->show();
			TDEApplication::kApplication()->processEvents();

			connect(
				m_progressDialog, TQT_SIGNAL(cancelClicked()),
				TQT_SLOT(slot_installProgressCancelClicked())
			);
			connect(
				&iMgr, TQT_SIGNAL(completed(const int, const int)),
				TQT_SLOT(installCompleted(const int, const int))
			);

			for ( TQStringList::Iterator it = moduleList.begin(); (it != moduleList.end()) && !m_progressDialog->wasCancelled(); ++it, ++m_installedModuleCount ) {

				tqWarning("installing %s", (*it).latin1());
				m_installingModule = *it;

				//check whether it's an update. If yes, remove existing module first
				CSwordModuleInfo* m = backend()->findModuleByName(*it);
				Q_ASSERT(!m);
				if (m) { //module found?
					TQString prefixPath = m->config(CSwordModuleInfo::AbsoluteDataPath) + "/";
					TQString dataPath = m->config(CSwordModuleInfo::DataPath);
					if (dataPath.left(2) == "./") {
						dataPath = dataPath.mid(2);
					}

					if (prefixPath.contains(dataPath)) {
						prefixPath.remove( prefixPath.find(dataPath), dataPath.length() ); //complicated to work with TQt 3.0
						//prefixPath = prefixPath.replace(dataPath, ""); //old code working with TQt 3.2
					}
					else {
						prefixPath = TQString::fromLatin1(backend()->prefixPath);
					}

					sword::SWMgr mgr(prefixPath.latin1());
					iMgr.removeModule(&mgr, m->name().latin1());
				}

				if (!m_progressDialog->wasCancelled()
						&& BTInstallMgr::Tool::RemoteConfig::isRemoteSource(&is)) {
					//        tqWarning("calling install");
					int status = iMgr.installModule(&lMgr, 0, (*it).latin1(), &is);
					//         tqWarning("status: %d", status);
					Q_ASSERT(status != -1);
				}
				else if (!m_progressDialog->wasCancelled()) { //local source
					iMgr.installModule(&lMgr, is.directory.c_str(), (*it).latin1());
				}
			}

			m_progressDialog->close();
			delete m_progressDialog;
			m_progressDialog = 0;

			//reload our backend because modules may have changed
			backend()->reloadModules();
			populateInstallModuleListView( currentInstallSource() ); //rebuild the tree
			populateRemoveModuleListView();
		}

		m_currentInstallMgr = 0;
		m_installBackButton->setEnabled(true);
		slot_installModulesChanged();
	}

	void CSwordSetupDialog::installCompleted( const int total, const int /* file */) {
		if (m_progressDialog) {
			m_progressDialog->progressBar()->setProgress(total+100*m_installedModuleCount);
			m_progressDialog->setLabel( i18n("[%1]: %2% complete").arg(m_installingModule).arg(total) );
		}
		TDEApplication::kApplication()->processEvents();
	}

	void CSwordSetupDialog::slot_showInstallSourcePage() {
		connect( m_installContinueButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slot_connectToSource()));
		disconnect( m_installContinueButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slot_installModules()));
		m_installBackButton->setEnabled(false);

		m_installContinueButton->setText(i18n("Connect to library"));
		m_installContinueButton->setEnabled(true);

		m_installWidgetStack->raiseWidget(m_installSourcePage);
	}

	void CSwordSetupDialog::slot_swordEditClicked() {
		if (TQListViewItem* i = m_swordPathListBox->currentItem()) {
			KURL url = KDirSelectDialog::selectDirectory(i->text(0), true);
			if (url.isValid()) {
				const TQFileInfo fi( url.path() );
				if (!fi.exists() || !fi.isWritable()) {
					const int result = KMessageBox::warningYesNo(this, i18n("This directory is not writable, so works \
   can not be installed here using BibleTime. \
   Do you want to use this directory instead of the previous value?"));
					if (result == KMessageBox::No) {
						return;
					}
				}
				i->setText(0, url.path());
				m_swordSetupChanged = true;
				writeSwordConfig(); //to make sure other parts work with the new setting
				populateInstallCombos(); //update target list bof on install page
				populateRemoveModuleListView();
			}
		}
	}

	void CSwordSetupDialog::slot_swordAddClicked() {
		KURL url = KDirSelectDialog::selectDirectory(TQString(), true);
		if (url.isValid()) {
			const TQFileInfo fi( url.path() );
			if (!fi.exists() || !fi.isWritable()) {
				const int result = KMessageBox::warningYesNo(this, i18n("This directory is not writable, \
   so works can not be installed here using BibleTime. \
   Do you want to add it to the list of module directories?"));
				if (result == KMessageBox::No) {
					return;
				}
			}
			(void)new TQListViewItem(m_swordPathListBox, url.path());
			m_swordSetupChanged = true;
			writeSwordConfig(); //to make sure other parts work with the new setting
			populateInstallCombos();     //update target list bof on install page
			populateRemoveModuleListView();
		}
	}

	void CSwordSetupDialog::slot_swordRemoveClicked() {
		TQListViewItem* i = m_swordPathListBox->currentItem();
		if (i) {
			delete i;

			m_swordSetupChanged = true;
			writeSwordConfig(); //to make sure other parts work with the new setting
			populateInstallCombos(); //update target list bof on install page
			populateRemoveModuleListView();
		}
	}

	void CSwordSetupDialog::setupSwordPathListBox() {
		TQStringList targets = BTInstallMgr::Tool::LocalConfig::targetList();
		m_swordPathListBox->clear();

		for (TQStringList::iterator it = targets.begin(); it != targets.end(); ++it)  {
			if ((*it).isEmpty()) {
				continue;
			}
			new TQListViewItem(m_swordPathListBox, *it);
		}
		m_swordPathListBox->setCurrentItem( m_swordPathListBox->firstChild() );
	}

	void CSwordSetupDialog::slot_swordPathSelected() {
		m_swordEditPathButton->setEnabled( m_swordPathListBox->currentItem() );
	}

	const TQString CSwordSetupDialog::currentInstallSource() {
		TQString source = m_sourceCombo->currentText();
		TQString rep = i18n("[Local]") + " ";
		int i = source.find(rep);
		if (i>=0) {
			source.remove(i, rep.length());
		}
		rep = i18n("[Remote]") + " ";
		i = source.find(rep);
		if (i>=0) {
			source.remove(i, rep.length());
		}
		return source;
	}

	void CSwordSetupDialog::slot_installProgressCancelClicked() {
		//cancel possible active module installation
		Q_ASSERT(m_currentInstallMgr);
		if (m_currentInstallMgr) {
			m_currentInstallMgr->terminate();
		}
	}

	void CSwordSetupDialog::slot_moduleRefreshProgressCancelClicked() {
		Q_ASSERT(m_currentInstallMgr);
		if (m_currentInstallMgr) {
			m_currentInstallMgr->terminate();
		}
		TDEApplication::kApplication()->processEvents();
	}

	void CSwordSetupDialog::slot_moduleRefreshCompleted(const int /*total*/, const int current) {
		if (m_progressDialog) {
			m_progressDialog->progressBar()->setProgress(current);
		}
		TDEApplication::kApplication()->processEvents();
	}

} // NAMESPACE

#include "cswordsetupdialog.moc"
