/*************************************************************************** kommanderwidget.cpp - Text widget core functionality ------------------- copyright : (C) 2002-2003 Marc Britton (C) 2004 Michal Rudolf ***************************************************************************/ /*************************************************************************** * * * 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 #include #include #include #include #include #include /* QT INCLUDES */ #include #include #include #include #include #include #include #include #include #include /* UNIX INCLUDES */ #include #include /* 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(TQObject *a_thisObject) { m_thisObject = a_thisObject; } KommanderWidget::~KommanderWidget() { } void KommanderWidget::setAssociatedText(const TQStringList& a_associations) { m_associatedText = a_associations; while(m_associatedText.count() < (states().count())) m_associatedText += TQString(); // sync states and associations } TQStringList 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 TQString& a_txt) { m_populationText = a_txt; } TQString KommanderWidget::populationText() const { return m_populationText; } TQStringList KommanderWidget::states() const { return m_states; } TQStringList KommanderWidget::displayStates() const { return m_displayStates; } void KommanderWidget::setStates(const TQStringList& a_states) { m_states = a_states; } void KommanderWidget::setDisplayStates(const TQStringList& a_displayStates) { m_displayStates = a_displayStates; } TQString 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 TQString(); } return evalAssociatedText(m_associatedText[index]); } TQString KommanderWidget::evalAssociatedText(const TQString& 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 TQString(); } /* Old macro-only parser is implemented below */ bool parserType = KommanderWidget::useInternalParser; KommanderWidget::useInternalParser = false; //shebang is used, switch to old parser TQString 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; } TQString 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; TQStringList args; /* Standard, non-prefixed special */ if (identifier == "if") // if required special handling as it takes expression { TQString arg = parseBrackets(a_text, pos, ok); if (!ok) return TQString(); 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 TQString(); 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++; TQString function = parseIdentifier(a_text, pos); args = parseFunction(identifier, function, a_text, pos, ok); if (!ok) return TQString(); 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 TQString(); } } else { printError(i18n("Unknown special: \'%1\'.").arg(identifier)); return TQString(); } } KommanderWidget::useInternalParser = parserType; return evalText; } TQString KommanderWidget::DCOPQuery(const TQStringList& a_query) { TQString app = a_query[0]; app.remove("\""); TQCString appId = app.latin1(), object = a_query[1].latin1(); // parse function arguments TQString 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 TQString(); } const TQStringList 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 TQString(); } TQCString replyType; TQByteArray byteData, byteReply; TQDataStream byteDataStream(byteData, IO_WriteOnly); for (uint i=0 ; icall(appId, object, function.latin1(), byteData, replyType, byteReply)) { printError(i18n("Tried to perform DCOP query, but failed.")); return TQString(); } TQDataStream byteReplyStream(byteReply, IO_ReadOnly); if (replyType == "TQString") { TQString text; byteReplyStream >> text; return text; } else if(replyType == "int") { int i; byteReplyStream >> i; return TQString::number(i); } else if(replyType == "bool") { bool b; byteReplyStream >> b; return TQString::number(b); } else if (replyType == "TQStringList") { TQStringList 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 TQString(); } TQString KommanderWidget::localDCOPQuery(const TQString function, const TQStringList& args) { TQStringList pArgs; pArgs.append(kapp->dcopClient()->appId()); pArgs.append("KommanderIf"); pArgs.append(function); for (uint i=0; idcopClient()->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); } TQString KommanderWidget::execCommand(const TQString& a_command, const TQString& a_shell) const { MyProcess proc(this); TQString text = proc.run(a_command.local8Bit(), a_shell.latin1()); //FIXME check if exec was successful return text; } TQString KommanderWidget::runDialog(const TQString& a_dialog, const TQString& a_params) { TQString pFileName = localDCOPQuery("global(TQString)", "_KDDIR") + TQString("/") + a_dialog; TQFileInfo pDialogFile(pFileName); if (!pDialogFile.exists()) { pFileName = a_dialog; pDialogFile.setFile(pFileName); if (!pDialogFile.exists()) return TQString(); } TQString cmd = TQString("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 TQString& 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, TQMessageBox::Warning, i18n("Error in widget %1:

%2").arg(TQString(m_thisObject->name())) .arg(a_error), TQStringList(), TQString(), 0, 0)) { case KDialogBase::No: showErrors = false; case KDialogBase::Yes: break; case KDialogBase::Cancel: if (parentDialog()->inherits("TQDialog")) { parentDialog()->close(); exit(-1); } else if (parentDialog()->inherits("TQMainWindow")) kapp->quit(); } } else { kdError() << i18n("Error in widget %1:\n %2\n").arg(m_thisObject->name()).arg(a_error); } } TQString KommanderWidget::parseIdentifier(const TQString& 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); } TQString KommanderWidget::parseBrackets(const TQString& 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 TQString(); 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 TQString(); } TQStringList KommanderWidget::parseArgs(const TQString& s, bool &ok) { TQStringList 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) { TQString arg = s.mid(start, i - start).stripWhiteSpace(); if (!arg.isEmpty()) argList.append(evalAssociatedText(parseQuotes(arg))); start = i+1; } } } if (!quoteDouble && !quoteSingle) { TQString arg = s.mid(start, s.length() - start + 1).stripWhiteSpace(); if (!arg.isEmpty()) argList.append(evalAssociatedText(parseQuotes(arg))); } ok = !quoteDouble && !quoteSingle; return argList; } TQString KommanderWidget::parseQuotes(const TQString& s) const { if (s[0] == s[s.length()-1] && (s[0] == '\'' || s[0] == '\"')) { TQMemArray buf(s.length()); int start = 0; int end = s.length() - 1; for (int i=1; iname()) == widgetName) return dynamic_cast (parentDialog()); TQCString s = widgetName.lower() == "self" ? m_thisObject->name() : widgetName.latin1(); TQObject* childObj = parentDialog()->child(s); /* if (!childObj) { Parser parser(internalParserData()); TQString variableValue = parser.variable(widgetName).toString(); s = variableValue.lower() == "self" ? m_thisObject->name() : variableValue.latin1(); childObj = parentDialog()->child(s); }*/ return dynamic_cast (childObj); } TQStringList KommanderWidget::parseFunction(const TQString& group, const TQString& function, const TQString& s, int& from, bool& ok) { ok = true; bool success = false; TQString arg = parseBrackets(s, from, ok); if (!ok) { printError(i18n("Unmatched parenthesis after \'%1\'.").arg(function)); return TQString(); } const TQStringList 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).

" "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).

" "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 TQString& s, int from, const TQStringList& args) const { int shortest = -1; for (uint i=0; i match || shortest == -1) shortest = match; } return shortest; } TQString KommanderWidget::substituteVariable(TQString text, TQString variable, TQString value) const { TQString var = TQString("@%1").arg(variable); TQString 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; } TQWidget* KommanderWidget::parentDialog() const { TQObject *superParent = m_thisObject; while (superParent->parent()) { superParent = superParent->parent(); if (superParent->inherits("TQDialog") || superParent->inherits("TQMainWindow")) break; } return (TQWidget*)superParent; } TQString KommanderWidget::global(const TQString& variableName) { TQString var = variableName.startsWith("_") ? variableName : TQString("_")+ variableName; Parser parser(internalParserData()); return parser.variable(var).toString(); } void KommanderWidget::setGlobal(const TQString& variableName, const TQString& value) { TQString var = variableName.startsWith("_") ? variableName : TQString("_")+ variableName; Parser parser(internalParserData()); parser.setVariable(var, value); } TQString KommanderWidget::handleDCOP(const int function, const TQStringList& args) { TQWidget* current = dynamic_cast(m_thisObject); if (!current) return TQString(); 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: { TQStringList matching; TQObjectList* widgets = current->queryList("TQWidget", 0, false, args.count() == 0 || args[0] != "false"); for (TQObject* w = widgets->first(); w; w = widgets->next()) if (w->name() && (dynamic_cast(w))) matching.append(w->name()); return matching.join("\n"); } } return TQString(); } 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; } TQString KommanderWidget::fileName() { KommanderWindow* window = dynamic_cast(parentDialog()); if (window) return TQString(window->fileName()); else return TQString(); } TQString KommanderWidget::widgetName() const { if (m_thisObject) return TQString::fromLatin1(m_thisObject->name()); else return TQString(); } bool KommanderWidget::inEditor = false; bool KommanderWidget::showErrors = true; bool KommanderWidget::useInternalParser = false; ParserData* KommanderWidget::m_parserData = new ParserData;