/*  smplayer, GUI front-end for mplayer.
    Copyright (C) 2006-2017 Ricardo Villalba <rvm@users.sourceforge.net>

    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

    Note: The ShortcutGetter class is taken from the source code of Edyuk
    (http://www.edyuk.org/), from file 3rdparty/qcumber/qshortcutdialog.cpp

    Copyright (C) 2006 FullMetalCoder
    License: GPL

    I modified it to support multiple shortcuts and some other few changes.
*/


/****************************************************************************
**
** Copyright (C) 2006 FullMetalCoder
**
** This file is part of the Edyuk project (beta version)
** 
** This file may be used under the terms of the GNU General Public License
** version 2 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** Notes :	Parts of the project are derivative work of Trolltech's QSA library
** or Trolltech's Qt4 framework but, unless notified, every single line of code
** is the work of the Edyuk team or a contributor. 
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/


#include "shortcutgetter.h"
#include "images.h"

#include <QLayout>
#include <QHash>
#include <QLabel>
#include <QString>
#include <QShortcut>
#include <QLineEdit>
#include <QKeyEvent>
#include <QPushButton>
#include <QDialogButtonBox>

#if 1

static QHash<int, const char*> keyMap;

static void initKeyMap()
{
	if ( !keyMap.isEmpty() )
		return;
	
	/*
		I'm a bit unsure about these one...
	*/
	keyMap[Qt::Key_Escape] = "Escape";
	keyMap[Qt::Key_Return] = "Return";
	keyMap[Qt::Key_Enter] = "Enter";
	keyMap[Qt::Key_Insert] = "Ins";
	keyMap[Qt::Key_Delete] = "Delete";
	keyMap[Qt::Key_Home] = "Home";
	keyMap[Qt::Key_End] = "End";
	keyMap[Qt::Key_Left] = "Left";
	keyMap[Qt::Key_Up] = "Up";
	keyMap[Qt::Key_Right] = "Right";
	keyMap[Qt::Key_Down] = "Down";
	keyMap[Qt::Key_PageUp] = "PgUp";
	keyMap[Qt::Key_PageDown] = "PgDown";
	keyMap[Qt::Key_CapsLock] = "CapsLock";
	keyMap[Qt::Key_NumLock] = "NumLock";
	keyMap[Qt::Key_ScrollLock] = "ScrollLock";
	
	/*
		These one are quite sure...
	*/
	keyMap[Qt::Key_F1] = "F1";
	keyMap[Qt::Key_F2] = "F2";
	keyMap[Qt::Key_F3] = "F3";
	keyMap[Qt::Key_F4] = "F4";
	keyMap[Qt::Key_F5] = "F5";
	keyMap[Qt::Key_F6] = "F6";
	keyMap[Qt::Key_F7] = "F7";
	keyMap[Qt::Key_F8] = "F8";
	keyMap[Qt::Key_F9] = "F9";
	keyMap[Qt::Key_F10] = "F10";
	keyMap[Qt::Key_F11] = "F11";
	keyMap[Qt::Key_F12] = "F12";
	keyMap[Qt::Key_F13] = "F13";
	keyMap[Qt::Key_F14] = "F14";
	keyMap[Qt::Key_F15] = "F15";
	keyMap[Qt::Key_F16] = "F16";
	keyMap[Qt::Key_F17] = "F17";
	keyMap[Qt::Key_F18] = "F18";
	keyMap[Qt::Key_F19] = "F19";
	keyMap[Qt::Key_F20] = "F20";
	keyMap[Qt::Key_F21] = "F21";
	keyMap[Qt::Key_F22] = "F22";
	keyMap[Qt::Key_F23] = "F23";
	keyMap[Qt::Key_F24] = "F24";
	keyMap[Qt::Key_F25] = "F25";
	keyMap[Qt::Key_F26] = "F26";
	keyMap[Qt::Key_F27] = "F27";
	keyMap[Qt::Key_F28] = "F28";
	keyMap[Qt::Key_F29] = "F29";
	keyMap[Qt::Key_F30] = "F30";
	keyMap[Qt::Key_F31] = "F31";
	keyMap[Qt::Key_F32] = "F32";
	keyMap[Qt::Key_F33] = "F33";
	keyMap[Qt::Key_F34] = "F34";
	keyMap[Qt::Key_F35] = "F35";
	
	keyMap[Qt::Key_Exclam] = "!";
	keyMap[Qt::Key_QuoteDbl] = "\"";
	keyMap[Qt::Key_NumberSign] = "-";
	keyMap[Qt::Key_Dollar] = "$";
	keyMap[Qt::Key_Percent] = "%";
	keyMap[Qt::Key_Ampersand] = "&amp;";
	keyMap[Qt::Key_Apostrophe] = "\'";
	keyMap[Qt::Key_ParenLeft] = "(";
	keyMap[Qt::Key_ParenRight] = ")";
	keyMap[Qt::Key_Asterisk] = "*";
	keyMap[Qt::Key_Plus] = "+";
	keyMap[Qt::Key_Comma] = ",";
	keyMap[Qt::Key_Minus] = "-";
	keyMap[Qt::Key_Period] = "Period";
	keyMap[Qt::Key_Slash] = "/";
	
	keyMap[Qt::Key_0] = "0";
	keyMap[Qt::Key_1] = "1";
	keyMap[Qt::Key_2] = "2";
	keyMap[Qt::Key_3] = "3";
	keyMap[Qt::Key_4] = "4";
	keyMap[Qt::Key_5] = "5";
	keyMap[Qt::Key_6] = "6";
	keyMap[Qt::Key_7] = "7";
	keyMap[Qt::Key_8] = "8";
	keyMap[Qt::Key_9] = "9";
	
	keyMap[Qt::Key_Colon] = ":";
	keyMap[Qt::Key_Semicolon] = ";";
	keyMap[Qt::Key_Less] = "<";
	keyMap[Qt::Key_Equal] = "=";
	keyMap[Qt::Key_Greater] = ">";
	keyMap[Qt::Key_Question] = "?";
	keyMap[Qt::Key_At] = "@";
	
	keyMap[Qt::Key_A] = "A";
	keyMap[Qt::Key_B] = "B";
	keyMap[Qt::Key_C] = "C";
	keyMap[Qt::Key_D] = "D";
	keyMap[Qt::Key_E] = "E";
	keyMap[Qt::Key_F] = "F";
	keyMap[Qt::Key_G] = "G";
	keyMap[Qt::Key_H] = "H";
	keyMap[Qt::Key_I] = "I";
	keyMap[Qt::Key_J] = "J";
	keyMap[Qt::Key_K] = "K";
	keyMap[Qt::Key_L] = "L";
	keyMap[Qt::Key_M] = "M";
	keyMap[Qt::Key_N] = "N";
	keyMap[Qt::Key_O] = "O";
	keyMap[Qt::Key_P] = "P";
	keyMap[Qt::Key_Q] = "Q";
	keyMap[Qt::Key_R] = "R";
	keyMap[Qt::Key_S] = "S";
	keyMap[Qt::Key_T] = "T";
	keyMap[Qt::Key_U] = "U";
	keyMap[Qt::Key_V] = "V";
	keyMap[Qt::Key_W] = "W";
	keyMap[Qt::Key_X] = "X";
	keyMap[Qt::Key_Y] = "Y";
	keyMap[Qt::Key_Z] = "Z";
	
	keyMap[Qt::Key_BracketLeft] = "[";
	keyMap[Qt::Key_Backslash] = "\\";
	keyMap[Qt::Key_BracketRight] = "]";
	
	keyMap[Qt::Key_Underscore] = "_";
	keyMap[Qt::Key_BraceLeft] = "{";
	keyMap[Qt::Key_Bar] = "|";
	keyMap[Qt::Key_BraceRight] = "}";
	keyMap[Qt::Key_AsciiTilde] = "~";

	// Added by rvm:
	keyMap[Qt::Key_Space] = "Space";
	keyMap[Qt::Key_Backspace] = "Backspace";
	keyMap[Qt::Key_MediaPlay] = "Media Play";
	keyMap[Qt::Key_MediaStop] = "Media Stop";
	keyMap[Qt::Key_MediaPrevious] = "Media Previous";
	keyMap[Qt::Key_MediaNext] = "Media Next";
	keyMap[Qt::Key_MediaRecord] = "Media Record";
	keyMap[Qt::Key_MediaLast] = "Media Last"; // doesn't work?
	keyMap[Qt::Key_VolumeUp] = "Volume Up";
	keyMap[Qt::Key_VolumeDown] = "Volume Down";
	keyMap[Qt::Key_VolumeMute] = "Volume Mute";	
	keyMap[Qt::Key_Back] = "Back";	
	keyMap[Qt::Key_Forward] = "Forward";	
	keyMap[Qt::Key_Stop] = "Stop";
}

static QString keyToString(int k)
{
	if (	k == Qt::Key_Shift || k == Qt::Key_Control || k == Qt::Key_Meta ||
			k == Qt::Key_Alt || k == Qt::Key_AltGr )
		return QString::null;

	initKeyMap();
	
	return keyMap[k];
}

#else

static QString keyToString(int k)
{
	if (	k == Qt::Key_Shift || k == Qt::Key_Control || k == Qt::Key_Meta ||
			k == Qt::Key_Alt || k == Qt::Key_AltGr )
		return QString::null;

	return QKeySequence(k).toString();
}

#endif

static QStringList modToString(Qt::KeyboardModifiers k)
{
	//qDebug("modToString: k: %x", (int) k);

	QStringList l;
	
	if ( k & Qt::ShiftModifier )
		l << "Shift";
	if ( k & Qt::ControlModifier )
		l << "Ctrl";
	if ( k & Qt::AltModifier )
		l << "Alt";
	if ( k & Qt::MetaModifier )
		l << "Meta";
	if ( k & Qt::GroupSwitchModifier )
		;
	if ( k & Qt::KeypadModifier )
		;
	
	return l;
}


ShortcutGetter::ShortcutGetter(QWidget *parent) : QDialog(parent)
{
	setWindowTitle(tr("Modify shortcut"));

	QVBoxLayout *vbox = new QVBoxLayout(this);
	vbox->setMargin(2);
	vbox->setSpacing(4);

	// List and buttons added by rvm
	list = new QListWidget(this);
	connect(list, SIGNAL(currentRowChanged(int)), this, SLOT(rowChanged(int)));
	vbox->addWidget(list);

	QHBoxLayout *hbox = new QHBoxLayout;
	addItem = new QPushButton(Images::icon("plus"), "", this);
	addItem->setToolTip(tr("Add shortcut"));
	connect(addItem, SIGNAL(clicked()), this, SLOT(addItemClicked()));

	removeItem = new QPushButton(Images::icon("minus"), "", this);
	removeItem->setToolTip(tr("Remove shortcut"));
	connect(removeItem, SIGNAL(clicked()), this, SLOT(removeItemClicked()));

	hbox->addSpacerItem(new QSpacerItem(20, 20, QSizePolicy::Expanding));
	hbox->addWidget(addItem);
	hbox->addWidget(removeItem);

	vbox->addLayout(hbox);

	QLabel *l = new QLabel(this);
	l->setText(tr("Press the key combination you want to assign"));
	vbox->addWidget(l);

	leKey = new QLineEdit(this);
	connect(leKey, SIGNAL(textChanged(const QString &)), this, SLOT(textChanged(const QString &)));

	leKey->installEventFilter(this);
	vbox->addWidget(leKey);

	// Change by rvm: use a QDialogButtonBox instead of QPushButtons
	// and add a clear button
	setCaptureKeyboard(true);
	QDialogButtonBox * buttonbox = new QDialogButtonBox(QDialogButtonBox::Ok |
                                                     QDialogButtonBox::Cancel | 
                                                     QDialogButtonBox::Reset );
	QPushButton * clearbutton = buttonbox->button(QDialogButtonBox::Reset);
	clearbutton->setText( tr("Clear") );

	QPushButton * captureButton = new QPushButton(tr("Capture"), this);
	captureButton->setToolTip( tr("Capture keystrokes") );
	captureButton->setCheckable( captureKeyboard() );
	captureButton->setChecked( captureKeyboard() );
	connect(captureButton, SIGNAL(toggled(bool)), 
            this, SLOT(setCaptureKeyboard(bool)));


	buttonbox->addButton(captureButton, QDialogButtonBox::ActionRole);

	connect( buttonbox, SIGNAL(accepted()), this, SLOT(accept()) );
	connect( buttonbox, SIGNAL(rejected()), this, SLOT(reject()) );
	connect( clearbutton, SIGNAL(clicked()), leKey, SLOT(clear()) );
	vbox->addWidget(buttonbox);
}

void ShortcutGetter::setCaptureKeyboard(bool b) { 
	capture = b; 
	leKey->setReadOnly(b);
	leKey->setFocus();
}

// Added by rvm
void ShortcutGetter::rowChanged(int row) {
	QString s = list->item(row)->text();
	leKey->setText(s);
	leKey->setFocus();
}

// Added by rvm
void ShortcutGetter::textChanged(const QString & text) {
	list->item(list->currentRow())->setText(text);
}

// Added by rvm
void ShortcutGetter::addItemClicked() {
	qDebug("ShortcutGetter::addItemClicked");
	list->addItem("");
	list->setCurrentRow( list->count()-1 ); // Select last item
}

// Added by rvm
void ShortcutGetter::removeItemClicked() {
	qDebug("ShortcutGetter::removeItemClicked");
	if (list->count() > 1) {
		QListWidgetItem * i = list->takeItem( list->currentRow() );
		if (i) delete i;
	} else {
		list->setCurrentRow(0);
		leKey->setText("");
	}
}

QString ShortcutGetter::exec(const QString& s)
{
	// Added by rvm
	QStringList shortcuts = s.split(", ");
	QString shortcut;
	foreach(shortcut, shortcuts) {
		list->addItem(shortcut.trimmed());
	}
	list->setCurrentRow(0);

	bStop = false;

	if (QDialog::exec() == QDialog::Accepted) {
		// Added by rvm
		QStringList l;
		for (int n = 0; n < list->count(); n++) {
			QString shortcut = list->item(n)->text();
			if (!shortcut.isEmpty()) {
				//qDebug("ShortcutGetter::exec: shortcut: '%s'", shortcut.toUtf8().constData());
				l << shortcut;
			}
		}
		QString res = l.join(", ");
		if (res.isNull()) res = "";
		return res;
	}

	return QString();
}

bool ShortcutGetter::event(QEvent *e)
{
	if (!capture) return QDialog::event(e);

	QString key;
	QStringList mods;
	QKeyEvent *k = static_cast<QKeyEvent*>(e);
			
	switch ( e->type() )
	{
		case QEvent::KeyPress :
					
		if ( bStop )
		{
			lKeys.clear();
			bStop = false;
		}

		key = keyToString(k->key());
		mods = modToString(k->modifiers());

		//qDebug("event: key.count: %d, mods.count: %d", key.count(), mods.count());

		if ( key.count() || mods.count() )
		{
						
			if ( key.count() && !lKeys.contains(key) )
				lKeys << key;
						
			foreach ( key, mods )
				if ( !lKeys.contains(key) )
					lKeys << key;
			
			} else {
				key = k->text();
						
				if ( !lKeys.contains(key) )
					lKeys << key;
			}
					
			setText();
			break;
					
		case QEvent::KeyRelease :
					
			bStop = true;
			break;
					
			/*
		case QEvent::ShortcutOverride :
			leKey->setText("Shortcut override");
			break;
			*/
					
		default:
			return QDialog::event(e);
			break;
	}
	
	return true;
}
		
bool ShortcutGetter::eventFilter(QObject *o, QEvent *e)
{
	if (!capture) return QDialog::eventFilter(o, e);

	if (	e->type() == QEvent::KeyPress ||
			e->type() ==QEvent::KeyRelease )
		return event(e);
	else
		return QDialog::eventFilter(o, e);
}
		
void ShortcutGetter::setText()
{
	QStringList seq;
			
	if ( lKeys.contains("Shift") )
		seq << "Shift";
			
	if ( lKeys.contains("Ctrl") )
		seq << "Ctrl";
				
	if ( lKeys.contains("Alt") )
		seq << "Alt";
			
	if ( lKeys.contains("Meta") )
		seq << "Meta";
			
	foreach ( QString s, lKeys ) {
		//qDebug("setText: s: '%s'", s.toUtf8().data());
		if ( s != "Shift" && s != "Ctrl"
			&& s != "Alt" && s != "Meta" )
			seq << s;
	}
			
	leKey->setText(seq.join("+"));
	//leKey->selectAll();
}
		
#include "moc_shortcutgetter.cpp"
