# # # add_file "res/forms/message.ui" # content [f8208ef0a1ebfaeae1a2260410daa0f0f140a8c9] # # add_file "src/view/dialogs/Message.cpp" # content [ac0fac32b19c603be4eac6af68230b5ed0ac2d18] # # add_file "src/view/dialogs/Message.h" # content [d8ff01342e07e6c2162f3d28719cdc1b7998972a] # # patch "guitone.pro" # from [bad165bd001ea9efdadeeb99cd5294c28eaaf1ae] # to [55dc2152982160f09a70ff3916db59967ea5f418] # # patch "src/GuitoneDriver.cpp" # from [65f257718ae2d0a79947d69043972a79ac34985a] # to [4ba006ff7f2e467db5341dac631cf42bc9cec07d] # # patch "src/GuitoneDriver.h" # from [b24931e08bf618708c41b9b55d6878de024f3f33] # to [701a19b67cd5627f86143f5ecfb598747c24303b] # ============================================================ --- res/forms/message.ui f8208ef0a1ebfaeae1a2260410daa0f0f140a8c9 +++ res/forms/message.ui f8208ef0a1ebfaeae1a2260410daa0f0f140a8c9 @@ -0,0 +1,90 @@ + + + MessageDialog + + + + 0 + 0 + 410 + 299 + + + + Dialog + + + + + + + false + false + false + + + + QPlainTextEdit::WidgetWidth + + + true + + + + + + Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + true + + + + + + + + + buttonBox + accepted() + MessageDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + MessageDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + ============================================================ --- src/view/dialogs/Message.cpp ac0fac32b19c603be4eac6af68230b5ed0ac2d18 +++ src/view/dialogs/Message.cpp ac0fac32b19c603be4eac6af68230b5ed0ac2d18 @@ -0,0 +1,38 @@ +/*************************************************************************** + * Copyright (C) 2009 by Thomas Keller * + * address@hidden * + * * + * 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 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#include "Message.h" + +#include + +Message::Message(QWidget * parent, const QString & title, const QString & msg) : Dialog(parent) +{ + setupUi(this); + Dialog::init(); + + setWindowTitle(title); + + QFont f; + f.setStyleHint(QFont::Courier); + f.setFamily("Courier"); + message->setFont(f); + message->setPlainText(msg); +} + +Message::~Message() {} + ============================================================ --- src/view/dialogs/Message.h d8ff01342e07e6c2162f3d28719cdc1b7998972a +++ src/view/dialogs/Message.h d8ff01342e07e6c2162f3d28719cdc1b7998972a @@ -0,0 +1,33 @@ +/*************************************************************************** + * Copyright (C) 2009 by Thomas Keller * + * address@hidden * + * * + * 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 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifndef MESSAGE_H +#define MESSAGE_H + +#include "ui_message.h" +#include "Dialog.h" + +class Message : public Dialog, private Ui::MessageDialog +{ + Q_OBJECT +public: + Message(QWidget *, const QString &, const QString &); + ~Message(); +}; + +#endif ============================================================ --- guitone.pro bad165bd001ea9efdadeeb99cd5294c28eaaf1ae +++ guitone.pro 55dc2152982160f09a70ff3916db59967ea5f418 @@ -61,6 +61,7 @@ HEADERS = src/view/TreeView.h \ src/view/dialogs/OpenPrompt.h \ src/view/dialogs/AddEditDatabaseVariable.h \ src/view/dialogs/CreateDatabase.h \ + src/view/dialogs/Message.h \ src/view/panels/IconHelp.h \ src/view/panels/DatabaseVariables.h \ src/view/panels/NodeInfo.h \ @@ -143,6 +144,7 @@ SOURCES += src/view/TreeView.cpp \ src/view/dialogs/OpenPrompt.cpp \ src/view/dialogs/AddEditDatabaseVariable.cpp \ src/view/dialogs/CreateDatabase.cpp \ + src/view/dialogs/Message.cpp \ src/view/panels/IconHelp.cpp \ src/view/panels/DatabaseVariables.cpp \ src/view/panels/NodeInfo.cpp \ @@ -212,7 +214,8 @@ FORMS += res/forms/select_revision.ui res/forms/db_variables.ui \ res/forms/add_edit_variables.ui \ res/forms/nodeinfo.ui \ - res/forms/create_database.ui + res/forms/create_database.ui \ + res/forms/message.ui UI_DIR = tmp OBJECTS_DIR = tmp ============================================================ --- src/GuitoneDriver.cpp 65f257718ae2d0a79947d69043972a79ac34985a +++ src/GuitoneDriver.cpp 4ba006ff7f2e467db5341dac631cf42bc9cec07d @@ -22,6 +22,7 @@ #include "DatabaseDialogManager.h" #include "WorkspaceDialogManager.h" +#include "Message.h" #include @@ -49,7 +50,7 @@ void GuitoneDriver::processCommands() if (args.size() < 2) { - error("wrong number of arguments"); + help(); return; } @@ -64,9 +65,11 @@ void GuitoneDriver::processCommands() QFileInfo fileInfo(path); if (!fileInfo.exists()) { - error("non-existant path"); + msg(QString("path '%1' does not exist").arg(path)); + QCoreApplication::exit(1); return; } + path = fileInfo.absoluteFilePath(); if (fileInfo.isDir()) @@ -75,11 +78,12 @@ void GuitoneDriver::processCommands() try { path = MonotoneManager::normalizeWorkspacePath(path); - APP->manager()->getThreadForWorkspace(path); + APP->manager()->getThreadForWorkspace(path)->waitForStarted(); } catch (GuitoneException e) { - error(e); + msg(QString("could not startup monotone: %1").arg(e)); + QCoreApplication::exit(1); return; } qobject_cast(dialogManager)->init(path); @@ -89,18 +93,20 @@ void GuitoneDriver::processCommands() dialogManager = new DatabaseDialogManager(NULL); try { - APP->manager()->getThreadForDatabase(path); + APP->manager()->getThreadForDatabase(path)->waitForStarted(); } catch (GuitoneException e) { - error(e); + msg(QString("could not startup monotone: %1").arg(e)); + QCoreApplication::exit(1); return; } qobject_cast(dialogManager)->init(path); } else { - error("file is neither a file nor a directory"); + msg(QString("path '%1' is neither a file nor a directory").arg(path)); + QCoreApplication::exit(1); return; } } @@ -111,70 +117,205 @@ void GuitoneDriver::processCommands() APP, SLOT(quit()) ); + // connect to all signals of the dialog manager + // FIXME: unfortunately our "general purpose" slots have no idea which + // signal they're responding to, since Qt has no API for that, obviously + // they store this information. It would be too cool if there would be + // a QObject::senderSignal() similar to QObject::sender() in the future... + const QMetaObject * metaObject = dialogManager->metaObject(); + for (int i=0; imethodCount(); i++) + { + QMetaMethod m = metaObject->method(i); + if (m.methodType() != QMetaMethod::Signal) continue; + + QByteArray sig = m.signature(); + // ignore these signals from QObject + if (sig == "destroyed()" || sig == "destroyed(QObject*)") + continue; + + D(QString("connecting to signal '%1'").arg(sig.constData())); + + sig.prepend("2"); // see qobjectdefs.h + if (m.parameterTypes().size() == 0) + { + connect( + dialogManager, sig, + this, SLOT(signalWithNoArguments()) + ); + } + else + if (m.parameterTypes().size() == 1 && m.parameterTypes().at(0) == "QString") + { + connect( + dialogManager, sig, + this, SLOT(signalWithOneStringArgument(const QString &)) + ); + } + else + { + W(QString("could not connect to signal '%1'").arg(sig.constData())); + } + } + QString reqMethod = args.takeFirst(); const QMetaObject * obj = dialogManager->metaObject(); - QMetaMethod method; - bool found = false; + QList methodCandidates; for (int i=0; imethodCount(); i++) { - method = obj->method(i); + QMetaMethod method = obj->method(i); QByteArray sig(method.signature()); sig = sig.left(sig.indexOf('(')); if (sig == reqMethod.toLatin1()) { - found = true; - break; + methodCandidates.push_back(method); } } - if (!found) + if (methodCandidates.size() == 0) { - error("method signature not found"); + msg(QString("method signature '%1' not found").arg(reqMethod)); + QCoreApplication::exit(1); return; } - QList methodArgs = method.parameterTypes(); + // FIXME: for now we only compare the number of arguments of a function + // but not their argument type - which of course would make a valid + // overload as well. since this is not a problem in the current API + // we leave this task for later... + const QMetaMethod * chosenMethod = 0; + foreach (const QMetaMethod & m, methodCandidates) + { + if (m.parameterTypes().size() == args.size()) + { + chosenMethod = &m; + } + } - if (methodArgs.size() != args.size()) + if (!chosenMethod) { - error("argument count doesn't match"); + msg(QString("found %1 overloads for '%2', but none takes %3 arguments") + .arg(methodCandidates.size()).arg(reqMethod).arg(args.size())); + QCoreApplication::exit(1); return; } if (args.size() > 10) { - error("cannot handle more than 10 function arguments"); + msg("cannot handle more than 10 function arguments"); + QCoreApplication::exit(1); return; } QGenericArgument genArgs[10]; - for (int i=0; iparameterTypes().size(); i++) { - const char * typeName = methodArgs.at(i).constData(); + const char * typeName = chosenMethod->parameterTypes().at(i).constData(); QVariant::Type type = QVariant::nameToType(typeName); - // we currently only use / support strings - switch (type) + // we currently only use / support strings and string lists + if (type == QVariant::String) { - case QVariant::String: genArgs[i] = Q_ARG(QString, args.at(i)); break; - case QVariant::Invalid: I(false); - default: error(QString("unrecognized type %1").arg(typeName)); return; + genArgs[i] = Q_ARG(QString, args.at(i)); } + else if (type == QVariant::StringList) + { + QString arg = args.at(i); + QRegExp rx("[^\\\\],"); + int pos = 0; + while ((pos = rx.indexIn(arg)) != -1) + { + listElements << arg.left(pos + 1); + arg = arg.mid(pos + 2); + } + listElements << arg; + + for (int j=0; j(reqMethod.toLatin1().data()); - QMetaObject::invokeMethod(dialogManager, methodName, Qt::DirectConnection, - genArgs[0], genArgs[1], genArgs[2], genArgs[3], - genArgs[4], genArgs[5], genArgs[6], genArgs[7], - genArgs[8], genArgs[9]); + bool ok = QMetaObject::invokeMethod(dialogManager, methodName, Qt::QueuedConnection, + genArgs[0], genArgs[1], genArgs[2], genArgs[3], + genArgs[4], genArgs[5], genArgs[6], genArgs[7], + genArgs[8], genArgs[9]); + D(QString("execution successful: %1").arg(ok)); } -void GuitoneDriver::error(const QString & msg) +void GuitoneDriver::msg(const QString & message) { - C(msg); - QMessageBox::critical(NULL, tr("Error"), msg, QMessageBox::Ok, 0, 0); - quit(); + Message msg(NULL, "guitone driver interface", message); + msg.exec(); } +void GuitoneDriver::help() +{ + QList objs; + objs.append((new DialogManager(NULL))->metaObject()); + objs.append((new DatabaseDialogManager(NULL))->metaObject()); + objs.append((new WorkspaceDialogManager(NULL))->metaObject()); + + QStringList output; + output << "Usage: guitone exec [ ...]\n\n"; + output << "Available functions:\n\n"; + + foreach (const QMetaObject * obj, objs) + { + output << obj->className() << ":\n"; + for (int i=obj->methodOffset(); i < obj->methodCount(); i++) + { + QMetaMethod m = obj->method(i); + if (m.access() != QMetaMethod::Public || + m.methodType() != QMetaMethod::Slot) + continue; + + QByteArray sig(m.signature()); + sig = sig.left(sig.indexOf('(')); + QList names = m.parameterNames(); + QList types = m.parameterTypes(); + + output << "\t" << sig; + for (int i=0; i 0) + output << ":" << names.at(i); + output << ">"; + } + output << "\n"; + } + } + output << "\n"; + output << "The stringlist type has to be given as a single argument. " + "Elements are separated with a comma ','; any comma inside " + "a string element has to be escaped with a backslash '\\,'."; + msg(output.join("")); +} + +void GuitoneDriver::signalWithNoArguments() +{ + L("signalled"); +} + +void GuitoneDriver::signalWithOneStringArgument(const QString & arg) +{ + L(QString("signalled, value: %1").arg(arg)); +} + ============================================================ --- src/GuitoneDriver.h b24931e08bf618708c41b9b55d6878de024f3f33 +++ src/GuitoneDriver.h 701a19b67cd5627f86143f5ecfb598747c24303b @@ -33,9 +33,12 @@ private slots: private slots: void processCommands(); + void signalWithNoArguments(); + void signalWithOneStringArgument(const QString &); private: - void error(const QString &); + void msg(const QString &); + void help(); DialogManager * dialogManager; };