From 415b19d7e14db3e0a0d0840932f330bcaafdb66d Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 3 Sep 2012 14:48:17 +0200 Subject: [PATCH] CodePaster: Add command-line frontend. Code pasting functionality is something that comes in very handy on the shell, so why have it be GUI-only? Change-Id: I4f316769b4ce25e1ab5f90df94ceef33f8478248 Reviewed-by: Tobias Hunger --- qtcreator.qbp | 3 +- .../cpaster/frontend/argumentscollector.cpp | 134 ++++++++++++++++++ .../cpaster/frontend/argumentscollector.h | 67 +++++++++ src/plugins/cpaster/frontend/frontend.pro | 30 ++++ src/plugins/cpaster/frontend/frontend.qbs | 30 ++++ src/plugins/cpaster/frontend/main.cpp | 128 +++++++++++++++++ src/plugins/cpaster/pastebindotcaprotocol.h | 4 +- src/tools/tools.pro | 3 +- 8 files changed, 396 insertions(+), 3 deletions(-) create mode 100644 src/plugins/cpaster/frontend/argumentscollector.cpp create mode 100644 src/plugins/cpaster/frontend/argumentscollector.h create mode 100644 src/plugins/cpaster/frontend/frontend.pro create mode 100644 src/plugins/cpaster/frontend/frontend.qbs create mode 100644 src/plugins/cpaster/frontend/main.cpp diff --git a/qtcreator.qbp b/qtcreator.qbp index e8ab24a7efb..0f5bc521b62 100644 --- a/qtcreator.qbp +++ b/qtcreator.qbp @@ -76,7 +76,8 @@ Project { "src/plugins/welcome/welcome.qbs", "src/share/share.qbs", "src/tools/qtcdebugger/qtcdebugger.qbs", - "src/tools/qtpromaker/qtpromaker.qbs" + "src/tools/qtpromaker/qtpromaker.qbs", + "src/plugins/cpaster/frontend/frontend.qbs" ] Product { diff --git a/src/plugins/cpaster/frontend/argumentscollector.cpp b/src/plugins/cpaster/frontend/argumentscollector.cpp new file mode 100644 index 00000000000..9b433cf275d --- /dev/null +++ b/src/plugins/cpaster/frontend/argumentscollector.cpp @@ -0,0 +1,134 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: http://www.qt-project.org/ +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +**************************************************************************/ +#include "argumentscollector.h" + +#include + +static QString pasteRequestString() { return QLatin1String("paste"); } +static QString listProtocolsRequestString() { return QLatin1String("list-protocols"); } +static QString helpRequestString() { return QLatin1String("help"); } +static QString pasteFileOptionString() { return QLatin1String("-file"); } +static QString pasteProtocolOptionString() { return QLatin1String("-protocol"); } + +namespace { +struct ArgumentErrorException +{ + ArgumentErrorException(const QString &error) : error(error) {} + const QString error; +}; +} + +ArgumentsCollector::ArgumentsCollector(const QStringList &availableProtocols) + : m_availableProtocols(availableProtocols) +{ +} + +bool ArgumentsCollector::collect(const QStringList &args) +{ + m_arguments = args; + m_errorString.clear(); + m_inputFilePath.clear(); + m_protocol.clear(); + try { + setRequest(); + if (m_requestType == RequestTypePaste) + setPasteOptions(); + return true; + } catch (const ArgumentErrorException &ex) { + m_errorString = ex.error; + return false; + } +} + +QString ArgumentsCollector::usageString() const +{ + QString usage = tr("Usage:"); + usage += QLatin1String("\n\t"); + usage += tr("%1 [ ]") + .arg(QFileInfo(QCoreApplication::applicationFilePath()).fileName()); + usage += QLatin1String("\n\t"); + usage += tr("Possible requests: \"%1\", \"%2\", \"%3\"") + .arg(pasteRequestString(), listProtocolsRequestString(), helpRequestString()); + usage += QLatin1String("\n\t"); + usage += tr("Possible options for request \"%1\": \"%2 \" (default: stdin), " + "\"%3 \"") + .arg(pasteRequestString(), pasteFileOptionString(), pasteProtocolOptionString()); + usage += QLatin1Char('\n'); + return usage; +} + +void ArgumentsCollector::setRequest() +{ + if (m_arguments.isEmpty()) + throw ArgumentErrorException(tr("No request given")); + const QString requestString = m_arguments.takeFirst(); + if (requestString == pasteRequestString()) + m_requestType = RequestTypePaste; + else if (requestString == listProtocolsRequestString()) + m_requestType = RequestTypeListProtocols; + else if (requestString == helpRequestString()) + m_requestType = RequestTypeHelp; + else + throw ArgumentErrorException(tr("Unknown request \"%1\"").arg(requestString)); +} + +void ArgumentsCollector::setPasteOptions() +{ + while (!m_arguments.isEmpty()) { + if (checkAndSetOption(pasteFileOptionString(), m_inputFilePath)) + continue; + if (checkAndSetOption(pasteProtocolOptionString(), m_protocol)) { + if (!m_availableProtocols.contains(m_protocol)) + throw ArgumentErrorException(tr("Unknown protocol \"%1\"").arg(m_protocol)); + continue; + } + throw ArgumentErrorException(tr("Invalid option \"%1\" for request \"%2\"") + .arg(m_arguments.first(), pasteRequestString())); + } + + if (m_protocol.isEmpty()) + throw ArgumentErrorException(tr("No protocol given")); +} + +bool ArgumentsCollector::checkAndSetOption(const QString &optionString, QString &optionValue) +{ + if (m_arguments.first() != optionString) + return false; + + if (!optionValue.isEmpty()) + throw ArgumentErrorException(tr("option \"%1\" was given twice").arg(optionString)); + m_arguments.removeFirst(); + if (m_arguments.isEmpty()) { + throw ArgumentErrorException(tr("Option \"%1\" requires an argument") + .arg(optionString)); + } + optionValue = m_arguments.takeFirst(); + return true; +} diff --git a/src/plugins/cpaster/frontend/argumentscollector.h b/src/plugins/cpaster/frontend/argumentscollector.h new file mode 100644 index 00000000000..c299b718f39 --- /dev/null +++ b/src/plugins/cpaster/frontend/argumentscollector.h @@ -0,0 +1,67 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: http://www.qt-project.org/ +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +**************************************************************************/ + +#ifndef ARGUMENTSCOLLECTOR_H +#define ARGUMENTSCOLLECTOR_H + +#include +#include + +class ArgumentsCollector +{ + Q_DECLARE_TR_FUNCTIONS(ArgumentsCollector) +public: + ArgumentsCollector(const QStringList &availableProtocols); + bool collect(const QStringList &args); // Application is already removed. + + enum RequestType { RequestTypeHelp, RequestTypeListProtocols, RequestTypePaste }; + RequestType requestType() const { return m_requestType; } + + QString errorString() const { return m_errorString; } + QString usageString() const; + + // These are valid <=> requestType() == RequestTypePaste + QString inputFilePath() const { return m_inputFilePath; } + QString protocol() const { return m_protocol; } + +private: + void setRequest(); + void setPasteOptions(); + bool checkAndSetOption(const QString &optionString, QString &optionValue); + + const QStringList m_availableProtocols; + QStringList m_arguments; + RequestType m_requestType; + QString m_inputFilePath; + QString m_protocol; + QString m_errorString; +}; + +#endif // ARGUMENTSCOLLECTOR_H diff --git a/src/plugins/cpaster/frontend/frontend.pro b/src/plugins/cpaster/frontend/frontend.pro new file mode 100644 index 00000000000..a5cdea93e4f --- /dev/null +++ b/src/plugins/cpaster/frontend/frontend.pro @@ -0,0 +1,30 @@ +TEMPLATE = app +TARGET=cpaster + +include(../../../../qtcreator.pri) +include(../../../rpath.pri) +include(../../../plugins/coreplugin/coreplugin.pri) + +CONFIG += console +QT += network + +LIBS *= -L$$IDE_PLUGIN_PATH/Nokia +QMAKE_RPATHDIR *= $$IDE_PLUGIN_PATH/Nokia + +DESTDIR=$$IDE_APP_PATH + +HEADERS = ../protocol.h \ + ../cpasterconstants.h \ + ../pastebindotcomprotocol.h \ + ../pastebindotcaprotocol.h \ + ../kdepasteprotocol.h \ + ../urlopenprotocol.h \ + argumentscollector.h + +SOURCES += ../protocol.cpp \ + ../pastebindotcomprotocol.cpp \ + ../pastebindotcaprotocol.cpp \ + ../kdepasteprotocol.cpp \ + ../urlopenprotocol.cpp \ + argumentscollector.cpp \ + main.cpp diff --git a/src/plugins/cpaster/frontend/frontend.qbs b/src/plugins/cpaster/frontend/frontend.qbs new file mode 100644 index 00000000000..37c7d94ac09 --- /dev/null +++ b/src/plugins/cpaster/frontend/frontend.qbs @@ -0,0 +1,30 @@ +import qbs.base 1.0 +import "../../../tools/QtcTool.qbs" as QtcTool + +QtcTool { + name: "cpaster" + + Depends { name: "cpp" } + Depends { + name: "Qt" + submodules: "core", "gui", "network" + } + Depends { name: "Core" } + + cpp.includePaths: ["../../"] + cpp.rpaths: [ + "$ORIGIN/../lib/qtcreator", + "$ORIGIN/../lib/qtcreator/plugins", + "$ORIGIN/../lib/qtcreator/plugins/Nokia" + ] + + files: [ "main.cpp", + "argumentscollector.h", "argumentscollector.cpp", + "../cpasterconstants.h", + "../protocol.h", "../protocol.cpp", + "../pastebindotcomprotocol.h", "../pastebindotcomprotocol.cpp", + "../pastebindotcaprotocol.h", "../pastebindotcaprotocol.cpp", + "../kdepasteprotocol.h", "../kdepasteprotocol.cpp", + "../urlopenprotocol.h", "../urlopenprotocol.cpp" + ] +} diff --git a/src/plugins/cpaster/frontend/main.cpp b/src/plugins/cpaster/frontend/main.cpp new file mode 100644 index 00000000000..ca3b995142e --- /dev/null +++ b/src/plugins/cpaster/frontend/main.cpp @@ -0,0 +1,128 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: http://www.qt-project.org/ +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +**************************************************************************/ + +#include "argumentscollector.h" +#include "../kdepasteprotocol.h" +#include "../pastebindotcaprotocol.h" +#include "../pastebindotcomprotocol.h" + +#include +#include +#include + +#include +#include +#include + +using namespace CodePaster; + +class PasteReceiver : public QObject +{ + Q_OBJECT +public: + PasteReceiver(const QString &protocol, const QString &filePath) : m_filePath(filePath) + { + const QSharedPointer accessMgr(new NetworkAccessManagerProxy); + if (protocol == KdePasteProtocol::protocolName().toLower()) + m_protocol.reset(new KdePasteProtocol(accessMgr)); + else if (protocol == PasteBinDotCaProtocol::protocolName().toLower()) + m_protocol.reset(new PasteBinDotCaProtocol(accessMgr)); + else if (protocol == PasteBinDotComProtocol::protocolName().toLower()) + m_protocol.reset(new PasteBinDotComProtocol(accessMgr)); + else + qFatal("Internal error: Invalid protocol."); + } + +public slots: + void paste() + { + QFile file(m_filePath); + const bool success = m_filePath.isEmpty() + ? file.open(stdin, QIODevice::ReadOnly) : file.open(QIODevice::ReadOnly); + if (!success) { + std::cerr << "Error: Failed to open file to paste from." << std::endl; + qApp->exit(EXIT_FAILURE); + return; + } + const QString content = QString::fromLocal8Bit(file.readAll()); + if (content.isEmpty()) { + std::cerr << "Empty input, aborting." << std::endl; + qApp->exit(EXIT_FAILURE); + return; + } + connect(m_protocol.data(), SIGNAL(pasteDone(QString)), SLOT(handlePasteDone(QString))); + m_protocol->paste(content); + } + +private slots: + void handlePasteDone(const QString &link) + { + std::cout << qPrintable(link) << std::endl; + qApp->quit(); + } + +private: + const QString m_filePath; + QScopedPointer m_protocol; +}; + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + const QStringList protocols = QStringList() << KdePasteProtocol::protocolName().toLower() + << PasteBinDotCaProtocol::protocolName().toLower() + << PasteBinDotComProtocol::protocolName().toLower(); + ArgumentsCollector argsCollector(protocols); + QStringList arguments = QCoreApplication::arguments(); + arguments.removeFirst(); + if (!argsCollector.collect(arguments)) { + std::cerr << "Error: " << qPrintable(argsCollector.errorString()) << '.' << std::endl + << qPrintable(argsCollector.usageString()) << std::endl; + return EXIT_FAILURE; + } + + switch (argsCollector.requestType()) { + case ArgumentsCollector::RequestTypeHelp: + std::cout << qPrintable(argsCollector.usageString()) << std::endl; + return EXIT_SUCCESS; + case ArgumentsCollector::RequestTypeListProtocols: + foreach (const QString &protocol, protocols) + std::cout << qPrintable(protocol) << std::endl; + return EXIT_SUCCESS; + case ArgumentsCollector::RequestTypePaste: { + PasteReceiver pr(argsCollector.protocol(), argsCollector.inputFilePath()); + QTimer::singleShot(0, &pr, SLOT(paste())); + return app.exec(); + } + } +} + +#include "main.moc" diff --git a/src/plugins/cpaster/pastebindotcaprotocol.h b/src/plugins/cpaster/pastebindotcaprotocol.h index e7c5019eef7..541d3635b70 100644 --- a/src/plugins/cpaster/pastebindotcaprotocol.h +++ b/src/plugins/cpaster/pastebindotcaprotocol.h @@ -39,7 +39,9 @@ class PasteBinDotCaProtocol : public NetworkProtocol Q_OBJECT public: explicit PasteBinDotCaProtocol(const NetworkAccessManagerProxyPtr &nw); - QString name() const { return QLatin1String("Pastebin.Ca"); } + + static QString protocolName() { return QLatin1String("Pastebin.Ca"); } + QString name() const { return protocolName(); } virtual bool hasSettings() const { return false; } virtual unsigned capabilities() const; diff --git a/src/tools/tools.pro b/src/tools/tools.pro index 321d6a8e57b..dcbb5bb6de9 100644 --- a/src/tools/tools.pro +++ b/src/tools/tools.pro @@ -1,7 +1,8 @@ TEMPLATE = subdirs SUBDIRS = qtpromaker \ - qmlpuppet + qmlpuppet \ + ../plugins/cpaster/frontend win32 { SUBDIRS += qtcdebugger