Subversion Repositories Code-Repo

Rev

Rev 348 | Go to most recent revision | Blame | Last modification | View Log | RSS feed

#include "MacroController.h"

MacroController::MacroController(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");
    currKeyBindInfo = QPair<QPushButton*,int>(NULL, 0);

    mainLayout = new QGridLayout();

    macroCount = 0;
    connected = false;
    lastKnownFilePath = ".";

    ioLayout = new QHBoxLayout();
    ioLayout->addWidget(btnAddMacro);
    ioLayout->addWidget(btnRemoveMacro);
    ioLayout->addWidget(btnExport);
    ioLayout->addWidget(btnImport);
    ioLayout->addStretch();
    mainLayout->addLayout(ioLayout, 0, 0, 1, 2);

    for (int i = 0; i < MACRO_DEFAULT_COUNT; i++) {
        Macro_AddEntry();
    }

    setLayout(mainLayout);

    connect(btnAddMacro, SIGNAL(clicked()), this, SLOT(Macro_AddEntry()));
    connect(btnRemoveMacro, SIGNAL(clicked()), this, SLOT(Macro_RemoveEntry()));
    connect(btnExport, SIGNAL(clicked()), this, SLOT(Macro_WriteToFile()));
    connect(btnImport, SIGNAL(clicked()), this, SLOT(Macro_ReadFromFile()));
    connect(sigmapTransmit, SIGNAL(mapped(QWidget*)), this, SLOT(Macro_InitTransmit(QWidget*)));
    connect(sigmapKeybind, SIGNAL(mapped(int)), this, SLOT(Macro_KeybindPrompt(int)));
}

MacroController::~MacroController()
{

}

QSize MacroController::sizeHint() const
{
    return this->minimumSizeHint();
}

void MacroController::Macro_EnableTransmit()
{
    connected = true;
    for (int i = 0; i < macroBtnSendList.size(); i++) {
        macroBtnSendList[i]->setEnabled(true);
    }
}

void MacroController::Macro_DisableTransmit()
{
    connected = false;
    for (int i = 0; i < macroBtnSendList.size(); i++) {
        macroBtnSendList[i]->setEnabled(false);
    }
}

void MacroController::Macro_InitTransmit(QWidget *t)
{
    QTextEdit *text = qobject_cast<QTextEdit*>(t);
    emit Macro_TransmitText(text->toPlainText());
}

void MacroController::Macro_KeybindPrompt(int id)
{
    QPushButton *btn = qobject_cast<QPushButton*>(sigmapKeybind->mapping(id));
    btn->setDown(true);
    btn->setText("Waiting for Key..");
    currKeyBindInfo = QPair<QPushButton*,int>(btn, id);

    // Steal all following keyboard events
    btn->installEventFilter(this);
}

void MacroController::Macro_AddEntry()
{
    macroCount++;

    // Create new layout/widgets
    QLineEdit *lineEdit = new QLineEdit(QString("Macro %1").arg(macroCount));
    lineEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    lineEdit->setAlignment(Qt::AlignCenter | Qt::AlignTop);
    macroNameList.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);
    macroValueList.append(textEdit);

    QPushButton *keyButton = new QPushButton("Key: None");
    keyButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    macroBtnKeyList.append(keyButton);
    macroKeybindList.append(QKeySequence(Qt::Key_unknown));

    QPushButton *pushButton = new QPushButton("Send Macro");
    pushButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    pushButton->setEnabled(connected);
    macroBtnSendList.append(pushButton);

    QVBoxLayout *tmpLayout = new QVBoxLayout();
    tmpLayout->addWidget(lineEdit);
    tmpLayout->addWidget(keyButton);
    tmpLayout->addWidget(pushButton);

    // Add layout/widgets to main layout
    mainLayout->addLayout(tmpLayout, macroCount, 0);
    mainLayout->addWidget(textEdit, macroCount, 1);
    mainLayout->setColumnStretch(1, 1);

    // Associate KeyButton with its corresponding ID
    sigmapKeybind->setMapping(keyButton, macroCount-1);
    connect(keyButton, SIGNAL(clicked()), sigmapKeybind, SLOT(map()));

    // Associate PushButton with its corresponding TextEdit
    sigmapTransmit->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 MacroController::Macro_RemoveEntry()
{

    // Remove and delete layout/widgets at last macro slot
    QLayoutItem *item = mainLayout->itemAtPosition(macroCount, 0);
    while(!item->isEmpty())
        delete item->layout()->takeAt(0)->widget();
    delete item;

    item = mainLayout->itemAtPosition(macroCount, 1);
    delete item->widget();

    item = mainLayout->itemAtPosition(1, 1);
    int height = item->widget()->height() + mainLayout->verticalSpacing();

    // Unmap and remove widgets from lists
    QPushButton *pushButton = macroBtnSendList.back();
    sigmapTransmit->removeMappings(pushButton);

    QPushButton *keyButton = macroBtnKeyList.back();
    sigmapKeybind->removeMappings(keyButton);

    macroNameList.pop_back();
    macroValueList.pop_back();
    macroBtnSendList.pop_back();
    macroBtnKeyList.pop_back();
    macroKeybindList.pop_back();

    macroCount--;

    QDockWidget *parent = qobject_cast<QDockWidget*>(this->parent());
    if (parent->isFloating())
        parent->resize(parent->width(), parent->height() - height);

    if (macroCount == 1)
        btnRemoveMacro->setEnabled(false);
}

void MacroController::Macro_WriteToFile()
{
    QString file = QFileDialog::getSaveFileName(this, "Settings XML File", lastKnownFilePath, "XML File (*.xml)");
    QCoreApplication::processEvents(); // Wait for dialog to close

    if (file.size() == 0) return;

    // If file was selected, save directory for next time
    QFileInfo fileInfo = QFileInfo(file);
    lastKnownFilePath = fileInfo.absolutePath();

    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 < macroCount; i++) {
        stream.writeStartElement("Macro_Entry");

        stream.writeAttribute("Name", macroNameList[i]->text());
        stream.writeTextElement("Value", macroValueList[i]->toPlainText());

        stream.writeEndElement(); // Macro Entry
    }

    stream.writeEndElement(); // Macro
    stream.writeEndElement(); // Settings
    stream.writeEndDocument();

    inputFile.close();
}

void MacroController::Macro_ReadFromFile()
{
    int counter = 0;

    QString file = QFileDialog::getOpenFileName(this, "Settings XML File", lastKnownFilePath, "XML File (*.xml)");
    QCoreApplication::processEvents(); // Wait for dialog to close

    if (file.size() == 0) return;

    // If file was selected, save directory for next time
    QFileInfo 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 StartDocument
        if (token == QXmlStreamReader::StartDocument) continue;

        // Parse StartElements
        if (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;

                // Read and save attribute value
                QXmlStreamAttributes attr = stream.attributes();
                if (attr.hasAttribute("Name"))
                    name = attr.value("Name").toString();

                stream.readNext();

                // Loop in this element to find all sub-elements
                while (!(stream.tokenType() == QXmlStreamReader::EndElement && stream.name() == "Macro_Entry")) {

                    // Parse and save element value
                    if (stream.tokenType() == QXmlStreamReader::StartElement) {
                        if (stream.name() == "Value") {
                            stream.readNext();
                            value = stream.text().toString();
                        }
                    }
                    stream.readNext();
                }

                // Write values to GUI
                if (counter == macroCount)
                    Macro_AddEntry();

                macroNameList[counter]->setText(name);
                macroValueList[counter]->setText(value);
                counter++;
            }
        }
    }
}

bool MacroController::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *keyevent = static_cast<QKeyEvent*>(event);

        if (currKeyBindInfo.first != NULL) {
            // Ignore modifier keys
            if (keyevent->key() == Qt::Key_Shift || keyevent->key() == Qt::Key_Control ||
                keyevent->key() == Qt::Key_Meta || keyevent->key() == Qt::Key_Alt)
                return true;

            // Reset on ESC key
            if (keyevent->key() == Qt::Key_Escape) {
                macroKeybindList[currKeyBindInfo.second] = Qt::Key_unknown;
                currKeyBindInfo.first->setText("Key: None");
                currKeyBindInfo.first->setDown(false);
                currKeyBindInfo.first->removeEventFilter(this);
                currKeyBindInfo = QPair<QPushButton*, int>(NULL, 0);
                return true;
            }

            // Otherwise save key sequence
            QKeySequence seq = keyevent->modifiers() + keyevent->key();
            macroKeybindList[currKeyBindInfo.second] = seq;
            currKeyBindInfo.first->setText(seq.toString());
            currKeyBindInfo.first->setDown(false);
            currKeyBindInfo.first->removeEventFilter(this);
            currKeyBindInfo = QPair<QPushButton*, int>(NULL, 0);
        }
        return true;
    }

    return QWidget::eventFilter(obj, event);
}