// vim: set tabstop=4 shiftwidth=4 noexpandtab:
/*
Gwenview - A simple image viewer for KDE
Copyright 2005 Aurelien Gateau

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.

*/

#include "bookmarkviewcontroller.moc"

#include <memory>

// TQt
#include <tqcursor.h>
#include <tqheader.h>
#include <tqpopupmenu.h>
#include <tqtooltip.h>
#include <tqvbox.h>

// KDE
#include <kaction.h>
#include <kactioncollection.h>
#include <kbookmarkmanager.h>
#include <kdebug.h>
#include <kdeversion.h>
#include <kiconloader.h>
#include <klistview.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kmimetype.h>
#include <ktoolbar.h>
#include <kurl.h>
#include <kurldrag.h>

// Local
#include "bookmarkdialog.h"
#include "../gvcore/fileoperation.h"

namespace Gwenview {

// URLDropListView	
URLDropListView::URLDropListView(TQWidget* tqparent)
: KListView(tqparent) {
	setAcceptDrops(true);
}


void URLDropListView::contentsDragMoveEvent(TQDragMoveEvent* event) {
	if (KURLDrag::canDecode(event)) {
		event->accept();
	} else {
		event->ignore();
	}
}




struct BookmarkItem : public KListViewItem {
	template <class ItemParent>
	BookmarkItem(ItemParent* tqparent, const KBookmark& bookmark)
	: KListViewItem(tqparent)
	, mBookmark(bookmark)
	{
		refresh();
	}

	void refresh() {
		setText(0, mBookmark.text() );
		setPixmap(0, SmallIcon(mBookmark.icon()) );
	}

	KBookmark mBookmark;
};


class BookmarkToolTip : public TQToolTip {
public:
	BookmarkToolTip(KListView* lv)
	: TQToolTip(lv->viewport())
	, mListView(lv) {}

	void maybeTip(const TQPoint& pos) {
		BookmarkItem *item = static_cast<BookmarkItem*>( mListView->itemAt(pos) );
		if ( !item) return;
		if (item->mBookmark.isGroup()) return;
		
		TQRect rect=mListView->tqitemRect(item);
		tip(rect, item->mBookmark.url().prettyURL());
	};
	
	KListView* mListView;
};


struct BookmarkViewController::Private {
	TQVBox* mBox;
	KListView* mListView;
	KBookmarkManager* mManager;
	KURL mCurrentURL;
	std::auto_ptr<BookmarkToolTip> mToolTip;
	KActionCollection* mActionCollection;
	KURL mDroppedURL;

	template <class ItemParent>
	void addGroup(ItemParent* itemParent, const KBookmarkGroup& group) {
		KBookmark bookmark=group.first();
		BookmarkItem* previousItem=0;
		BookmarkItem* item=0;
		for (;!bookmark.isNull(); bookmark=group.next(bookmark) ) {
			if (bookmark.isSeparator()) continue;
			
			// Create the item and make sure it's placed at the end
			previousItem=item;
			item=new BookmarkItem(itemParent, bookmark);
			if (previousItem) {
				item->moveItem(previousItem);
			}
			
			if (bookmark.isGroup()) {
				addGroup(item, static_cast<const KBookmarkGroup&>(bookmark) );
			}
		}
	}

	KBookmarkGroup findBestParentGroup() {
		KBookmarkGroup parentGroup;
		BookmarkItem* item=static_cast<BookmarkItem*>( mListView->currentItem() );
		if (item) {
			if (item->mBookmark.isGroup()) {
				parentGroup=item->mBookmark.toGroup();
			} else {
				parentGroup=item->mBookmark.parentGroup();
			}
		} else {
			parentGroup=mManager->root();
		}

		return parentGroup;
	}

	void bookmarkURL(const KURL& url) {
		BookmarkDialog dialog(mListView, BookmarkDialog::BOOKMARK);
		dialog.setTitle(url.fileName());
		dialog.setURL(url.prettyURL());
		dialog.setIcon(KMimeType::iconForURL(url));
		if (dialog.exec()==TQDialog::Rejected) return;

		KBookmarkGroup parentGroup=findBestParentGroup();
		parentGroup.addBookmark(mManager, dialog.title(), dialog.url(), dialog.icon());
		mManager->emitChanged(parentGroup);
	}
};


void URLDropListView::contentsDropEvent(TQDropEvent* event) {
	KURL::List urls;
	if (!KURLDrag::decode(event, urls)) return;
	emit urlDropped(event, urls);
}


BookmarkViewController::BookmarkViewController(TQWidget* tqparent)
: TQObject(tqparent)
{
	d=new Private;
	d->mManager=0;

	d->mBox=new TQVBox(tqparent);
	
	// Init listview
	d->mListView=new URLDropListView(d->mBox);
	d->mToolTip.reset(new BookmarkToolTip(d->mListView) );
	d->mActionCollection=new KActionCollection(d->mListView);

	d->mListView->header()->hide();
	d->mListView->setRootIsDecorated(true);
	d->mListView->addColumn(TQString());
	d->mListView->setSorting(-1);
	d->mListView->setShowToolTips(false);
	d->mListView->setFullWidth(true);

	connect(d->mListView, TQT_SIGNAL(clicked(TQListViewItem*)),
		this, TQT_SLOT(slotOpenBookmark(TQListViewItem*)) );
	connect(d->mListView, TQT_SIGNAL(returnPressed(TQListViewItem*)),
		this, TQT_SLOT(slotOpenBookmark(TQListViewItem*)) );
	connect(d->mListView, TQT_SIGNAL(contextMenuRequested(TQListViewItem*, const TQPoint&, int)),
		this, TQT_SLOT(slotContextMenu(TQListViewItem*)) );
	connect(d->mListView, TQT_SIGNAL(urlDropped(TQDropEvent*, const KURL::List&)),
		this, TQT_SLOT(slotURLDropped(TQDropEvent*, const KURL::List&)) );

	// Init toolbar
	KToolBar* toolbar=new KToolBar(d->mBox, "", true);
	KAction* action;
	toolbar->setIconText(KToolBar::IconTextRight);
	action=new KAction(i18n("Add a bookmark (keep it short)", "Add"), "bookmark_add", 0, 
			this, TQT_SLOT(bookmarkCurrentURL()), d->mActionCollection);
	action->plug(toolbar);
	action=new KAction(i18n("Remove a bookmark (keep it short)", "Remove"), "editdelete", 0,
			this, TQT_SLOT(deleteCurrentBookmark()), d->mActionCollection);
	action->plug(toolbar);
}


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


void BookmarkViewController::init(KBookmarkManager* manager) {
	// This method should not be called twice
	Q_ASSERT(!d->mManager);
	
	d->mManager=manager;
	// For now, we ignore the caller parameter and just refresh the full list on update
	connect(d->mManager, TQT_SIGNAL(changed(const TQString&, const TQString&)),
		this, TQT_SLOT(fill()) );
	fill();
}


void BookmarkViewController::setURL(const KURL& url) {
	d->mCurrentURL=url;
}


TQWidget* BookmarkViewController::widget() const {
	return d->mBox;
}


void BookmarkViewController::fill() {
	d->mListView->clear();
	KBookmarkGroup root=d->mManager->root();
	d->addGroup(d->mListView, root);
}


void BookmarkViewController::slotURLDropped(TQDropEvent* event, const KURL::List& urls) {
	// Get a pointer to the drop item
	TQPoint point(0,event->pos().y());
	KListView* lst=d->mListView;
	BookmarkItem* item=static_cast<BookmarkItem*>( lst->itemAt(lst->contentsToViewport(point)) );
	
	TQPopupMenu menu(lst);
	int addBookmarkID=menu.insertItem( SmallIcon("bookmark_add"), i18n("&Add Bookmark"),
		this, TQT_SLOT(slotBookmarkDroppedURL()) );
	if (urls.count()==1) {
		d->mDroppedURL=*urls.begin();
	} else {
		menu.setItemEnabled(addBookmarkID, false);
	}

	if (item) {
		menu.insertSeparator();
		KURL dest=item->mBookmark.url();
		FileOperation::fillDropURLMenu(&menu, urls, dest);
	}

	menu.insertSeparator();
	menu.insertItem( SmallIcon("cancel"), i18n("Cancel") );
	menu.exec(TQCursor::pos());
}


void BookmarkViewController::slotBookmarkDroppedURL() {
	d->bookmarkURL(d->mDroppedURL);
}


void BookmarkViewController::slotOpenBookmark(TQListViewItem* item_) {
	if (!item_) return;
	BookmarkItem* item=static_cast<BookmarkItem*>(item_);
	const KURL& url=item->mBookmark.url();
	if (!url.isValid()) return;
	emit openURL(url);
}


void BookmarkViewController::slotContextMenu(TQListViewItem* item_) {
	BookmarkItem* item=static_cast<BookmarkItem*>(item_);
	TQPopupMenu menu(d->mListView);
	menu.insertItem(SmallIcon("bookmark_add"), i18n("Add Bookmark..."),
		this, TQT_SLOT(bookmarkCurrentURL()));
	menu.insertItem(SmallIcon("bookmark_folder"), i18n("Add Bookmark Folder..."),
		this, TQT_SLOT(addBookmarkGroup()));

	if (item) {
		menu.insertSeparator();
		menu.insertItem(SmallIcon("edit"), i18n("Edit..."), 
			this, TQT_SLOT(editCurrentBookmark()));
		menu.insertItem(SmallIcon("editdelete"), i18n("Delete"),
			this, TQT_SLOT(deleteCurrentBookmark()));
	}
	menu.exec(TQCursor::pos());
}


void BookmarkViewController::bookmarkCurrentURL() {
	d->bookmarkURL(d->mCurrentURL);
}


void BookmarkViewController::addBookmarkGroup() {
	BookmarkDialog dialog(d->mListView, BookmarkDialog::BOOKMARK_GROUP);
	if (dialog.exec()==TQDialog::Rejected) return;

	KBookmarkGroup parentGroup=d->findBestParentGroup();
	KBookmarkGroup newGroup=parentGroup.createNewFolder(d->mManager, dialog.title());
	newGroup.internalElement().setAttribute("icon", dialog.icon());
	d->mManager->emitChanged(parentGroup);
	TQListViewItem* item=d->mListView->currentItem();
	if (item) {
		item->setOpen(true);
	}
}


void BookmarkViewController::editCurrentBookmark() {
	BookmarkItem* item=static_cast<BookmarkItem*>( d->mListView->currentItem() );
	Q_ASSERT(item);
	if (!item) return;
	KBookmark bookmark=item->mBookmark;
	bool isGroup=bookmark.isGroup();
	
	BookmarkDialog dialog(d->mListView,
		isGroup ? BookmarkDialog::BOOKMARK_GROUP : BookmarkDialog::BOOKMARK);

	dialog.setIcon(bookmark.icon());
	dialog.setTitle(bookmark.text());
	if (!isGroup) {
		dialog.setURL(bookmark.url().prettyURL());
	}
	if (dialog.exec()==TQDialog::Rejected) return;

	TQDomElement element=bookmark.internalElement();
	element.setAttribute("icon", dialog.icon());
	if (!isGroup) {
		element.setAttribute("href", dialog.url());
	}

	// Find title element (or create it if it does not exist)
	TQDomElement titleElement;
	TQDomNode tmp=element.namedItem("title");
	if (tmp.isNull()) {
		titleElement=element.ownerDocument().createElement("title");
		element.appendChild(titleElement);
	} else {
		titleElement=tmp.toElement();
	}
	Q_ASSERT(!titleElement.isNull());

	// Get title element content (or create)
	TQDomText titleText;
	tmp=titleElement.firstChild();
	if (tmp.isNull()) {
		titleText=element.ownerDocument().createTextNode("");
		titleElement.appendChild(titleText);
	} else {
		titleText=tmp.toText();
	}
	Q_ASSERT(!titleText.isNull());

	// Set title (at last!)
	titleText.setData(dialog.title());
	
	KBookmarkGroup group=bookmark.parentGroup();
	d->mManager->emitChanged(group);
}


void BookmarkViewController::deleteCurrentBookmark() {
	BookmarkItem* item=static_cast<BookmarkItem*>( d->mListView->currentItem() );
	Q_ASSERT(item);
	if (!item) return;
	KBookmark bookmark=item->mBookmark;

	TQString msg;
	TQString title;
	if (bookmark.isGroup()) {
		msg=i18n("Are you sure you want to delete the bookmark folder <b>%1</b>?<br>This will delete the folder and all the bookmarks in it.")
			.tqarg(bookmark.text());
		title=i18n("Delete Bookmark &Folder");
	} else {
		msg=i18n("Are you sure you want to delete the bookmark <b>%1</b>?")
			.tqarg(bookmark.text());
		title=i18n("Delete &Bookmark");
	}

	int response=KMessageBox::warningContinueCancel(d->mListView,
		"<qt>" + msg + "</qt>", title,
		KGuiItem(title, "editdelete")
		);
	if (response==KMessageBox::Cancel) return;
	
	KBookmarkGroup group=bookmark.parentGroup();
	group.deleteBookmark(bookmark);
	d->mManager->emitChanged(group);
}


} // namespace