/* -*- mode: c++; tab-width: 4; c-basic-offset: 4 -*- */
/*
 * Copyright (C) 2005 Atmark <atmarkat _AT_ msn _DOT_ com>
 *                    AGAWA Koji <i _AT_ atty _DOT_ jp>
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <qapplication.h>
#include <qvbox.h>
#include <qhgroupbox.h>
#include <qvgroupbox.h>
#include <qcombobox.h>
#include <qpushbutton.h>
#include <qradiobutton.h>
#include <qvbuttongroup.h>
#include <qlistview.h>
#include <qmessagebox.h>
#include <qlayout.h>

#include "hotkeyconfig.h"
#include "configuration.h"
#include "keynames.h"
#include "action.h"
#include "identifykeydialog.h"

//! ホットキー一覧のために属性を追加した QListViewItem です。
class HotKeyListItem : public QListViewItem
{
public:
	HotKeyListItem(int context, int key, const Action& action, QListView *parent)
		: QListViewItem(parent),
		  context_(context),
		  key_(key),
		  action_(action)
	{
		static const char *contextNames[] = {
			QT_TR_NOOP("Global"),
			QT_TR_NOOP("Playlist"),
			QT_TR_NOOP("Video"),
			QT_TR_NOOP("Audio")
		};
		setText(0, KeyNames::getName(key));
		setText(1, HotKeyConfig::tr(contextNames[context]));
		setText(2, action.translatedName());
	}

	int context() const { return context_; }
	int key() const { return key_; }
	const Action& action() const { return action_; }

private:
	int context_;
	int key_;
	const Action& action_;
};

HotKeyConfig::HotKeyConfig(Configuration& config, QWidget *parent, const char *name)
	: QWidget(parent, name),
	  config_(config),
	  allActions_(g_ActionManager.allActions()),
	  currentContext_(Configuration::HOTKEY_CONTEXT_GLOBAL),
	  lastKey_(-1)
{
	createWidgets();
	setStatesByConfiguration(config);
}

void HotKeyConfig::setStatesByConfiguration(const Configuration& config)
{
	if (&config != &config_)
		config_ = config;

	list->clear();

	for (int i = 0; i < Configuration::HOTKEY_CONTEXT_MAX; ++i) {
		for (Configuration::HotKeyMap::ConstIterator it = config.hotKeyMap[i].begin();
			 it != config.hotKeyMap[i].end();
			 ++it)
		{
			const Action& action(g_ActionManager.actionByAccel(it.data()));
			new HotKeyListItem(i, it.key(), action, list);
		}
	}
}

#include <qtabbar.h>

void HotKeyConfig::createWidgets()
{
	QVBoxLayout *mainLayout = new QVBoxLayout(this);

	actionCombo_ = new QComboBox(false, this);
	for (QListIterator<Action> it(allActions_); it.current(); ++it) {
		actionCombo_->insertItem(it.current()->translatedName());
	}
	mainLayout->addWidget(actionCombo_);

	QHBoxLayout *buttonLayout = new QHBoxLayout(this);
	
	QComboBox *contextList = new QComboBox(this);
	contextList->insertStringList(QStringList()
		<< tr("Global")
		<< tr("Playlist")
		<< tr("Video")
		<< tr("Audio")
	);
	connect(contextList, SIGNAL(activated(int)), this, SLOT(setContext(int)));
	keyButton_ = new QPushButton(tr("Scan key..."), this);
	connect(keyButton_, SIGNAL(clicked()), this, SLOT(identifyKey()));
	QPushButton *addButton = new QPushButton(tr("Add"), this);
	connect(addButton, SIGNAL(clicked()), this, SLOT(addHotKey()));
	QPushButton *removeButton = new QPushButton(tr("Remove"), this);
	connect(removeButton, SIGNAL(clicked()), this, SLOT(removeHotKey()));
	buttonLayout->addWidget(contextList);
	buttonLayout->addWidget(keyButton_);
	buttonLayout->addWidget(addButton);
	buttonLayout->addWidget(removeButton);
	mainLayout->addLayout(buttonLayout);

	// List
	list = new QListView(this);
	list->setAllColumnsShowFocus(true);
	list->addColumn(tr("Key"));
	list->addColumn(tr("Context"));
	list->addColumn(tr("Action"));
	mainLayout->addWidget(list);
}

void HotKeyConfig::identifyKey()
{
	IdentifyKeyDialog dialog(this);
	dialog.show();
	qApp->processEvents();
	if (dialog.exec() == QDialog::Accepted) {
		int key = dialog.key();
		if (key > 0) {
			keyButton_->setText(QString(tr("Key:")) + KeyNames::getName(key));
			lastKey_ = key;
		}
	}
}

//! 新しいホットキーを追加します。
void HotKeyConfig::addHotKey()
{
	const Action& action(*(allActions_.at(actionCombo_->currentItem())));

	if (lastKey_ < 0)
		return;

	// 新規登録するホットキーが既に設定されていないか検査する
	Configuration::HotKeyMap::Iterator it(config_.hotKeyMap[currentContext_].find(lastKey_));
	if (it != config_.hotKeyMap[currentContext_].end()) {
		// 既にホットキーが登録されているので、警告ダイアログを出す
		int ret =
			QMessageBox::warning(this, tr("Replace"),
								 tr("Replace a existed hotkey ?"),
								 QMessageBox::Yes, QMessageBox::Cancel);
		if (ret == 1)
			// ユーザーにより登録のキャンセルが選択されたので、何もせずにreturnする
			return;

		// 既存のキーマップからホットキーを削除
		config_.hotKeyMap[currentContext_].remove(it);

		// リストビューからホットキーの表示を削除
		for (QListViewItemIterator it(list); it.current(); ++it) {
			HotKeyListItem *item = static_cast<HotKeyListItem *>(it.current());
			if (currentContext_ == item->context() &&
				lastKey_ == item->key()) {
				delete item;
			}
		}
	}

	config_.hotKeyMap[currentContext_].insert(lastKey_, action.accel());

	new HotKeyListItem(currentContext_, lastKey_, action, list);
}

//! 選択されたホットキーを削除します。
void HotKeyConfig::removeHotKey()
{
	HotKeyListItem *item = static_cast<HotKeyListItem *>(list->currentItem());

	if (item) {
		if (config_.hotKeyMap[item->context()].contains(item->key())) {
			config_.hotKeyMap[item->context()].remove(item->key());
			delete item;
		}
	}
}
