diff options
Diffstat (limited to 'kommander/widget/kommanderwidget.cpp')
-rw-r--r-- | kommander/widget/kommanderwidget.cpp | 745 |
1 files changed, 745 insertions, 0 deletions
diff --git a/kommander/widget/kommanderwidget.cpp b/kommander/widget/kommanderwidget.cpp new file mode 100644 index 00000000..525f662b --- /dev/null +++ b/kommander/widget/kommanderwidget.cpp @@ -0,0 +1,745 @@ +/*************************************************************************** + kommanderwidget.cpp - Text widget core functionality + ------------------- + copyright : (C) 2002-2003 Marc Britton <[email protected]> + (C) 2004 Michal Rudolf <[email protected]> + + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + + + /* KDE INCLUDES */ +#include <dcopclient.h> +#include <kapplication.h> +#include <kdebug.h> +#include <klocale.h> +#include <kdialogbase.h> +#include <kmessagebox.h> +#include <kprocess.h> + +/* QT INCLUDES */ +#include <qcstring.h> +#include <qdatastream.h> +#include <qfileinfo.h> +#include <qobject.h> +#include <qobjectlist.h> +#include <qregexp.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qvaluelist.h> +#include <qvariant.h> + + +/* UNIX INCLUDES */ +#include <unistd.h> +#include <stdlib.h> + +/* OTHER INCLUDES */ +#include "myprocess.h" +#include "kommanderwidget.h" +#include "specials.h" +#include "specialinformation.h" +#include "parser.h" +#include "parserdata.h" +#include "kommanderwindow.h" + +KommanderWidget::KommanderWidget(QObject *a_thisObject) +{ + m_thisObject = a_thisObject; +} + +KommanderWidget::~KommanderWidget() +{ +} + +void KommanderWidget::setAssociatedText(const QStringList& a_associations) +{ + m_associatedText = a_associations; + while(m_associatedText.count() < (states().count())) + m_associatedText += QString(); // sync states and associations +} + +QStringList KommanderWidget::associatedText() const +{ + return m_associatedText; +} + +bool KommanderWidget::hasAssociatedText() +{ + int index = states().findIndex(currentState()); + if (index == -1 || m_associatedText[index].isEmpty()) + return false; + return true; +} + + +void KommanderWidget::setPopulationText(const QString& a_txt) +{ + m_populationText = a_txt; +} + +QString KommanderWidget::populationText() const +{ + return m_populationText; +} + +QStringList KommanderWidget::states() const +{ + return m_states; +} + +QStringList KommanderWidget::displayStates() const +{ + return m_displayStates; +} + +void KommanderWidget::setStates(const QStringList& a_states) +{ + m_states = a_states; +} + +void KommanderWidget::setDisplayStates(const QStringList& a_displayStates) +{ + m_displayStates = a_displayStates; +} + +QString KommanderWidget::evalAssociatedText() // expands and returns associated text as a string +{ + int index = ( states().findIndex( currentState()) ); + if (index == -1) + { + printError(i18n("Invalid state for associated text.")); + return QString(); + } + return evalAssociatedText(m_associatedText[index]); +} + +QString KommanderWidget::evalAssociatedText(const QString& a_text) +{ + /* New internal parser is used if global flag is set */ + if ((KommanderWidget::useInternalParser && !a_text.startsWith("#!")) || a_text.startsWith("#!kommander")) + { + Parser p(internalParserData()); + p.setWidget(this); + p.setString(a_text); + if (!p.setString(a_text) || !p.parse()) + printError(i18n("Line %1: %2.\n").arg(p.errorLine()+1).arg(p.errorMessage())); + return QString(); + } + /* Old macro-only parser is implemented below */ + + bool parserType = KommanderWidget::useInternalParser; + KommanderWidget::useInternalParser = false; //shebang is used, switch to old parser + + QString evalText; + int pos = 0, baseTextLength = a_text.length(); + while (pos < baseTextLength) + { + int ident = a_text.find(ESCCHAR, pos); + if (ident == -1) { + evalText += a_text.mid(pos); + break; + } + evalText += a_text.mid(pos, ident - pos); + pos = ident+1; + + /* escaped @ */ + if (pos < baseTextLength-1 && a_text[pos] == ESCCHAR) + { + evalText += ESCCHAR; + pos++; + continue; + } + + QString identifier = parseIdentifier(a_text, pos); + /* comment */ + if (identifier.isEmpty()) + { + if (pos < baseTextLength && a_text[pos] == '#') { // comment + int newpos = a_text.find('\n', pos+1); + if (newpos == -1) + newpos = a_text.length(); + if (pos > 1 && a_text[pos-2] == '\n') + newpos++; + pos = newpos; + } + else + evalText += ESCCHAR; // single @ + continue; + } + bool ok = true; + QStringList args; + + + + /* Standard, non-prefixed special */ + if (identifier == "if") // if required special handling as it takes expression + { + QString arg = parseBrackets(a_text, pos, ok); + if (!ok) + return QString(); + args.append(evalAssociatedText(arg)); + evalText += evalIfBlock(args, a_text, pos); + } + else if (SpecialInformation::function(Group::Kommander, identifier) != -1) + { + args = parseFunction("Kommander", identifier, a_text, pos, ok); + if (!ok) + return QString(); + else if (identifier == "execBegin") + evalText += evalExecBlock(args, a_text, pos); + else if (identifier == "forEach") + evalText += evalForEachBlock(args, a_text, pos); + else if (identifier == "for") + evalText += evalForBlock(args, a_text, pos); + else if (identifier == "switch") + evalText += evalSwitchBlock(args, a_text, pos); + else if (identifier == "if") + evalText += evalIfBlock(args, a_text, pos); + else + evalText += evalFunction(identifier, args); + } + + /* Widget special */ + else if (parseWidget(identifier)) + evalText += evalWidgetFunction(identifier, a_text, pos); + else if (a_text[pos] == '.') + { + pos++; + QString function = parseIdentifier(a_text, pos); + args = parseFunction(identifier, function, a_text, pos, ok); + if (!ok) + return QString(); + switch (SpecialInformation::group(identifier)) + { + case Group::Array: + evalText += evalArrayFunction(function, args); + break; + case Group::String: + evalText += Parser::function(internalParserData(), "str_" + function, args); + break; + case Group::File: + evalText += Parser::function(internalParserData(), "file_" + function, args); + break; + case Group::Message: + evalText += Parser::function(internalParserData(), "message_" + function, args); + break; + case Group::Input: + evalText += Parser::function(internalParserData(), "input_" + function, args); + break; + default: + return QString(); + } + } + else + { + printError(i18n("Unknown special: \'%1\'.").arg(identifier)); + return QString(); + } + } + + KommanderWidget::useInternalParser = parserType; + return evalText; +} + + +QString KommanderWidget::DCOPQuery(const QStringList& a_query) +{ + QString app = a_query[0]; + app.remove("\""); + QCString appId = app.latin1(), object = a_query[1].latin1(); + + // parse function arguments + QString function = a_query[2], pTypes; + function.remove(' '); + int start = function.find('('); + bool ok = false; + if (start != -1) + pTypes = parseBrackets(function, start, ok); + else + { + ok = true; + function += "()"; + } + if (!ok) + { + printError(i18n("Unmatched parenthesis in DCOP call \'%1\'.").arg(a_query[2])); + return QString(); + } + const QStringList argTypes = parseArgs(pTypes, ok); + if (!ok || argTypes.count() != a_query.count() - 3) + { + printError(i18n("Incorrect arguments in DCOP call \'%1\'.").arg(a_query[2])); + return QString(); + } + + QCString replyType; + QByteArray byteData, byteReply; + QDataStream byteDataStream(byteData, IO_WriteOnly); + for (uint i=0 ; i<argTypes.count(); i++) { + if (argTypes[i] == "int") + byteDataStream << a_query[i+3].toInt(); + else if (argTypes[i] == "long") + byteDataStream << a_query[i+3].toLong(); + else if (argTypes[i] == "float") + byteDataStream << a_query[i+3].toFloat(); + else if (argTypes[i] == "double") + byteDataStream << a_query[i+3].toDouble(); + else if (argTypes[i] == "bool") + byteDataStream << (bool)(a_query[i+3] != "false" && a_query[i+3] != "false" && a_query[i+3] != "0"); + else if (argTypes[i] == "QStringList") + if (a_query[i+3].find('\n') != -1) + byteDataStream << QStringList::split("\n", a_query[i+3], true); + else + byteDataStream << QStringList::split("\\n", a_query[i+3], true); + else + byteDataStream << a_query[i+3]; + } + + DCOPClient *cl = KApplication::dcopClient(); + if (!cl || !cl->call(appId, object, function.latin1(), byteData, replyType, byteReply)) + { + printError(i18n("Tried to perform DCOP query, but failed.")); + return QString(); + } + + QDataStream byteReplyStream(byteReply, IO_ReadOnly); + if (replyType == "QString") + { + QString text; + byteReplyStream >> text; + return text; + } + else if(replyType == "int") + { + int i; + byteReplyStream >> i; + return QString::number(i); + } + else if(replyType == "bool") + { + bool b; + byteReplyStream >> b; + return QString::number(b); + } + else if (replyType == "QStringList") + { + QStringList text; + byteReplyStream >> text; + return text.join("\n"); + } + else if(replyType != "void") + { + printError(i18n("DCOP return type %1 is not yet implemented.").arg(replyType.data())); + } + + return QString(); +} + +QString KommanderWidget::localDCOPQuery(const QString function, const QStringList& args) +{ + QStringList pArgs; + pArgs.append(kapp->dcopClient()->appId()); + pArgs.append("KommanderIf"); + pArgs.append(function); + for (uint i=0; i<args.count(); i++) + pArgs.append(args[i]); + return DCOPQuery(pArgs); +} + +QString KommanderWidget::localDCOPQuery(const QString function, const QString& arg1, + const QString& arg2, const QString& arg3, const QString& arg4) +{ + QStringList pArgs; + pArgs.append(kapp->dcopClient()->appId()); + pArgs.append("KommanderIf"); + pArgs.append(function); + pArgs.append(arg1); + pArgs.append(arg2); + if (!arg3.isNull()) + pArgs.append(arg3); + if (!arg4.isNull()) + pArgs.append(arg4); + return DCOPQuery(pArgs); +} + + +QString KommanderWidget::execCommand(const QString& a_command, const QString& a_shell) const +{ + MyProcess proc(this); + QString text = proc.run(a_command.local8Bit(), a_shell.latin1()); +//FIXME check if exec was successful + return text; +} + +QString KommanderWidget::runDialog(const QString& a_dialog, const QString& a_params) +{ + QString pFileName = localDCOPQuery("global(QString)", "_KDDIR") + QString("/") + a_dialog; + QFileInfo pDialogFile(pFileName); + if (!pDialogFile.exists()) + { + pFileName = a_dialog; + pDialogFile.setFile(pFileName); + if (!pDialogFile.exists()) + return QString(); + } + QString cmd = QString("kmdr-executor %1 %2 _PARENTPID=%3 _PARENTDCOPID=kmdr-executor-%4") + .arg(pFileName).arg(a_params).arg(getpid()).arg(getpid()); + return execCommand(cmd); +} + + +void KommanderWidget::printError(const QString& a_error) const +{ + if (showErrors) + { + KDialogBase* dialog = new KDialogBase("Error", KDialogBase::Yes | KDialogBase::No | KDialogBase::Cancel, + KDialogBase::Yes, KDialogBase::No, 0, 0, true, false, + i18n("Continue"), i18n("Continue && Ignore Next Errors"), i18n("Stop")); + switch (KMessageBox::createKMessageBox(dialog, QMessageBox::Warning, + i18n("<qt>Error in widget <b>%1</b>:<p><i>%2</i></qt>").arg(QString(m_thisObject->name())) + .arg(a_error), QStringList(), QString(), 0, 0)) + { + case KDialogBase::No: + showErrors = false; + case KDialogBase::Yes: + break; + case KDialogBase::Cancel: + if (parentDialog()->inherits("QDialog")) + { + parentDialog()->close(); + exit(-1); + } + else if (parentDialog()->inherits("QMainWindow")) + kapp->quit(); + } + } + else + { + kdError() << i18n("Error in widget %1:\n %2\n").arg(m_thisObject->name()).arg(a_error); + } +} + + + +QString KommanderWidget::parseIdentifier(const QString& s, int& from) const +{ + uint start = from; + while (start < s.length() && s[start].isSpace()) + start++; + uint end = start; + while (end < s.length() && (s[end].isLetterOrNumber() || s[end] == '_')) + end++; + from = end; + return s.mid(start, end-start); +} + +QString KommanderWidget::parseBrackets(const QString& s, int& from, bool& ok) const +{ + ok = true; + uint start = from; + while (start < s.length() && s[start].isSpace()) + start++; + if (start == s.length() || s[start] != '(') + return QString(); + bool quoteSingle = false, quoteDouble = false; + int brackets = 1; + for (uint end = start+1; end < s.length(); end++) + { + if (!quoteDouble && s[end] == '\'' && s[end-1] != '\\') + quoteSingle = !quoteSingle; + else if (!quoteSingle && s[end] == '\"' && s[end-1] != '\\') + quoteDouble = !quoteDouble; + else if (!quoteDouble && !quoteSingle && s[end] == '(') + brackets++; + else if (!quoteDouble && !quoteSingle && s[end] == ')') + { + brackets--; + if (!brackets) { + from = end + 1; + return s.mid(start+1, end-start-1); + } + } + } + ok = false; + return QString(); +} + + +QStringList KommanderWidget::parseArgs(const QString& s, bool &ok) +{ + QStringList argList; + bool quoteDouble = false, quoteSingle = false; + uint i, start = 0, brackets=0; + for (i = 0; i < s.length(); i++) + { + /* Handle brackets */ + if (s[i] == '(' && !quoteSingle && !quoteDouble) + brackets++; + else if (s[i] == ')' && !quoteSingle && !quoteDouble) + brackets--; + /* Ignore everything in brackets */ + else if (!brackets) + { + if (s[i] == '\'' && s[i-1] != '\\' && !quoteDouble) + quoteSingle = !quoteSingle; + else if (s[i] == '\"' && s[i-1] != '\\' && !quoteSingle) + quoteDouble = !quoteDouble; + else if (s[i] == ',' && !quoteDouble && !quoteSingle) + { + QString arg = s.mid(start, i - start).stripWhiteSpace(); + if (!arg.isEmpty()) + argList.append(evalAssociatedText(parseQuotes(arg))); + start = i+1; + } + } + } + if (!quoteDouble && !quoteSingle) + { + QString arg = s.mid(start, s.length() - start + 1).stripWhiteSpace(); + if (!arg.isEmpty()) + argList.append(evalAssociatedText(parseQuotes(arg))); + } + ok = !quoteDouble && !quoteSingle; + + return argList; +} + +QString KommanderWidget::parseQuotes(const QString& s) const +{ + if (s[0] == s[s.length()-1] && (s[0] == '\'' || s[0] == '\"')) + { + QMemArray<QChar> buf(s.length()); + int start = 0; + int end = s.length() - 1; + for (int i=1; i<end; i++) + if (s[i] == '\\') + { + if (s[i+1] == 't') + buf[start++] = '\t'; + else if (s[i+1] == 'n') + buf[start++] = '\n'; + else if (s[i+1] == '\\') + buf[start++] = '\\'; + else + { + buf[start++] = s[i]; + i--; + } + i++; + } + else + buf[start++] = s[i]; + return QString(buf, start); + //return s.mid(1, s.length()-2); + } + else return s; +} + +bool KommanderWidget::isWidget(const QString& a_name) const +{ + return parseWidget(a_name); +} + +KommanderWidget* KommanderWidget::widgetByName(const QString& a_name) const +{ + return parseWidget(a_name); +} + + +KommanderWidget* KommanderWidget::parseWidget(const QString& widgetName) const +{ + if (QString(parentDialog()->name()) == widgetName) + return dynamic_cast <KommanderWidget*>(parentDialog()); + QCString s = widgetName.lower() == "self" ? m_thisObject->name() : widgetName.latin1(); + QObject* childObj = parentDialog()->child(s); +/* if (!childObj) + { + Parser parser(internalParserData()); + QString variableValue = parser.variable(widgetName).toString(); + s = variableValue.lower() == "self" ? m_thisObject->name() : variableValue.latin1(); + childObj = parentDialog()->child(s); + }*/ + return dynamic_cast <KommanderWidget*>(childObj); +} + +QStringList KommanderWidget::parseFunction(const QString& group, const QString& function, + const QString& s, int& from, bool& ok) +{ + ok = true; + bool success = false; + QString arg = parseBrackets(s, from, ok); + if (!ok) + { + printError(i18n("Unmatched parenthesis after \'%1\'.").arg(function)); + return QString(); + } + const QStringList args = parseArgs(arg, ok); + int gname = SpecialInformation::group(group); + int fname = SpecialInformation::function(gname, function); + bool extraArg = gname == Group::DCOP; + + if (!ok) + printError(i18n("Unmatched quotes in argument of \'%1\'.").arg(function)); + else if (gname == -1) + printError(i18n("Unknown function group: \'%1\'.").arg(group)); + else if (fname == -1 && !extraArg) + printError(i18n("Unknown function: \'%1\' in group '%2'.").arg(function).arg(group)); + else if (fname == -1 && extraArg) + printError(i18n("Unknown widget function: \'%1\'.").arg(function)); + else if ((int)args.count() + extraArg < SpecialInformation::minArg(gname, fname)) + printError(i18n("Not enough arguments for \'%1\' (%2 instead of %3).<p>" + "Correct syntax is: %4") + .arg(function).arg(args.count() + extraArg).arg(SpecialInformation::minArg(gname, fname)) + .arg(SpecialInformation::prototype(gname, fname, SpecialFunction::ShowArgumentNames))); + else if ((int)args.count() + extraArg > SpecialInformation::maxArg(gname, fname)) + printError(i18n("Too many arguments for \'%1\' (%2 instead of %3).<p>" + "Correct syntax is: %4") + .arg(function).arg(args.count() + extraArg).arg(SpecialInformation::maxArg(gname, fname)) + .arg(SpecialInformation::prototype(gname, fname, SpecialFunction::ShowArgumentNames))); + else + success = true; + ok = success; + return args; +} + +int KommanderWidget::parseBlockBoundary(const QString& s, int from, const QStringList& args) const +{ + int shortest = -1; + for (uint i=0; i<args.count(); i++) + { + int match = s.find(args[i], from); + if (shortest > match || shortest == -1) + shortest = match; + } + return shortest; +} + + + +QString KommanderWidget::substituteVariable(QString text, QString variable, QString value) const +{ + QString var = QString("@%1").arg(variable); + QString newtext; + int newpos, pos = 0; + while (true) + { + newpos = text.find(var, pos); + if (newpos != -1) + { + newtext += text.mid(pos, newpos-pos); + newtext += value; + pos = newpos + var.length(); + } else + { + newtext += text.mid(pos); + break; + } + } + return newtext; +} + + + +QWidget* KommanderWidget::parentDialog() const +{ + QObject *superParent = m_thisObject; + while (superParent->parent()) + { + superParent = superParent->parent(); + if (superParent->inherits("QDialog") || superParent->inherits("QMainWindow")) + break; + } + return (QWidget*)superParent; +} + + + + +QString KommanderWidget::global(const QString& variableName) +{ + QString var = variableName.startsWith("_") ? variableName : QString("_")+ variableName; + Parser parser(internalParserData()); + return parser.variable(var).toString(); +} + +void KommanderWidget::setGlobal(const QString& variableName, const QString& value) +{ + QString var = variableName.startsWith("_") ? variableName : QString("_")+ variableName; + Parser parser(internalParserData()); + parser.setVariable(var, value); +} + +QString KommanderWidget::handleDCOP(const int function, const QStringList& args) +{ + QWidget* current = dynamic_cast<QWidget*>(m_thisObject); + if (!current) + return QString(); + switch(function) { + case DCOP::setEnabled: + current->setEnabled( args[0] != "false" && args[0] != "0"); + break; + case DCOP::setVisible: + current->setShown(args[0] != "false" && args[0] != "0"); + break; + case DCOP::type: + return current->className(); + case DCOP::children: + { + QStringList matching; + QObjectList* widgets = current->queryList("QWidget", 0, false, args.count() == 0 || args[0] != "false"); + for (QObject* w = widgets->first(); w; w = widgets->next()) + if (w->name() && (dynamic_cast<KommanderWidget*>(w))) + matching.append(w->name()); + return matching.join("\n"); + } + } + return QString(); +} + +bool KommanderWidget::isFunctionSupported(int f) +{ + return f == DCOP::setEnabled || f == DCOP::setVisible || f == DCOP::children || f == DCOP::type; +} + +bool KommanderWidget::isCommonFunction(int f) +{ + return f == DCOP::setEnabled || f == DCOP::setVisible || f == DCOP::children || f == DCOP::type; +} + +ParserData* KommanderWidget::internalParserData() const +{ + return m_parserData; +} + +QString KommanderWidget::fileName() +{ + KommanderWindow* window = dynamic_cast<KommanderWindow*>(parentDialog()); + if (window) + return QString(window->fileName()); + else + return QString(); +} + +QString KommanderWidget::widgetName() const +{ + if (m_thisObject) + return QString::fromLatin1(m_thisObject->name()); + else + return QString(); +} + +bool KommanderWidget::inEditor = false; +bool KommanderWidget::showErrors = true; +bool KommanderWidget::useInternalParser = false; +ParserData* KommanderWidget::m_parserData = new ParserData; + + |