Rev 372 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
#include "MacroWidget.h"MacroWidget::MacroWidget(QWidget *parent) : QWidget(parent){sigmapTransmit = new QSignalMapper();sigmapKeybind = new QSignalMapper();btnExport = new QPushButton("Export");btnImport = new QPushButton("Import");btnAddMacro = new QPushButton("&Add");btnRemoveMacro = new QPushButton("&Remove");btnClear = new QPushButton("&Clear");currKeyBindInfo = QPair<QPushButton*,int>(NULL, 0);mainLayout = new QGridLayout();count = 0;connected = false;lastKnownFilePath = ".";ioLayout = new QHBoxLayout();ioLayout->addWidget(btnAddMacro);ioLayout->addWidget(btnRemoveMacro);ioLayout->addWidget(btnClear);ioLayout->addWidget(btnExport);ioLayout->addWidget(btnImport);ioLayout->addStretch();mainLayout->addLayout(ioLayout, 0, 0, 1, 2);for (int i = 0; i < MACRO_DEFAULT_COUNT; i++) {AddEntry();}setLayout(mainLayout);connect(btnAddMacro, SIGNAL(clicked()), this, SLOT(AddEntry()));connect(btnRemoveMacro, SIGNAL(clicked()), this, SLOT(RemoveEntry()));connect(btnClear, SIGNAL(clicked()), this, SLOT(Clear()));connect(btnExport, SIGNAL(clicked()), this, SLOT(WriteToFile()));connect(btnImport, SIGNAL(clicked()), this, SLOT(ReadFromFile()));connect(sigmapTransmit, SIGNAL(mapped(QWidget*)), this, SLOT(InitTransmit(QWidget*)));connect(sigmapKeybind, SIGNAL(mapped(int)), this, SLOT(KeybindPrompt(int)));// Register global event process for keyboard shortcut handlingqApp->installEventFilter(this);}MacroWidget::~MacroWidget(){}QSize MacroWidget::sizeHint() const{return this->minimumSizeHint();}void MacroWidget::EnableTransmit(bool enable){if (enable) {connected = true;for (int i = 0; i < btnSendList.size(); i++) {btnSendList[i]->setEnabled(true);}} else {connected = false;for (int i = 0; i < btnSendList.size(); i++) {btnSendList[i]->setEnabled(false);}}}void MacroWidget::InitTransmit(QWidget *t){if (connected) {QTextEdit *text = qobject_cast<QTextEdit*>(t);emit TransmitText(text->toPlainText().toUtf8());}}void MacroWidget::KeybindPrompt(int id){QPushButton *btn = qobject_cast<QPushButton*>(sigmapKeybind->mapping(id));// Check to make sure we arn't processing another key firstif (currKeyBindInfo.first != NULL) {currKeyBindInfo.first->setText("Hotkey: None");currKeyBindInfo.first->setDown(false);currKeyBindInfo.first->removeEventFilter(this);}// Mark and save button as waiting for key sequencebtn->setDown(true);btn->setText("Waiting for Key..");currKeyBindInfo = QPair<QPushButton*,int>(btn, id);// Remove current keybinding for this macroint index = registeredKeyMacroIDs.indexOf(id);if (index >= 0) {registeredKeySequences.removeAt(index);registeredKeyMacroIDs.removeAt(index);}// Inspect all following keyboard eventsbtn->installEventFilter(this);}void MacroWidget::AddEntry(){count++;// Create new layout/widgetsQLineEdit *lineEdit = new QLineEdit(QString("Macro %1").arg(count));lineEdit->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);lineEdit->setMinimumWidth(100);lineEdit->setAlignment(Qt::AlignCenter);nameList.append(lineEdit);QTextEdit *textEdit = new QTextEdit();textEdit->setMinimumHeight(50);textEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);textEdit->setWordWrapMode(QTextOption::NoWrap);textEdit->setFont(QFont("Consolas", 8));textEdit->setAcceptRichText(false);textEdit->setTabChangesFocus(true);valueList.append(textEdit);QPushButton *keyButton = new QPushButton("Hotkey: None");keyButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);btnKeyList.append(keyButton);QPushButton *pushButton = new QPushButton("Send Macro");pushButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);pushButton->setEnabled(connected);btnSendList.append(pushButton);QVBoxLayout *tmpLayout = new QVBoxLayout();tmpLayout->addWidget(lineEdit);tmpLayout->addWidget(keyButton);tmpLayout->addWidget(pushButton);// Add layout/widgets to main layoutmainLayout->addLayout(tmpLayout, count, 0);mainLayout->addWidget(textEdit, count, 1);mainLayout->setColumnStretch(1, 1);// Associate KeyButton with its corresponding IDsigmapKeybind->setMapping(keyButton, count-1);connect(keyButton, SIGNAL(clicked()), sigmapKeybind, SLOT(map()));// Associate PushButton with its corresponding TextEditsigmapTransmit->setMapping(pushButton, textEdit);connect(pushButton, SIGNAL(clicked()), sigmapTransmit, SLOT(map()));QLayoutItem *item = mainLayout->itemAtPosition(1, 1);int height = item->widget()->height() + mainLayout->verticalSpacing();QDockWidget *parent = qobject_cast<QDockWidget*>(this->parent());if (parent->isFloating())parent->resize(parent->width(), parent->height() + height);btnRemoveMacro->setEnabled(true);}void MacroWidget::RemoveEntry(){// Remove and delete layout/widgets at last macro slotQLayoutItem *item = mainLayout->itemAtPosition(count, 0);while(!item->isEmpty())delete item->layout()->takeAt(0)->widget();delete item;item = mainLayout->itemAtPosition(count, 1);delete item->widget();item = mainLayout->itemAtPosition(1, 1);int height = item->widget()->height() + mainLayout->verticalSpacing();// Unmap and remove widgets from listsQPushButton *pushButton = btnSendList.back();sigmapTransmit->removeMappings(pushButton);QPushButton *keyButton = btnKeyList.back();sigmapKeybind->removeMappings(keyButton);nameList.pop_back();valueList.pop_back();btnSendList.pop_back();btnKeyList.pop_back();int index = registeredKeyMacroIDs.indexOf(count-1);if (index >= 0) {registeredKeySequences.removeAt(index);registeredKeyMacroIDs.removeAt(index);}count--;QDockWidget *parent = qobject_cast<QDockWidget*>(this->parent());if (parent->isFloating())parent->resize(parent->width(), parent->height() - height);if (count == 1)btnRemoveMacro->setEnabled(false);}void MacroWidget::Clear(){for (int i = 0; i < count; i++) {nameList[i]->setText(QString("Macro %1").arg(i+1));valueList[i]->clear();btnKeyList[i]->setText("Hotkey: None");}registeredKeyMacroIDs.clear();registeredKeySequences.clear();}void MacroWidget::WriteToFile(){QString file = QFileDialog::getSaveFileName(this, "Settings XML File", lastKnownFilePath, "XML File (*.xml)");QCoreApplication::processEvents(); // Wait for dialog to closeif (file.size() == 0) return;// If file was selected, save directory for next timeQFileInfo fileInfo = QFileInfo(file);lastKnownFilePath = fileInfo.absolutePath();if (file.size() != 0)QFile::remove(file);QFile inputFile(file);if (!inputFile.open(QIODevice::ReadWrite | QIODevice::Text)) return;QXmlStreamWriter stream(&inputFile);stream.setAutoFormatting(true);stream.writeStartDocument();stream.writeStartElement("Settings");stream.writeStartElement("Macro");for (int i = 0; i < count; i++) {stream.writeStartElement("Macro_Entry");stream.writeAttribute("Name", nameList[i]->text());stream.writeTextElement("Value", valueList[i]->toPlainText());int index = registeredKeyMacroIDs.indexOf(i);if (index >= 0) {stream.writeTextElement("Keybinding", registeredKeySequences[index].toString());} else {stream.writeTextElement("Keybinding", "");}stream.writeEndElement(); // Macro Entry}stream.writeEndElement(); // Macrostream.writeEndElement(); // Settingsstream.writeEndDocument();inputFile.close();}void MacroWidget::ReadFromFile(){int counter = 0;QString file = QFileDialog::getOpenFileName(this, "Settings XML File", lastKnownFilePath, "XML File (*.xml)");QCoreApplication::processEvents(); // Wait for dialog to closeif (file.size() == 0) return;Clear();// If file was selected, save directory for next timeQFileInfo fileInfo = QFileInfo(file);lastKnownFilePath = fileInfo.absolutePath();QFile inputFile(file);if (!inputFile.open(QIODevice::ReadWrite | QIODevice::Text)) return;QXmlStreamReader stream(&inputFile);// Parse the XML file till we reach the end (or errors)while (!stream.atEnd() && !stream.hasError()) {QXmlStreamReader::TokenType token = stream.readNext();// Ignore StartDocumentif (token == QXmlStreamReader::StartDocument) continue;// Parse StartElementsif (token == QXmlStreamReader::StartElement) {// Ignore elements <Settings> and <Macro>if (stream.name() == "Settings") continue;if (stream.name() == "Macro") continue;// Parse element <Macro_Entry>if (stream.name() == "Macro_Entry") {QString name, value, keybinding;// Read and save attribute valueQXmlStreamAttributes attr = stream.attributes();if (attr.hasAttribute("Name"))name = attr.value("Name").toString();stream.readNext();// Loop in this element to find all sub-elementswhile (!(stream.tokenType() == QXmlStreamReader::EndElement && stream.name() == "Macro_Entry")) {// Parse and save element valueif (stream.tokenType() == QXmlStreamReader::StartElement) {if (stream.name() == "Value") {stream.readNext();value = stream.text().toString();}if (stream.name() == "Keybinding") {stream.readNext();keybinding = stream.text().toString();}}stream.readNext();}// Write values to GUIif (counter == count)AddEntry();nameList[counter]->setText(name);valueList[counter]->setText(value);if (keybinding != "") {registeredKeySequences.append(QKeySequence(keybinding));registeredKeyMacroIDs.append(counter);btnKeyList[counter]->setText("Hotkey: " + keybinding);}counter++;}}}}bool MacroWidget::eventFilter(QObject *obj, QEvent *event){// Only process keyboard eventsif (event->type() == QEvent::KeyPress) {QKeyEvent *keyevent = static_cast<QKeyEvent*>(event);QKeySequence seq = keyevent->modifiers() + keyevent->key();if ((keyevent->key() >= 0x21 && keyevent->key() <= 0x2F) ||(keyevent->key() >= 0x3A && keyevent->key() <= 0x40) ||(keyevent->key() >= 0x5E && keyevent->key() <= 0x7E) ) {seq = keyevent->key();}if (connected) {// First check if key sequence matches any saved onesif (!registeredKeySequences.isEmpty()) {int index = registeredKeySequences.indexOf(seq);if (index >= 0) {InitTransmit(valueList[registeredKeyMacroIDs[index]]);return true;}}}// Then save key sequence if neededif (currKeyBindInfo.first != NULL) {// Ignore modifier keys and locksif (keyevent->key() == Qt::Key_Shift || keyevent->key() == Qt::Key_Control ||keyevent->key() == Qt::Key_Meta || keyevent->key() == Qt::Key_Alt ||keyevent->key() == Qt::Key_AltGr || keyevent->key() == Qt::Key_CapsLock ||keyevent->key() == Qt::Key_NumLock || keyevent->key() == Qt::Key_ScrollLock)return true;// Reset on ESC keyif (keyevent->key() == Qt::Key_Escape) {currKeyBindInfo.first->setText("Hotkey: None");currKeyBindInfo.first->setDown(false);currKeyBindInfo.first->removeEventFilter(this);currKeyBindInfo = QPair<QPushButton*, int>(NULL, 0);return true;}// Otherwise save key sequence if it doesnt already existif (!registeredKeySequences.contains(seq)) {registeredKeySequences.append(seq);registeredKeyMacroIDs.append(currKeyBindInfo.second);currKeyBindInfo.first->setText("Hotkey: " + seq.toString());currKeyBindInfo.first->setDown(false);currKeyBindInfo.first->removeEventFilter(this);currKeyBindInfo = QPair<QPushButton*, int>(NULL, 0);return true;}}}return QWidget::eventFilter(obj, event);}