// vim: set tabstop=4 shiftwidth=4 noexpandtab
/*
Gwenview - A simple image viewer for KDE
Copyright 2000-2004 Aur�lien G�teau

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 option) 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.

*/
// TQt
#include <tqbuttongroup.h>
#include <tqheader.h>
#include <tqwhatsthis.h>

// KDE
#include <kdebug.h>
#include <kdesktopfile.h>
#include <kicondialog.h>
#include <kiconloader.h>
#include <kimageio.h>
#include <klineedit.h>
#include <klistview.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <krun.h>
#include <kurllabel.h>
#include <kurlrequester.h>

// Local
#include "archive.h"
#include "mimetypeutils.h"
#include "externaltoolmanager.h"
#include "externaltooldialogbase.h"
#include "externaltooldialog.moc"
namespace Gwenview {


enum { ID_ALL_IMAGES=0, ID_ALL_FILES, ID_CUSTOM };


class ToolListViewItem : public KListViewItem {
public:
	ToolListViewItem(KListView* parent, const TQString& label)
	: KListViewItem(parent, label), mDesktopFile(0L) {}
	
	void setDesktopFile(KDesktopFile* df) {
		mDesktopFile=df;
	}

	KDesktopFile* desktopFile() const {
		return mDesktopFile;
	}

private:
	KDesktopFile* mDesktopFile;
};


struct ExternalToolDialogPrivate {
	ExternalToolDialogBase* mContent;
	TQPtrList<KDesktopFile> mDeletedTools;
	ToolListViewItem* mSelectedItem;


	ExternalToolDialogPrivate()
	: mSelectedItem(0L) {}
	
	void fillMimeTypeListView() {
		TQStringList mimeTypes=MimeTypeUtils::rasterImageMimeTypes();
		mimeTypes.append("inode/directory");
		mimeTypes+=Archive::mimeTypes();

		TQStringList::const_iterator it=mimeTypes.begin();
		for(; it!=mimeTypes.end(); ++it) {
			(void)new TQCheckListItem(mContent->mMimeTypeListView, *it, TQCheckListItem::CheckBox);
		}
	}

	
	void fillToolListView() {
		TQDict<KDesktopFile> desktopFiles=ExternalToolManager::instance()->desktopFiles();
		
		TQDictIterator<KDesktopFile> it(desktopFiles);
		for (; it.current(); ++it) {
			ToolListViewItem* item=new ToolListViewItem(mContent->mToolListView, it.current()->readName());
			item->setPixmap(0, SmallIcon(it.current()->readIcon()) );
			item->setDesktopFile(it.current());
		}
		mContent->mToolListView->setSortColumn(0);
		mContent->mToolListView->sort();
	}


	void writeServiceTypes(KDesktopFile* desktopFile) {
		TQButton* button=mContent->mFileAssociationGroup->selected();
		if (!button) {
			desktopFile->writeEntry("ServiceTypes", "*");
			return;
		}

		int id=mContent->mFileAssociationGroup->id(button);
		if (id==ID_ALL_IMAGES) {
			desktopFile->writeEntry("ServiceTypes", "image/*");
			return;
		}
		if (id==ID_ALL_FILES) {
			desktopFile->writeEntry("ServiceTypes", "*");
			return;
		}

		TQStringList mimeTypes;
		TQListViewItem* item=mContent->mMimeTypeListView->firstChild();
		for (; item; item=item->nextSibling()) {
			if (static_cast<TQCheckListItem*>(item)->isOn()) {
				mimeTypes.append(item->text(0));
			}
		}
		desktopFile->writeEntry("ServiceTypes", mimeTypes);
	}
	

	bool saveChanges() {
		if (!mSelectedItem) return true;

		// Check name
		TQString name=mContent->mName->text().stripWhiteSpace();
		if (name.isEmpty()) {
			KMessageBox::sorry(mContent, i18n("The tool name cannot be empty"));
			return false;
		}

		TQListViewItem* item=mContent->mToolListView->firstChild();
		for (; item; item=item->nextSibling()) {
			if (item==mSelectedItem) continue;
			if (name==item->text(0)) {
				KMessageBox::sorry(mContent, i18n("There is already a tool named \"%1\"").arg(name));
				return false;
			}
		}
		
		// Save data
		KDesktopFile* desktopFile=mSelectedItem->desktopFile();
		if (desktopFile) {
			if (desktopFile->isReadOnly()) {
				desktopFile=ExternalToolManager::instance()->editSystemDesktopFile(desktopFile);
				mSelectedItem->setDesktopFile(desktopFile);
			}
		} else {		
			desktopFile=ExternalToolManager::instance()->createUserDesktopFile(name);
			mSelectedItem->setDesktopFile(desktopFile);
		}
		desktopFile->writeEntry("Name", name);
		desktopFile->writeEntry("Icon", mContent->mIconButton->icon());
		desktopFile->writeEntry("Exec", mContent->mCommand->url());
		writeServiceTypes(desktopFile);

		mSelectedItem->setPixmap(0, SmallIcon(mContent->mIconButton->icon()) );
		mSelectedItem->setText(0, name);

		return true;
	}


	void updateFileAssociationGroup(const TQStringList& serviceTypes) {
		TQListViewItem* item=mContent->mMimeTypeListView->firstChild();
		for (; item; item=item->nextSibling()) {
			static_cast<TQCheckListItem*>(item)->setOn(false);
		}
		
		if (serviceTypes.size()==0) {
			mContent->mFileAssociationGroup->setButton(ID_ALL_FILES);
			return;
		}
		if (serviceTypes.size()==1) {
			TQString serviceType=serviceTypes[0];
			if (serviceType=="image/*") {
				mContent->mFileAssociationGroup->setButton(ID_ALL_IMAGES);
				return;
			}
			if (serviceType=="*") {
				mContent->mFileAssociationGroup->setButton(ID_ALL_FILES);
				return;
			}
		}

		mContent->mFileAssociationGroup->setButton(ID_CUSTOM);
		TQStringList::ConstIterator it=serviceTypes.begin();
		for (;it!=serviceTypes.end(); ++it) {
			TQListViewItem* item=
				mContent->mMimeTypeListView->findItem(*it, 0, TQt::ExactMatch);
			if (item) static_cast<TQCheckListItem*>(item)->setOn(true);
		}
	}
	

	void updateDetails() {
		mContent->mDetails->setEnabled(mSelectedItem!=0);
		
		if (mSelectedItem) {
			KDesktopFile* desktopFile=mSelectedItem->desktopFile();
			if (desktopFile) {
				mContent->mName->setText(desktopFile->readName());
				mContent->mCommand->setURL(desktopFile->readEntry("Exec"));
				mContent->mIconButton->setIcon(desktopFile->readIcon());
				TQStringList serviceTypes=desktopFile->readListEntry("ServiceTypes");
				updateFileAssociationGroup(serviceTypes);
				return;
			}
		}

		mContent->mName->setText(TQString());
		mContent->mCommand->setURL(TQString());
		mContent->mIconButton->setIcon(TQString());
		mContent->mFileAssociationGroup->setButton(ID_ALL_IMAGES);
	}
	
	bool apply() {
		if (!saveChanges()) return false;
		TQPtrListIterator<KDesktopFile> it(mDeletedTools);
		for(; it.current(); ++it) {
			ExternalToolManager::instance()->hideDesktopFile(it.current());
		}
		ExternalToolManager::instance()->updateServices();
		return true;
	}
};


/**
 * This event filter object is here to prevent the user from selecting a
 * different tool in the tool list view if the current tool could not be saved.
 */
class ToolListViewFilterObject : public TQObject {
	ExternalToolDialogPrivate* d;
public:
	ToolListViewFilterObject(TQObject* parent, ExternalToolDialogPrivate* _d)
	: TQObject(parent), d(_d) {}

	bool eventFilter(TQObject*, TQEvent* event) {
		if (event->type()!=TQEvent::MouseButtonPress) return false;
		return !d->saveChanges();
	}
};


ExternalToolDialog::ExternalToolDialog(TQWidget* parent)
: KDialogBase(
	parent,0, false, TQString(), KDialogBase::Ok|KDialogBase::Apply|KDialogBase::Cancel,
	KDialogBase::Ok, true)
{
	setWFlags(getWFlags() | TQt::WDestructiveClose);
	d=new ExternalToolDialogPrivate;
	
	d->mContent=new ExternalToolDialogBase(this);
	setMainWidget(d->mContent);
	setCaption(d->mContent->caption());
	
	d->mContent->mToolListView->header()->hide();
	d->mContent->mMimeTypeListView->header()->hide();

	d->fillMimeTypeListView();
	d->fillToolListView();
	d->mContent->mToolListView->viewport()->installEventFilter(
		new ToolListViewFilterObject(TQT_TQOBJECT(this), d));

	connect( d->mContent->mToolListView, TQT_SIGNAL(selectionChanged(TQListViewItem*)),
		this, TQT_SLOT(slotSelectionChanged(TQListViewItem*)) );
	connect( d->mContent->mAddButton, TQT_SIGNAL(clicked()),
		this, TQT_SLOT(addTool()) );
	connect( d->mContent->mDeleteButton, TQT_SIGNAL(clicked()),
		this, TQT_SLOT(deleteTool()) );
	connect( d->mContent->mHelp, TQT_SIGNAL(leftClickedURL()),
		this, TQT_SLOT(showCommandHelp()) );
	connect( d->mContent->mMoreTools, TQT_SIGNAL(leftClickedURL(const TQString&)),
		this, TQT_SLOT(openURL(const TQString&)) );

	KListView* view=d->mContent->mToolListView;
	if (view->firstChild()) {
		view->setSelected(view->firstChild(), true);
	}
	d->updateDetails();
}


ExternalToolDialog::~ExternalToolDialog() {
	delete d;
}


void ExternalToolDialog::slotOk() {
	if (!d->apply()) return;
	accept();
}


void ExternalToolDialog::slotApply() {
	d->apply();
}


void ExternalToolDialog::slotCancel() {
	KDialogBase::slotCancel();
}


void ExternalToolDialog::slotSelectionChanged(TQListViewItem* item) {
	d->mSelectedItem=static_cast<ToolListViewItem*>(item);
	d->updateDetails();
}


void ExternalToolDialog::addTool() {
	KListView* view=d->mContent->mToolListView;
	TQString name=i18n("<Unnamed tool>");
	ToolListViewItem* item=new ToolListViewItem(view, name);
	view->setSelected(item, true);
}


void ExternalToolDialog::deleteTool() {
	KListView* view=d->mContent->mToolListView;
	ToolListViewItem* item=static_cast<ToolListViewItem*>(view->selectedItem());
	if (!item) return;

	KDesktopFile* desktopFile=item->desktopFile();
	delete item;
	d->mDeletedTools.append(desktopFile);
	d->mSelectedItem=0L;
	d->updateDetails();
}


void ExternalToolDialog::showCommandHelp() {
	KURLRequester* lbl=d->mContent->mCommand;
	TQWhatsThis::display(TQWhatsThis::textFor(lbl),
		lbl->mapToGlobal( lbl->rect().bottomRight() ) );
}


void ExternalToolDialog::openURL(const TQString& url) {
	new KRun(KURL(url));
}

} // namespace
