123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- // This module implements the QsciMacro class.
- //
- // Copyright (c) 2017 Riverbank Computing Limited <info@riverbankcomputing.com>
- //
- // This file is part of QScintilla.
- //
- // This file may be used under the terms of the GNU General Public License
- // version 3.0 as published by the Free Software Foundation and appearing in
- // the file LICENSE included in the packaging of this file. Please review the
- // following information to ensure the GNU General Public License version 3.0
- // requirements will be met: http://www.gnu.org/copyleft/gpl.html.
- //
- // If you do not wish to use this file under the terms of the GPL version 3.0
- // then you may purchase a commercial license. For more information contact
- // info@riverbankcomputing.com.
- //
- // 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 "Qsci/qscimacro.h"
- #include <QStringList>
- #include "Qsci/qsciscintilla.h"
- static int fromHex(unsigned char ch);
- // The ctor.
- QsciMacro::QsciMacro(QsciScintilla *parent)
- : QObject(parent), qsci(parent)
- {
- }
- // The ctor that initialises the macro.
- QsciMacro::QsciMacro(const QString &asc, QsciScintilla *parent)
- : QObject(parent), qsci(parent)
- {
- load(asc);
- }
- // The dtor.
- QsciMacro::~QsciMacro()
- {
- }
- // Clear the contents of the macro.
- void QsciMacro::clear()
- {
- macro.clear();
- }
- // Read a macro from a string.
- bool QsciMacro::load(const QString &asc)
- {
- bool ok = true;
- macro.clear();
- QStringList fields = asc.split(' ');
- int f = 0;
- while (f < fields.size())
- {
- Macro cmd;
- unsigned len;
- // Extract the 3 fixed fields.
- if (f + 3 > fields.size())
- {
- ok = false;
- break;
- }
- cmd.msg = fields[f++].toUInt(&ok);
- if (!ok)
- break;
- cmd.wParam = fields[f++].toULong(&ok);
- if (!ok)
- break;
- len = fields[f++].toUInt(&ok);
- if (!ok)
- break;
- // Extract any text.
- if (len)
- {
- if (f + 1 > fields.size())
- {
- ok = false;
- break;
- }
- QByteArray ba = fields[f++].toLatin1();
- const char *sp = ba.data();
- if (!sp)
- {
- ok = false;
- break;
- }
- // Because of historical bugs the length field is unreliable.
- bool embedded_null = false;
- unsigned char ch;
- while ((ch = *sp++) != '\0')
- {
- if (ch == '"' || ch <= ' ' || ch >= 0x7f)
- {
- ok = false;
- break;
- }
- if (ch == '\\')
- {
- int b1, b2;
- if ((b1 = fromHex(*sp++)) < 0 ||
- (b2 = fromHex(*sp++)) < 0)
- {
- ok = false;
- break;
- }
- ch = (b1 << 4) + b2;
- }
- if (ch == '\0')
- {
- // Don't add it now as it may be the terminating '\0'.
- embedded_null = true;
- }
- else
- {
- if (embedded_null)
- {
- // Add the pending embedded '\0'.
- cmd.text += '\0';
- embedded_null = false;
- }
- cmd.text += ch;
- }
- }
- if (!ok)
- break;
- }
- macro.append(cmd);
- }
-
- if (!ok)
- macro.clear();
- return ok;
- }
- // Write a macro to a string.
- QString QsciMacro::save() const
- {
- QString ms;
- QList<Macro>::const_iterator it;
- for (it = macro.begin(); it != macro.end(); ++it)
- {
- if (!ms.isEmpty())
- ms += ' ';
- unsigned len = (*it).text.size();
- QString m;
- ms += m.sprintf("%u %lu %u", (*it).msg, (*it).wParam, len);
- if (len)
- {
- // In Qt v3, if the length is greater than zero then it also
- // includes the '\0', so we need to make sure that Qt v4 writes the
- // '\0'. That the '\0' is written at all is a bug because
- // QCString::size() is used instead of QCString::length(). We
- // don't fix this so as not to break old macros. However this is
- // still broken because we have already written the unadjusted
- // length. So, in summary, the length field should be interpreted
- // as a zero/non-zero value, and the end of the data is either at
- // the next space or the very end of the data.
- ++len;
- ms += ' ';
- const char *cp = (*it).text.data();
- while (len--)
- {
- unsigned char ch = *cp++;
- if (ch == '\\' || ch == '"' || ch <= ' ' || ch >= 0x7f)
- {
- QString buf;
- ms += buf.sprintf("\\%02x", ch);
- }
- else
- ms += ch;
- }
- }
- }
- return ms;
- }
- // Play the macro.
- void QsciMacro::play()
- {
- if (!qsci)
- return;
- QList<Macro>::const_iterator it;
- for (it = macro.begin(); it != macro.end(); ++it)
- qsci->SendScintilla((*it).msg, (*it).wParam, (*it).text.data());
- }
- // Start recording.
- void QsciMacro::startRecording()
- {
- if (!qsci)
- return;
- macro.clear();
- connect(qsci, SIGNAL(SCN_MACRORECORD(unsigned int, unsigned long, void *)),
- SLOT(record(unsigned int, unsigned long, void *)));
- qsci->SendScintilla(QsciScintillaBase::SCI_STARTRECORD);
- }
- // End recording.
- void QsciMacro::endRecording()
- {
- if (!qsci)
- return;
- qsci->SendScintilla(QsciScintillaBase::SCI_STOPRECORD);
- qsci->disconnect(this);
- }
- // Record a command.
- void QsciMacro::record(unsigned int msg, unsigned long wParam, void *lParam)
- {
- Macro m;
- m.msg = msg;
- m.wParam = wParam;
- // Determine commands which need special handling of the parameters.
- switch (msg)
- {
- case QsciScintillaBase::SCI_ADDTEXT:
- m.text = QByteArray(reinterpret_cast<const char *>(lParam), wParam);
- break;
- case QsciScintillaBase::SCI_REPLACESEL:
- if (!macro.isEmpty() && macro.last().msg == QsciScintillaBase::SCI_REPLACESEL)
- {
- // This is the command used for ordinary user input so it's a
- // significant space reduction to append it to the previous
- // command.
- macro.last().text.append(reinterpret_cast<const char *>(lParam));
- return;
- }
- /* Drop through. */
- case QsciScintillaBase::SCI_INSERTTEXT:
- case QsciScintillaBase::SCI_APPENDTEXT:
- case QsciScintillaBase::SCI_SEARCHNEXT:
- case QsciScintillaBase::SCI_SEARCHPREV:
- m.text.append(reinterpret_cast<const char *>(lParam));
- break;
- }
- macro.append(m);
- }
- // Return the given hex character as a binary.
- static int fromHex(unsigned char ch)
- {
- if (ch >= '0' && ch <= '9')
- return ch - '0';
- if (ch >= 'a' && ch <= 'f')
- return ch - 'a' + 10;
- return -1;
- }
|