diff options
Diffstat (limited to 'src/libs/utils')
44 files changed, 5419 insertions, 0 deletions
diff --git a/src/libs/utils/basevalidatinglineedit.cpp b/src/libs/utils/basevalidatinglineedit.cpp new file mode 100644 index 00000000000..cb936e3c2d2 --- /dev/null +++ b/src/libs/utils/basevalidatinglineedit.cpp @@ -0,0 +1,157 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "basevalidatinglineedit.h" + +#include <QtCore/QDebug> + +enum { debug = 0 }; + +namespace Core { +namespace Utils { + +struct BaseValidatingLineEditPrivate { + explicit BaseValidatingLineEditPrivate(const QWidget *w); + + const QColor m_okTextColor; + QColor m_errorTextColor; + + BaseValidatingLineEdit::State m_state; + QString m_errorMessage; + QString m_initialText; + bool m_firstChange; +}; + +BaseValidatingLineEditPrivate::BaseValidatingLineEditPrivate(const QWidget *w) : + m_okTextColor(BaseValidatingLineEdit::textColor(w)), + m_errorTextColor(Qt::red), + m_state(BaseValidatingLineEdit::Invalid), + m_firstChange(true) +{ +} + +BaseValidatingLineEdit::BaseValidatingLineEdit(QWidget *parent) : + QLineEdit(parent), + m_bd(new BaseValidatingLineEditPrivate(this)) +{ + // Note that textChanged() is also triggered automagically by + // QLineEdit::setText(), no need to trigger manually. + connect(this, SIGNAL(textChanged(QString)), this, SLOT(slotChanged(QString))); +} + +BaseValidatingLineEdit::~BaseValidatingLineEdit() +{ + delete m_bd; +} + +QString BaseValidatingLineEdit::initialText() const +{ + return m_bd->m_initialText; +} + +void BaseValidatingLineEdit::setInitialText(const QString &t) +{ + if (m_bd->m_initialText != t) { + m_bd->m_initialText = t; + m_bd->m_firstChange = true; + setText(t); + } +} + +QColor BaseValidatingLineEdit::errorColor() const +{ + return m_bd->m_errorTextColor; +} + +void BaseValidatingLineEdit::setErrorColor(const QColor &c) +{ + m_bd->m_errorTextColor = c; +} + +QColor BaseValidatingLineEdit::textColor(const QWidget *w) +{ + return w->palette().color(QPalette::Active, QPalette::Text); +} + +void BaseValidatingLineEdit::setTextColor(QWidget *w, const QColor &c) +{ + QPalette palette = w->palette(); + palette.setColor(QPalette::Active, QPalette::Text, c); + w->setPalette(palette); +} + +BaseValidatingLineEdit::State BaseValidatingLineEdit::state() const +{ + return m_bd->m_state; +} + +bool BaseValidatingLineEdit::isValid() const +{ + return m_bd->m_state == Valid; +} + +QString BaseValidatingLineEdit::errorMessage() const +{ + return m_bd->m_errorMessage; +} + +void BaseValidatingLineEdit::slotChanged(const QString &t) +{ + m_bd->m_errorMessage.clear(); + // Are we displaying the initial text? + const bool isDisplayingInitialText = !m_bd->m_initialText.isEmpty() && t == m_bd->m_initialText; + const State newState = isDisplayingInitialText ? + DisplayingInitialText : + (validate(t, &m_bd->m_errorMessage) ? Valid : Invalid); + setToolTip(m_bd->m_errorMessage); + if (debug) + qDebug() << Q_FUNC_INFO << t << "State" << m_bd->m_state << "->" << newState << m_bd->m_errorMessage; + // Changed..figure out if valid changed. DisplayingInitialText is not valid, + // but should not show error color. Also trigger on the first change. + if (newState != m_bd->m_state || m_bd->m_firstChange) { + const bool validHasChanged = (m_bd->m_state == Valid) != (newState == Valid); + m_bd->m_state = newState; + m_bd->m_firstChange = false; + setTextColor(this, newState == Invalid ? m_bd->m_errorTextColor : m_bd->m_okTextColor); + if (validHasChanged) + emit validChanged(); + } +} + +void BaseValidatingLineEdit::slotReturnPressed() +{ + if (isValid()) + emit validReturnPressed(); +} + +} +} diff --git a/src/libs/utils/basevalidatinglineedit.h b/src/libs/utils/basevalidatinglineedit.h new file mode 100644 index 00000000000..34826870112 --- /dev/null +++ b/src/libs/utils/basevalidatinglineedit.h @@ -0,0 +1,100 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef BASEVALIDATINGLINEEDIT_H +#define BASEVALIDATINGLINEEDIT_H + +#include "utils_global.h" + +#include <QtGui/QLineEdit> + +namespace Core { +namespace Utils { + +struct BaseValidatingLineEditPrivate; + +/* Base class for validating line edits that performs validation in a virtual + * validate() function to be implemented in derived classes. + * When invalid, the text color will turn red and a tooltip will + * contain the error message. This approach is less intrusive than a + * QValidator which will prevent the user from entering certain characters. + * + * The widget has a concept of an "initialText" which can be something like + * "<Enter name here>". This results in state 'DisplayingInitialText', which + * is not valid, but is not marked red. */ + +class QWORKBENCH_UTILS_EXPORT BaseValidatingLineEdit : public QLineEdit { + Q_OBJECT + Q_DISABLE_COPY(BaseValidatingLineEdit) + Q_PROPERTY(QString initialText READ initialText WRITE setInitialText DESIGNABLE true) + Q_PROPERTY(QColor errorColor READ errorColor WRITE setErrorColor DESIGNABLE true) + +public: + enum State { Invalid, DisplayingInitialText, Valid }; + + explicit BaseValidatingLineEdit(QWidget *parent = 0); + virtual ~BaseValidatingLineEdit(); + + + State state() const; + bool isValid() const; + QString errorMessage() const; + + QString initialText() const; + void setInitialText(const QString &); + + QColor errorColor() const; + void setErrorColor(const QColor &); + + static QColor textColor(const QWidget *w); + static void setTextColor(QWidget *w, const QColor &c); + +signals: + void validChanged(); + void validReturnPressed(); + +protected: + virtual bool validate(const QString &value, QString *errorMessage) const = 0; + +protected slots: + // Custom behaviour can be added here. The base implementation must + // be called. + virtual void slotReturnPressed(); + virtual void slotChanged(const QString &t); + +private: + BaseValidatingLineEditPrivate *m_bd; +}; + +} +} +#endif // BASEVALIDATINGLINEEDIT_H diff --git a/src/libs/utils/classnamevalidatinglineedit.cpp b/src/libs/utils/classnamevalidatinglineedit.cpp new file mode 100644 index 00000000000..b52758eda5f --- /dev/null +++ b/src/libs/utils/classnamevalidatinglineedit.cpp @@ -0,0 +1,137 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "classnamevalidatinglineedit.h" + +#include <QtCore/QDebug> +#include <QtCore/QRegExp> + +namespace Core { +namespace Utils { + +struct ClassNameValidatingLineEditPrivate { + ClassNameValidatingLineEditPrivate(); + + const QRegExp m_nameRegexp; + const QString m_namespaceDelimiter; + bool m_namespacesEnabled; +}; + +// Match something like "Namespace1::Namespace2::ClassName". +ClassNameValidatingLineEditPrivate:: ClassNameValidatingLineEditPrivate() : + m_nameRegexp(QLatin1String("[a-zA-Z_][a-zA-Z0-9_]*(::[a-zA-Z_][a-zA-Z0-9_]*)*")), + m_namespaceDelimiter(QLatin1String("::")), + m_namespacesEnabled(false) +{ + Q_ASSERT(m_nameRegexp.isValid()); +} + +// --------------------- ClassNameValidatingLineEdit +ClassNameValidatingLineEdit::ClassNameValidatingLineEdit(QWidget *parent) : + Core::Utils::BaseValidatingLineEdit(parent), + m_d(new ClassNameValidatingLineEditPrivate) +{ +} + +ClassNameValidatingLineEdit::~ClassNameValidatingLineEdit() +{ + delete m_d; +} + +bool ClassNameValidatingLineEdit::namespacesEnabled() const +{ + return m_d->m_namespacesEnabled; +} + +void ClassNameValidatingLineEdit::setNamespacesEnabled(bool b) +{ + m_d->m_namespacesEnabled = b; +} + +bool ClassNameValidatingLineEdit::validate(const QString &value, QString *errorMessage) const +{ + if (!m_d->m_namespacesEnabled && value.contains(QLatin1Char(':'))) { + if (errorMessage) + *errorMessage = tr("The class name must not contain namespace delimiters."); + return false; + } + if (!m_d->m_nameRegexp.exactMatch(value)) { + if (errorMessage) + *errorMessage = tr("The class name contains invalid characters."); + return false; + } + return true; +} + +void ClassNameValidatingLineEdit::slotChanged(const QString &t) +{ + Core::Utils::BaseValidatingLineEdit::slotChanged(t); + if (isValid()) { + // Suggest file names, strip namespaces + QString fileName = t.toLower(); + if (m_d->m_namespacesEnabled) { + const int namespaceIndex = fileName.lastIndexOf(m_d->m_namespaceDelimiter); + if (namespaceIndex != -1) + fileName.remove(0, namespaceIndex + m_d->m_namespaceDelimiter.size()); + } + emit updateFileName(fileName); + } +} + +QString ClassNameValidatingLineEdit::createClassName(const QString &name) +{ + // Remove spaces and convert the adjacent characters to uppercase + QString className = name; + QRegExp spaceMatcher(QLatin1String(" +(\\w)"), Qt::CaseSensitive, QRegExp::RegExp2); + Q_ASSERT(spaceMatcher.isValid()); + int pos; + while ((pos = spaceMatcher.indexIn(className)) != -1) { + className.replace(pos, spaceMatcher.matchedLength(), + spaceMatcher.cap(1).toUpper()); + } + + // Filter out any remaining invalid characters + className.remove(QRegExp(QLatin1String("[^a-zA-Z0-9_]"))); + + // If the first character is numeric, prefix the name with a "_" + if (className.at(0).isNumber()) { + className.prepend(QLatin1Char('_')); + } else { + // Convert the first character to uppercase + className.replace(0, 1, className.left(1).toUpper()); + } + + return className; +} + +} +} diff --git a/src/libs/utils/classnamevalidatinglineedit.h b/src/libs/utils/classnamevalidatinglineedit.h new file mode 100644 index 00000000000..c0a209d0d71 --- /dev/null +++ b/src/libs/utils/classnamevalidatinglineedit.h @@ -0,0 +1,79 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef CLASSNAMEVALIDATINGLINEEDIT_H +#define CLASSNAMEVALIDATINGLINEEDIT_H + +#include "utils_global.h" +#include "basevalidatinglineedit.h" + +namespace Core { +namespace Utils { + +struct ClassNameValidatingLineEditPrivate; + +/* A Line edit that validates a C++ class name and emits a signal + * to derive suggested file names from it. */ + +class QWORKBENCH_UTILS_EXPORT ClassNameValidatingLineEdit : + public Core::Utils::BaseValidatingLineEdit { + Q_DISABLE_COPY(ClassNameValidatingLineEdit) + Q_PROPERTY(bool namespacesEnabled READ namespacesEnabled WRITE setNamespacesEnabled DESIGNABLE true) + Q_OBJECT + +public: + explicit ClassNameValidatingLineEdit(QWidget *parent = 0); + virtual ~ClassNameValidatingLineEdit(); + + bool namespacesEnabled() const; + void setNamespacesEnabled(bool b); + + // Clean an input string to get a valid class name. + static QString createClassName(const QString &name); + +signals: + // Will be emitted with a suggestion for a base name of the + // source/header file of the class. + void updateFileName(const QString &t); + +protected: + virtual bool validate(const QString &value, QString *errorMessage) const; + virtual void slotChanged(const QString &t); + +private: + ClassNameValidatingLineEditPrivate *m_d; +}; + +} +} + +#endif // CLASSNAMEVALIDATINGLINEEDIT_H diff --git a/src/libs/utils/codegeneration.cpp b/src/libs/utils/codegeneration.cpp new file mode 100644 index 00000000000..3af484935a7 --- /dev/null +++ b/src/libs/utils/codegeneration.cpp @@ -0,0 +1,89 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "codegeneration.h" + +#include <QtCore/QTextStream> +#include <QtCore/QStringList> +#include <QtCore/QFileInfo> + +namespace Core { +namespace Utils { + +QWORKBENCH_UTILS_EXPORT QString headerGuard(const QString &file) +{ + QString rc = QFileInfo(file).baseName().toUpper(); + rc += QLatin1String("_H"); + return rc; +} + +QWORKBENCH_UTILS_EXPORT +void writeIncludeFileDirective(const QString &file, bool globalInclude, + QTextStream &str) +{ + const QChar opening = globalInclude ? QLatin1Char('<') : QLatin1Char('"'); + const QChar closing = globalInclude ? QLatin1Char('>') : QLatin1Char('"'); + str << QLatin1String("#include ") << opening << file << closing << QLatin1Char('\n'); +} + +QWORKBENCH_UTILS_EXPORT +QString writeOpeningNameSpaces(const QStringList &l, const QString &indent, + QTextStream &str) +{ + const int count = l.size(); + QString rc; + if (count) { + str << '\n'; + for (int i = 0; i < count; i++) { + str << rc << "namespace " << l.at(i) << " {\n"; + rc += indent; + } + str << '\n'; + } + return rc; +} + +QWORKBENCH_UTILS_EXPORT +void writeClosingNameSpaces(const QStringList &l, const QString &indent, + QTextStream &str) +{ + if (!l.empty()) + str << '\n'; + for (int i = l.size() - 1; i >= 0; i--) { + if (i) + str << QString(indent.size() * i, QLatin1Char(' ')); + str << "} // namespace " << l.at(i) << '\n'; + } +} + +} // namespace Utils +} // namespace Core diff --git a/src/libs/utils/codegeneration.h b/src/libs/utils/codegeneration.h new file mode 100644 index 00000000000..1a20c76d083 --- /dev/null +++ b/src/libs/utils/codegeneration.h @@ -0,0 +1,70 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef CODEGENERATION_H +#define CODEGENERATION_H + +#include "utils_global.h" +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE +class QTextStream; +class QStringList; +QT_END_NAMESPACE + +namespace Core { +namespace Utils { + +QWORKBENCH_UTILS_EXPORT QString headerGuard(const QString &file); + +QWORKBENCH_UTILS_EXPORT +void writeIncludeFileDirective(const QString &file, + bool globalInclude, + QTextStream &str); + +// Write opening namespaces and return an indentation string to be used +// in the following code if there are any. +QWORKBENCH_UTILS_EXPORT +QString writeOpeningNameSpaces(const QStringList &namespaces, + const QString &indent, + QTextStream &str); + +// Close namespacesnamespaces +QWORKBENCH_UTILS_EXPORT +void writeClosingNameSpaces(const QStringList &namespaces, + const QString &indent, + QTextStream &str); + +} // namespace Utils +} // namespace Core + +#endif // CODEGENERATION_H diff --git a/src/libs/utils/fancylineedit.cpp b/src/libs/utils/fancylineedit.cpp new file mode 100644 index 00000000000..e7e930c544e --- /dev/null +++ b/src/libs/utils/fancylineedit.cpp @@ -0,0 +1,317 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "fancylineedit.h" + +#include <QtCore/QEvent> +#include <QtCore/QDebug> +#include <QtCore/QString> +#include <QtGui/QApplication> +#include <QtGui/QMenu> +#include <QtGui/QMouseEvent> +#include <QtGui/QLabel> + +enum { margin = 6 }; + +namespace Core { +namespace Utils { + +static inline QString sideToStyleSheetString(FancyLineEdit::Side side) +{ + return side == FancyLineEdit::Left ? QLatin1String("left") : QLatin1String("right"); +} + +// Format style sheet for the label containing the pixmap. It has a margin on +// the outer side of the whole FancyLineEdit. +static QString labelStyleSheet(FancyLineEdit::Side side) +{ + QString rc = QLatin1String("QLabel { margin-"); + rc += sideToStyleSheetString(side); + rc += QLatin1String(": "); + rc += QString::number(margin); + rc += QLatin1Char('}'); + return rc; +} + +// --------- FancyLineEditPrivate as QObject with label +// event filter + +class FancyLineEditPrivate : public QObject { +public: + explicit FancyLineEditPrivate(QLineEdit *parent); + + virtual bool eventFilter(QObject *obj, QEvent *event); + + const QString m_leftLabelStyleSheet; + const QString m_rightLabelStyleSheet; + + QLineEdit *m_lineEdit; + QPixmap m_pixmap; + QMenu *m_menu; + QLabel *m_menuLabel; + FancyLineEdit::Side m_side; + bool m_useLayoutDirection; + bool m_menuTabFocusTrigger; + QString m_hintText; + bool m_showingHintText; +}; + + +FancyLineEditPrivate::FancyLineEditPrivate(QLineEdit *parent) : + QObject(parent), + m_leftLabelStyleSheet(labelStyleSheet(FancyLineEdit::Left)), + m_rightLabelStyleSheet(labelStyleSheet(FancyLineEdit::Right)), + m_lineEdit(parent), + m_menu(0), + m_menuLabel(0), + m_side(FancyLineEdit::Left), + m_useLayoutDirection(false), + m_menuTabFocusTrigger(false), + m_showingHintText(false) +{ +} + +bool FancyLineEditPrivate::eventFilter(QObject *obj, QEvent *event) +{ + if (!m_menu || obj != m_menuLabel) + return QObject::eventFilter(obj, event); + + switch (event->type()) { + case QEvent::MouseButtonPress: { + const QMouseEvent *me = static_cast<QMouseEvent *>(event); + m_menu->exec(me->globalPos()); + return true; + } + case QEvent::FocusIn: + if (m_menuTabFocusTrigger) { + m_lineEdit->setFocus(); + m_menu->exec(m_menuLabel->mapToGlobal(m_menuLabel->rect().center())); + return true; + } + default: + break; + } + return QObject::eventFilter(obj, event); +} + +// --------- FancyLineEdit +FancyLineEdit::FancyLineEdit(QWidget *parent) : + QLineEdit(parent), + m_d(new FancyLineEditPrivate(this)) +{ + m_d->m_menuLabel = new QLabel(this); + m_d->m_menuLabel->installEventFilter(m_d); + updateMenuLabel(); + showHintText(); +} + +FancyLineEdit::~FancyLineEdit() +{ +} + +// Position the menu label left or right according to size. +// Called when switching side and from resizeEvent. +void FancyLineEdit::positionMenuLabel() +{ + switch (side()) { + case Left: + m_d->m_menuLabel->setGeometry(0, 0, m_d->m_pixmap.width()+margin, height()); + break; + case Right: + m_d->m_menuLabel->setGeometry(width() - m_d->m_pixmap.width() - margin, 0, + m_d->m_pixmap.width()+margin, height()); + break; + } +} + +void FancyLineEdit::updateStyleSheet(Side side) +{ + // Udate the LineEdit style sheet. Make room for the label on the + // respective side and set color according to whether we are showing the + // hint text + QString sheet = QLatin1String("QLineEdit{ padding-"); + sheet += sideToStyleSheetString(side); + sheet += QLatin1String(": "); + sheet += QString::number(m_d->m_pixmap.width() + margin); + sheet += QLatin1Char(';'); + if (m_d->m_showingHintText) + sheet += QLatin1String(" color: #BBBBBB;"); + sheet += QLatin1Char('}'); + setStyleSheet(sheet); +} + +void FancyLineEdit::updateMenuLabel() +{ + m_d->m_menuLabel->setPixmap(m_d->m_pixmap); + const Side s = side(); + switch (s) { + case Left: + m_d->m_menuLabel->setAlignment(Qt::AlignVCenter | Qt::AlignLeft); + m_d->m_menuLabel->setStyleSheet(m_d->m_leftLabelStyleSheet); + break; + case Right: + m_d->m_menuLabel->setAlignment(Qt::AlignVCenter | Qt::AlignRight); + m_d->m_menuLabel->setStyleSheet(m_d->m_rightLabelStyleSheet); + break; + } + updateStyleSheet(s); + positionMenuLabel(); +} + +void FancyLineEdit::setSide(Side side) +{ + m_d->m_side = side; + updateMenuLabel(); +} + +FancyLineEdit::Side FancyLineEdit::side() const +{ + if (m_d->m_useLayoutDirection) + return qApp->layoutDirection() == Qt::LeftToRight ? Left : Right; + return m_d->m_side; +} + +void FancyLineEdit::resizeEvent(QResizeEvent *) +{ + positionMenuLabel(); +} + +void FancyLineEdit::setPixmap(const QPixmap &pixmap) +{ + m_d->m_pixmap = pixmap; + updateMenuLabel(); +} + +QPixmap FancyLineEdit::pixmap() const +{ + return m_d->m_pixmap; +} + +void FancyLineEdit::setMenu(QMenu *menu) +{ + m_d->m_menu = menu; +} + +QMenu *FancyLineEdit::menu() const +{ + return m_d->m_menu; +} + +bool FancyLineEdit::useLayoutDirection() const +{ + return m_d->m_useLayoutDirection; +} + +void FancyLineEdit::setUseLayoutDirection(bool v) +{ + m_d->m_useLayoutDirection = v; +} + +bool FancyLineEdit::isSideStored() const +{ + return !m_d->m_useLayoutDirection; +} + +bool FancyLineEdit::hasMenuTabFocusTrigger() const +{ + return m_d->m_menuTabFocusTrigger; +} + +void FancyLineEdit::setMenuTabFocusTrigger(bool v) +{ + if (m_d->m_menuTabFocusTrigger == v) + return; + + m_d->m_menuTabFocusTrigger = v; + m_d->m_menuLabel->setFocusPolicy(v ? Qt::TabFocus : Qt::NoFocus); +} + +QString FancyLineEdit::hintText() const +{ + return m_d->m_hintText; +} + +void FancyLineEdit::setHintText(const QString &ht) +{ + // Updating magic to make the property work in Designer. + if (ht == m_d->m_hintText) + return; + hideHintText(); + m_d->m_hintText = ht; + if (!hasFocus() && !ht.isEmpty()) + showHintText(); +} + +void FancyLineEdit::showHintText() +{ + if (!m_d->m_showingHintText && text().isEmpty() && !m_d->m_hintText.isEmpty()) { + m_d->m_showingHintText = true; + setText(m_d->m_hintText); + updateStyleSheet(side()); + } +} + +void FancyLineEdit::hideHintText() +{ + if (m_d->m_showingHintText && !m_d->m_hintText.isEmpty()) { + m_d->m_showingHintText = false; + setText(QString()); + updateStyleSheet(side()); + } +} + +void FancyLineEdit::focusInEvent(QFocusEvent *e) +{ + hideHintText(); + QLineEdit::focusInEvent(e); +} + +void FancyLineEdit::focusOutEvent(QFocusEvent *e) +{ + // Focus out: Switch to displaying the hint text unless + // there is user input + showHintText(); + QLineEdit::focusOutEvent(e); +} + +bool FancyLineEdit::isShowingHintText() const +{ + return m_d->m_showingHintText; +} + +QString FancyLineEdit::typedText() const +{ + return m_d->m_showingHintText ? QString() : text(); +} + +} // namespace Utils +} // namespace Core diff --git a/src/libs/utils/fancylineedit.h b/src/libs/utils/fancylineedit.h new file mode 100644 index 00000000000..24a109eada3 --- /dev/null +++ b/src/libs/utils/fancylineedit.h @@ -0,0 +1,115 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef FANCYLINEEDIT_H +#define FANCYLINEEDIT_H + +#include "utils_global.h" + +#include <QtGui/QLineEdit> + +namespace Core { +namespace Utils { + +class FancyLineEditPrivate; + +/* A line edit with an embedded pixmap on one side that is connected to + * a menu. Additionally, it can display a grayed hintText (like "Type Here to") + * when not focussed and empty. When connecting to the changed signals and + * querying text, one has to be aware that the text is set to that hint + * text if isShowingHintText() returns true (that is, does not contain + * valid user input). + */ +class QWORKBENCH_UTILS_EXPORT FancyLineEdit : public QLineEdit +{ + Q_DISABLE_COPY(FancyLineEdit) + Q_OBJECT + Q_ENUMS(Side) + Q_PROPERTY(QPixmap pixmap READ pixmap WRITE setPixmap DESIGNABLE true) + Q_PROPERTY(Side side READ side WRITE setSide DESIGNABLE isSideStored STORED isSideStored) + Q_PROPERTY(bool useLayoutDirection READ useLayoutDirection WRITE setUseLayoutDirection DESIGNABLE true) + Q_PROPERTY(bool menuTabFocusTrigger READ hasMenuTabFocusTrigger WRITE setMenuTabFocusTrigger DESIGNABLE true) + Q_PROPERTY(QString hintText READ hintText WRITE setHintText DESIGNABLE true) + +public: + enum Side {Left, Right}; + + explicit FancyLineEdit(QWidget *parent = 0); + ~FancyLineEdit(); + + QPixmap pixmap() const; + + void setMenu(QMenu *menu); + QMenu *menu() const; + + void setSide(Side side); + Side side() const; + + bool useLayoutDirection() const; + void setUseLayoutDirection(bool v); + + /* Set whether tabbing in will trigger the menu. */ + bool hasMenuTabFocusTrigger() const; + void setMenuTabFocusTrigger(bool v); + + /* Hint text that is displayed when no focus is set */ + QString hintText() const; + + bool isShowingHintText() const; + + // Convenience for accessing the text that returns "" in case of isShowingHintText(). + QString typedText() const; + +public slots: + void setPixmap(const QPixmap &pixmap); + void setHintText(const QString &ht); + void showHintText(); + void hideHintText(); + +protected: + virtual void resizeEvent(QResizeEvent *e); + virtual void focusInEvent(QFocusEvent *e); + virtual void focusOutEvent(QFocusEvent *e); + +private: + bool isSideStored() const; + void updateMenuLabel(); + void positionMenuLabel(); + void updateStyleSheet(Side side); + + FancyLineEditPrivate *m_d; +}; + +} // namespace Utils +} // namespace Core + +#endif // FANCYLINEEDIT_H diff --git a/src/libs/utils/filenamevalidatinglineedit.cpp b/src/libs/utils/filenamevalidatinglineedit.cpp new file mode 100644 index 00000000000..1beed717efd --- /dev/null +++ b/src/libs/utils/filenamevalidatinglineedit.cpp @@ -0,0 +1,97 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "filenamevalidatinglineedit.h" + +namespace Core { +namespace Utils { + +FileNameValidatingLineEdit::FileNameValidatingLineEdit(QWidget *parent) : + BaseValidatingLineEdit(parent) +{ + +} + +/* Validate a file base name, check for forbidden characters/strings. */ + +static const char *notAllowedChars = "/?:&\\*\"|#%<> "; +static const char *notAllowedSubStrings[] = {".."}; + +// Naming a file like a device name will break on Windows, even if it is +// "com1.txt". Since we are cross-platform, we generally disallow such file +// names. +static const char *notAllowedStrings[] = {"CON", "AUX", "PRN", "COM1", "COM2", "LPT1", "LPT2" }; + +bool FileNameValidatingLineEdit::validateFileName(const QString &name, QString *errorMessage /* = 0*/) +{ + if (name.isEmpty()) { + if (errorMessage) + *errorMessage = tr("The name must not be empty"); + return false; + } + // Characters + for (const char *c = notAllowedChars; *c; c++) + if (name.contains(QLatin1Char(*c))) { + if (errorMessage) + *errorMessage = tr("The name must not contain any of the characters '%1'.").arg(QLatin1String(notAllowedChars)); + return false; + } + // Substrings + const int notAllowedSubStringCount = sizeof(notAllowedSubStrings)/sizeof(const char *); + for (int s = 0; s < notAllowedSubStringCount; s++) { + const QLatin1String notAllowedSubString(notAllowedSubStrings[s]); + if (name.contains(notAllowedSubString)) { + if (errorMessage) + *errorMessage = tr("The name must not contain '%1'.").arg(QString(notAllowedSubString)); + return false; + } + } + // Strings + const int notAllowedStringCount = sizeof(notAllowedStrings)/sizeof(const char *); + for (int s = 0; s < notAllowedStringCount; s++) { + const QLatin1String notAllowedString(notAllowedStrings[s]); + if (name == notAllowedString) { + if (errorMessage) + *errorMessage = tr("The name must not be '%1'.").arg(QString(notAllowedString)); + return false; + } + } + return true; +} + +bool FileNameValidatingLineEdit::validate(const QString &value, QString *errorMessage) const +{ + return validateFileName(value, errorMessage); +} + +} +} diff --git a/src/libs/utils/filenamevalidatinglineedit.h b/src/libs/utils/filenamevalidatinglineedit.h new file mode 100644 index 00000000000..7535fc196de --- /dev/null +++ b/src/libs/utils/filenamevalidatinglineedit.h @@ -0,0 +1,56 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef FILENAMEVALIDATINGLINEEDIT_H +#define FILENAMEVALIDATINGLINEEDIT_H + +#include "basevalidatinglineedit.h" + +namespace Core { +namespace Utils { + +class QWORKBENCH_UTILS_EXPORT FileNameValidatingLineEdit : public BaseValidatingLineEdit { + Q_OBJECT + Q_DISABLE_COPY(FileNameValidatingLineEdit) + +public: + explicit FileNameValidatingLineEdit(QWidget *parent = 0); + + static bool validateFileName(const QString &name, QString *errorMessage /* = 0*/); + +protected: + virtual bool validate(const QString &value, QString *errorMessage) const; +}; + +} +} +#endif // FILENAMEVALIDATINGLINEEDIT_H diff --git a/src/libs/utils/filesearch.cpp b/src/libs/utils/filesearch.cpp new file mode 100644 index 00000000000..9756984b4b0 --- /dev/null +++ b/src/libs/utils/filesearch.cpp @@ -0,0 +1,216 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "filesearch.h" + +#include <QtCore/QFile> +#include <QtCore/QDir> +#include <QtCore/QFutureInterface> +#include <QtCore/QtConcurrentRun> +#include <QtCore/QRegExp> +#include <QtGui/QApplication> + +#include <qtconcurrent/runextensions.h> + +using namespace Core::Utils; + +namespace { + void runFileSearch(QFutureInterface<FileSearchResult> &future, + QString searchTerm, + QStringList files, + QTextDocument::FindFlags flags) + { + future.setProgressRange(0, files.size()); + int numFilesSearched = 0; + int numMatches = 0; + + bool caseInsensitive = !(flags & QTextDocument::FindCaseSensitively); + bool wholeWord = (flags & QTextDocument::FindWholeWords); + + QByteArray sa = searchTerm.toUtf8(); + int scMaxIndex = sa.length()-1; + const char *sc = sa.constData(); + + QByteArray sal = searchTerm.toLower().toUtf8(); + const char *scl = sal.constData(); + + QByteArray sau = searchTerm.toUpper().toUtf8(); + const char *scu = sau.constData(); + + int chunkSize = qMax(100000, sa.length()); + + foreach (QString s, files) { + if (future.isPaused()) + future.waitForResume(); + if (future.isCanceled()) { + future.setProgressValueAndText(numFilesSearched, + qApp->translate("FileSearch", "%1: canceled. %2 occurrences found in %3 files."). + arg(searchTerm).arg(numMatches).arg(numFilesSearched)); + break; + } + QFile file(s); + if (!file.open(QIODevice::ReadOnly)) + continue; + int lineNr = 1; + const char *startOfLastLine = NULL; + + bool firstChunk = true; + while (!file.atEnd()) { + if (!firstChunk) + file.seek(file.pos()-sa.length()+1); + + const QByteArray chunk = file.read(chunkSize); + const char *chunkPtr = chunk.constData(); + startOfLastLine = chunkPtr; + for (const char *regionPtr = chunkPtr; regionPtr < chunkPtr + chunk.length()-scMaxIndex; ++regionPtr) { + const char *regionEnd = regionPtr + scMaxIndex; + + if (*regionPtr == '\n') { + startOfLastLine = regionPtr + 1; + ++lineNr; + } + else if ( + // case sensitive + (!caseInsensitive && *regionPtr == sc[0] && *regionEnd == sc[scMaxIndex]) + || + // case insensitive + (caseInsensitive && (*regionPtr == scl[0] || *regionPtr == scu[0]) + && (*regionEnd == scl[scMaxIndex] || *regionEnd == scu[scMaxIndex])) + ) { + const char *afterRegion = regionEnd + 1; + const char *beforeRegion = regionPtr - 1; + bool equal = true; + if (wholeWord && + ( ((*beforeRegion >= '0' && *beforeRegion <= '9') || *beforeRegion >= 'A') + || ((*afterRegion >= '0' && *afterRegion <= '9') || *afterRegion >= 'A'))) + { + equal = false; + } + + int regionIndex = 1; + for (const char *regionCursor = regionPtr + 1; regionCursor < regionEnd; ++regionCursor, ++regionIndex) { + if ( // case sensitive + (!caseInsensitive && equal && *regionCursor != sc[regionIndex]) + || + // case insensitive + (caseInsensitive && equal && *regionCursor != sc[regionIndex] && *regionCursor != scl[regionIndex] && *regionCursor != scu[regionIndex]) + ) { + equal = false; + } + } + if (equal) { + int textLength = chunk.length() - (startOfLastLine - chunkPtr); + if (textLength > 0) { + QByteArray res; + res.reserve(256); + int i = 0; + int n = 0; + while (startOfLastLine[i] != '\n' && startOfLastLine[i] != '\r' && i < textLength && n++ < 256) + res.append(startOfLastLine[i++]); + future.reportResult(FileSearchResult(QDir::toNativeSeparators(s), lineNr, QString(res), + regionPtr - startOfLastLine, sa.length())); + ++numMatches; + } + } + } + } + firstChunk = false; + } + ++numFilesSearched; + future.setProgressValueAndText(numFilesSearched, qApp->translate("FileSearch", "%1: %2 occurrences found in %3 of %4 files."). + arg(searchTerm).arg(numMatches).arg(numFilesSearched).arg(files.size())); + } + if (!future.isCanceled()) + future.setProgressValueAndText(numFilesSearched, qApp->translate("FileSearch", "%1: %2 occurrences found in %3 files."). + arg(searchTerm).arg(numMatches).arg(numFilesSearched)); + } + + void runFileSearchRegExp(QFutureInterface<FileSearchResult> &future, + QString searchTerm, + QStringList files, + QTextDocument::FindFlags flags) + { + future.setProgressRange(0, files.size()); + int numFilesSearched = 0; + int numMatches = 0; + if (flags & QTextDocument::FindWholeWords) + searchTerm = QString("\b%1\b").arg(searchTerm); + Qt::CaseSensitivity caseSensitivity = (flags & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive; + QRegExp expression(searchTerm, caseSensitivity); + + foreach (QString s, files) { + if (future.isPaused()) + future.waitForResume(); + if (future.isCanceled()) { + future.setProgressValueAndText(numFilesSearched, + qApp->translate("FileSearch", "%1: canceled. %2 occurrences found in %3 files."). + arg(searchTerm).arg(numMatches).arg(numFilesSearched)); + break; + } + QFile file(s); + if (!file.open(QIODevice::ReadOnly)) + continue; + QTextStream stream(&file); + int lineNr = 1; + QString line; + while (!stream.atEnd()) { + line = stream.readLine(); + int pos = 0; + while ((pos = expression.indexIn(line, pos)) != -1) { + future.reportResult(FileSearchResult(QDir::toNativeSeparators(s), lineNr, line, + pos, expression.matchedLength())); + pos += expression.matchedLength(); + } + ++lineNr; + } + ++numFilesSearched; + future.setProgressValueAndText(numFilesSearched, qApp->translate("FileSearch", "%1: %2 occurrences found in %3 of %4 files."). + arg(searchTerm).arg(numMatches).arg(numFilesSearched).arg(files.size())); + } + if (!future.isCanceled()) + future.setProgressValueAndText(numFilesSearched, qApp->translate("FileSearch", "%1: %2 occurrences found in %3 files."). + arg(searchTerm).arg(numMatches).arg(numFilesSearched)); + } +} // namespace + + +QFuture<FileSearchResult> Core::Utils::findInFiles(const QString &searchTerm, const QStringList &files, + QTextDocument::FindFlags flags) +{ + return QtConcurrent::run<FileSearchResult, QString, QStringList, QTextDocument::FindFlags>(runFileSearch, searchTerm, files, flags); +} + +QFuture<FileSearchResult> Core::Utils::findInFilesRegExp(const QString &searchTerm, const QStringList &files, + QTextDocument::FindFlags flags) +{ + return QtConcurrent::run<FileSearchResult, QString, QStringList, QTextDocument::FindFlags>(runFileSearchRegExp, searchTerm, files, flags); +} diff --git a/src/libs/utils/filesearch.h b/src/libs/utils/filesearch.h new file mode 100644 index 00000000000..3b747fb5489 --- /dev/null +++ b/src/libs/utils/filesearch.h @@ -0,0 +1,69 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef FILESEARCH_H +#define FILESEARCH_H + +#include "utils_global.h" + +#include <QtCore/QStringList> +#include <QtCore/QFuture> +#include <QtGui/QTextDocument> + +namespace Core { +namespace Utils { + +class QWORKBENCH_UTILS_EXPORT FileSearchResult +{ +public: + FileSearchResult() {} + FileSearchResult(QString fileName, int lineNumber, QString matchingLine, int matchStart, int matchLength) + : fileName(fileName), lineNumber(lineNumber), matchingLine(matchingLine), matchStart(matchStart), matchLength(matchLength) + { + } + QString fileName; + int lineNumber; + QString matchingLine; + int matchStart; + int matchLength; +}; + +QWORKBENCH_UTILS_EXPORT QFuture<FileSearchResult> findInFiles(const QString &searchTerm, const QStringList &files, + QTextDocument::FindFlags flags); + +QWORKBENCH_UTILS_EXPORT QFuture<FileSearchResult> findInFilesRegExp(const QString &searchTerm, const QStringList &files, + QTextDocument::FindFlags flags); + +} //Utils +} //Core + +#endif diff --git a/src/libs/utils/filewizarddialog.cpp b/src/libs/utils/filewizarddialog.cpp new file mode 100644 index 00000000000..2843a304e5b --- /dev/null +++ b/src/libs/utils/filewizarddialog.cpp @@ -0,0 +1,73 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "filewizarddialog.h" +#include "filewizardpage.h" + +#include <QtGui/QAbstractButton> + +namespace Core { +namespace Utils { + +FileWizardDialog::FileWizardDialog(QWidget *parent) : + QWizard(parent), + m_filePage(new FileWizardPage) +{ + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setPixmap(QWizard::WatermarkPixmap, QPixmap(QLatin1String(":/qworkbench/images/qtwatermark.png"))); + addPage(m_filePage); + connect(m_filePage, SIGNAL(activated()), button(QWizard::FinishButton), SLOT(animateClick())); +} + +QString FileWizardDialog::name() const +{ + return m_filePage->name(); +} + +QString FileWizardDialog::path() const +{ + return m_filePage->path(); +} + +void FileWizardDialog::setPath(const QString &path) +{ + m_filePage->setPath(path); + +} + +void FileWizardDialog::setName(const QString &name) +{ + m_filePage->setName(name); +} + +} // namespace Utils +} // namespace Core diff --git a/src/libs/utils/filewizarddialog.h b/src/libs/utils/filewizarddialog.h new file mode 100644 index 00000000000..6a4a7d9ba6f --- /dev/null +++ b/src/libs/utils/filewizarddialog.h @@ -0,0 +1,69 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef FILEWIZARDDIALOG_H +#define FILEWIZARDDIALOG_H + +#include "utils_global.h" + +#include <QtGui/QWizard> + +namespace Core { +namespace Utils { + +class FileWizardPage; + +/* + Standard wizard for a single file letting the user choose name + and path. Custom pages can be added via Core::IWizardExtension. +*/ + +class QWORKBENCH_UTILS_EXPORT FileWizardDialog : public QWizard { + Q_OBJECT + Q_DISABLE_COPY(FileWizardDialog) +public: + explicit FileWizardDialog(QWidget *parent = 0); + + QString name() const; + QString path() const; + +public slots: + void setPath(const QString &path); + void setName(const QString &name); + +private: + FileWizardPage *m_filePage; +}; + +} +} +#endif // FILEWIZARDDIALOG_H diff --git a/src/libs/utils/filewizardpage.cpp b/src/libs/utils/filewizardpage.cpp new file mode 100644 index 00000000000..a448ebe7395 --- /dev/null +++ b/src/libs/utils/filewizardpage.cpp @@ -0,0 +1,129 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "filewizardpage.h" +#include "ui_filewizardpage.h" + +#include <QtCore/QDebug> +#include <QtCore/QDir> +#include <QtGui/QMessageBox> + +namespace Core { +namespace Utils { + +struct FileWizardPagePrivate +{ + FileWizardPagePrivate(); + Ui::WizardPage m_ui; + bool m_complete; +}; + +FileWizardPagePrivate::FileWizardPagePrivate() : + m_complete(false) +{ +} + +FileWizardPage::FileWizardPage(QWidget *parent) : + QWizardPage(parent), + m_d(new FileWizardPagePrivate) +{ + m_d->m_ui.setupUi(this); + connect(m_d->m_ui.pathChooser, SIGNAL(validChanged()), this, SLOT(slotValidChanged())); + connect(m_d->m_ui.nameLineEdit, SIGNAL(validChanged()), this, SLOT(slotValidChanged())); + + connect(m_d->m_ui.pathChooser, SIGNAL(returnPressed()), this, SLOT(slotActivated())); + connect(m_d->m_ui.nameLineEdit, SIGNAL(validReturnPressed()), this, SLOT(slotActivated())); +} + +FileWizardPage::~FileWizardPage() +{ + delete m_d; +} + +QString FileWizardPage::name() const +{ + return m_d->m_ui.nameLineEdit->text(); +} + +QString FileWizardPage::path() const +{ + return m_d->m_ui.pathChooser->path(); +} + +void FileWizardPage::setPath(const QString &path) +{ + m_d->m_ui.pathChooser->setPath(path); +} + +void FileWizardPage::setName(const QString &name) +{ + m_d->m_ui.nameLineEdit->setText(name); +} + +void FileWizardPage::changeEvent(QEvent *e) +{ + switch(e->type()) { + case QEvent::LanguageChange: + m_d->m_ui.retranslateUi(this); + break; + default: + break; + } +} + +bool FileWizardPage::isComplete() const +{ + return m_d->m_complete; +} + +void FileWizardPage::slotValidChanged() +{ + const bool newComplete = m_d->m_ui.pathChooser->isValid() && m_d->m_ui.nameLineEdit->isValid(); + if (newComplete != m_d->m_complete) { + m_d->m_complete = newComplete; + emit completeChanged(); + } +} + +void FileWizardPage::slotActivated() +{ + if (m_d->m_complete) + emit activated(); +} + +bool FileWizardPage::validateBaseName(const QString &name, QString *errorMessage /* = 0*/) +{ + return FileNameValidatingLineEdit::validateFileName(name, errorMessage); +} + +} // namespace Utils +} // namespace Core diff --git a/src/libs/utils/filewizardpage.h b/src/libs/utils/filewizardpage.h new file mode 100644 index 00000000000..b2ae28a9d0d --- /dev/null +++ b/src/libs/utils/filewizardpage.h @@ -0,0 +1,86 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef FILEWIZARDPAGE_H +#define FILEWIZARDPAGE_H + +#include "utils_global.h" + +#include <QtGui/QWizardPage> + +namespace Core { +namespace Utils { + +struct FileWizardPagePrivate; + +/* Standard wizard page for a single file letting the user choose name + * and path. Sets the "FileNames" QWizard field. */ + +class QWORKBENCH_UTILS_EXPORT FileWizardPage : public QWizardPage { + Q_OBJECT + Q_DISABLE_COPY(FileWizardPage) + Q_PROPERTY(QString path READ path WRITE setPath DESIGNABLE true) + Q_PROPERTY(QString name READ name WRITE setName DESIGNABLE true) +public: + explicit FileWizardPage(QWidget *parent = 0); + virtual ~FileWizardPage(); + + QString name() const; + QString path() const; + + virtual bool isComplete() const; + + // Validate a base name entry field (potentially containing extension) + static bool validateBaseName(const QString &name, QString *errorMessage = 0); + +signals: + void activated(); + void pathChanged(); + +public slots: + void setPath(const QString &path); + void setName(const QString &name); + +private slots: + void slotValidChanged(); + void slotActivated(); + +protected: + virtual void changeEvent(QEvent *e); + +private: + FileWizardPagePrivate *m_d; +}; + +} +} +#endif // FILEWIZARDPAGE_H diff --git a/src/libs/utils/filewizardpage.ui b/src/libs/utils/filewizardpage.ui new file mode 100644 index 00000000000..2e614c6f552 --- /dev/null +++ b/src/libs/utils/filewizardpage.ui @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Core::Utils::WizardPage</class> + <widget class="QWizardPage" name="Core::Utils::WizardPage"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>WizardPage</string> + </property> + <property name="title"> + <string>Choose the location</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QWidget" name="widget" native="true"> + <layout class="QFormLayout" name="formLayout"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="nameLabel"> + <property name="text"> + <string>Name:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="Core::Utils::FileNameValidatingLineEdit" name="nameLineEdit"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="pathLabel"> + <property name="text"> + <string>Path:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="Core::Utils::PathChooser" name="pathChooser" native="true"/> + </item> + </layout> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>201</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>Core::Utils::PathChooser</class> + <extends>QWidget</extends> + <header>pathchooser.h</header> + <container>1</container> + </customwidget> + <customwidget> + <class>Core::Utils::FileNameValidatingLineEdit</class> + <extends>QLineEdit</extends> + <header>filenamevalidatinglineedit.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/src/libs/utils/linecolumnlabel.cpp b/src/libs/utils/linecolumnlabel.cpp new file mode 100644 index 00000000000..c6028ab13ff --- /dev/null +++ b/src/libs/utils/linecolumnlabel.cpp @@ -0,0 +1,69 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "linecolumnlabel.h" + +namespace Core { +namespace Utils { + +LineColumnLabel::LineColumnLabel(QWidget *parent) : + QLabel(parent), + m_unused(0) +{ +} + +LineColumnLabel::~LineColumnLabel() +{ +} + +void LineColumnLabel::setText(const QString &text, const QString &maxText) +{ + QLabel::setText(text); + m_maxText = maxText; +} +QSize LineColumnLabel::sizeHint() const +{ + return fontMetrics().boundingRect(m_maxText).size(); +} + +QString LineColumnLabel::maxText() const +{ + return m_maxText; +} + +void LineColumnLabel::setMaxText(const QString &maxText) +{ + m_maxText = maxText; +} + +} +} diff --git a/src/libs/utils/linecolumnlabel.h b/src/libs/utils/linecolumnlabel.h new file mode 100644 index 00000000000..d5dea084cc2 --- /dev/null +++ b/src/libs/utils/linecolumnlabel.h @@ -0,0 +1,68 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef LINECOLUMNLABEL_H +#define LINECOLUMNLABEL_H + +#include "utils_global.h" +#include <QtGui/QLabel> + +namespace Core { +namespace Utils { + +/* A label suitable for displaying cursor positions, etc. with a fixed + * with derived from a sample text. */ + +class QWORKBENCH_UTILS_EXPORT LineColumnLabel : public QLabel { + Q_DISABLE_COPY(LineColumnLabel) + Q_OBJECT + Q_PROPERTY(QString maxText READ maxText WRITE setMaxText DESIGNABLE true) + +public: + explicit LineColumnLabel(QWidget *parent = 0); + virtual ~LineColumnLabel(); + + void setText(const QString &text, const QString &maxText); + QSize sizeHint() const; + + QString maxText() const; + void setMaxText(const QString &maxText); + +private: + QString m_maxText; + void *m_unused; +}; + +} +} + +#endif // LINECOLUMNLABEL_H diff --git a/src/libs/utils/listutils.h b/src/libs/utils/listutils.h new file mode 100644 index 00000000000..3b688f336df --- /dev/null +++ b/src/libs/utils/listutils.h @@ -0,0 +1,54 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef LISTUTILS_H +#define LISTUTILS_H + +#include <QtCore/QList> + +namespace Core { +namespace Utils { + +template <class T1, class T2> +QList<T1> qwConvertList(const QList<T2> &list) +{ + QList<T1> convertedList; + foreach (T2 listEntry, list) { + convertedList << qobject_cast<T1>(listEntry); + } + return convertedList; +} + +} // Utils +} // Core + +#endif // LISTUTILS_H diff --git a/src/libs/utils/newclasswidget.cpp b/src/libs/utils/newclasswidget.cpp new file mode 100644 index 00000000000..67cd1f8691d --- /dev/null +++ b/src/libs/utils/newclasswidget.cpp @@ -0,0 +1,462 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "newclasswidget.h" +#include "ui_newclasswidget.h" + +#include <utils/filewizardpage.h> + +#include <QtGui/QFileDialog> +#include <QtCore/QFileInfo> +#include <QtCore/QStringList> +#include <QtCore/QDir> +#include <QtCore/QDebug> +#include <QtCore/QRegExp> + +enum { debugNewClassWidget = 0 }; + +namespace Core { +namespace Utils { + +struct NewClassWidgetPrivate { + NewClassWidgetPrivate(); + + Ui::NewClassWidget m_ui; + QString m_headerExtension; + QString m_sourceExtension; + QString m_formExtension; + bool m_valid; + bool m_classEdited; + // Store the "visible" values to prevent the READ accessors from being + // fooled by a temporarily hidden widget + bool m_baseClassInputVisible; + bool m_formInputVisible; + bool m_pathInputVisible; + bool m_formInputCheckable; +}; + +NewClassWidgetPrivate:: NewClassWidgetPrivate() : + m_headerExtension(QLatin1String("h")), + m_sourceExtension(QLatin1String("cpp")), + m_formExtension(QLatin1String("ui")), + m_valid(false), + m_classEdited(false), + m_baseClassInputVisible(true), + m_formInputVisible(true), + m_pathInputVisible(true), + m_formInputCheckable(false) +{ +} + +// --------------------- NewClassWidget +NewClassWidget::NewClassWidget(QWidget *parent) : + QWidget(parent), + m_d(new NewClassWidgetPrivate) +{ + m_d->m_ui.setupUi(this); + + m_d->m_ui.baseClassComboBox->setEditable(false); + + connect(m_d->m_ui.classLineEdit, SIGNAL(updateFileName(QString)), + this, SLOT(updateFileNames(QString))); + connect(m_d->m_ui.classLineEdit, SIGNAL(textEdited(QString)), + this, SLOT(classNameEdited())); + connect(m_d->m_ui.baseClassComboBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(suggestClassNameFromBase())); + connect(m_d->m_ui.baseClassComboBox, SIGNAL(editTextChanged(QString)), + this, SLOT(slotValidChanged())); + connect(m_d->m_ui.classLineEdit, SIGNAL(validChanged()), + this, SLOT(slotValidChanged())); + connect(m_d->m_ui.headerFileLineEdit, SIGNAL(validChanged()), + this, SLOT(slotValidChanged())); + connect(m_d->m_ui.sourceFileLineEdit, SIGNAL(validChanged()), + this, SLOT(slotValidChanged())); + connect(m_d->m_ui.formFileLineEdit, SIGNAL(validChanged()), + this, SLOT(slotValidChanged())); + connect(m_d->m_ui.pathChooser, SIGNAL(validChanged()), + this, SLOT(slotValidChanged())); + + connect(m_d->m_ui.classLineEdit, SIGNAL(validReturnPressed()), + this, SLOT(slotActivated())); + connect(m_d->m_ui.headerFileLineEdit, SIGNAL(validReturnPressed()), + this, SLOT(slotActivated())); + connect(m_d->m_ui.sourceFileLineEdit, SIGNAL(validReturnPressed()), + this, SLOT(slotActivated())); + connect(m_d->m_ui.formFileLineEdit, SIGNAL(validReturnPressed()), + this, SLOT(slotActivated())); + connect(m_d->m_ui.formFileLineEdit, SIGNAL(validReturnPressed()), + this, SLOT(slotActivated())); + connect(m_d->m_ui.pathChooser, SIGNAL(returnPressed()), + this, SLOT(slotActivated())); + + connect(m_d->m_ui.generateFormCheckBox, SIGNAL(stateChanged(int)), + this, SLOT(slotFormInputChecked())); + + m_d->m_ui.generateFormCheckBox->setChecked(true); + setFormInputCheckable(false, true); +} + +NewClassWidget::~NewClassWidget() +{ + delete m_d; +} + +void NewClassWidget::classNameEdited() +{ + if (debugNewClassWidget) + qDebug() << Q_FUNC_INFO << m_d->m_headerExtension << m_d->m_sourceExtension; + m_d->m_classEdited = true; +} + +void NewClassWidget::suggestClassNameFromBase() +{ + if (debugNewClassWidget) + qDebug() << Q_FUNC_INFO << m_d->m_headerExtension << m_d->m_sourceExtension; + if (m_d->m_classEdited) + return; + // Suggest a class unless edited ("QMainWindow"->"MainWindow") + QString base = baseClassName(); + if (base.startsWith(QLatin1Char('Q'))) { + base.remove(0, 1); + setClassName(base); + } +} + +QStringList NewClassWidget::baseClassChoices() const +{ + QStringList rc; + const int count = m_d->m_ui.baseClassComboBox->count(); + for (int i = 0; i < count; i++) + rc.push_back(m_d->m_ui.baseClassComboBox->itemText(i)); + return rc; +} + +void NewClassWidget::setBaseClassChoices(const QStringList &choices) +{ + m_d->m_ui.baseClassComboBox->clear(); + m_d->m_ui.baseClassComboBox->addItems(choices); +} + +void NewClassWidget::setBaseClassInputVisible(bool visible) +{ + m_d->m_baseClassInputVisible = visible; + m_d->m_ui.baseClassLabel->setVisible(visible); + m_d->m_ui.baseClassComboBox->setVisible(visible); +} + +void NewClassWidget::setBaseClassEditable(bool editable) +{ + m_d->m_ui.baseClassComboBox->setEditable(editable); +} + +bool NewClassWidget::isBaseClassInputVisible() const +{ + return m_d->m_baseClassInputVisible; +} + +bool NewClassWidget::isBaseClassEditable() const +{ + return m_d->m_ui.baseClassComboBox->isEditable(); +} + +void NewClassWidget::setFormInputVisible(bool visible) +{ + m_d->m_formInputVisible = visible; + m_d->m_ui.formLabel->setVisible(visible); + m_d->m_ui.formFileLineEdit->setVisible(visible); +} + +bool NewClassWidget::isFormInputVisible() const +{ + return m_d->m_formInputVisible; +} + +void NewClassWidget::setFormInputCheckable(bool checkable) +{ + setFormInputCheckable(checkable, false); +} + +void NewClassWidget::setFormInputCheckable(bool checkable, bool force) +{ + if (!force && checkable == m_d->m_formInputCheckable) + return; + m_d->m_formInputCheckable = checkable; + m_d->m_ui.generateFormLabel->setVisible(checkable); + m_d->m_ui.generateFormCheckBox->setVisible(checkable); +} + +void NewClassWidget::setFormInputChecked(bool v) +{ + m_d->m_ui.generateFormCheckBox->setChecked(v); +} + +bool NewClassWidget::formInputCheckable() const +{ + return m_d->m_formInputCheckable; +} + +bool NewClassWidget::formInputChecked() const +{ + return m_d->m_ui.generateFormCheckBox->isChecked(); +} + +void NewClassWidget::slotFormInputChecked() +{ + const bool checked = formInputChecked(); + m_d->m_ui.formLabel->setEnabled(checked); + m_d->m_ui.formFileLineEdit->setEnabled(checked); +} + +void NewClassWidget::setPathInputVisible(bool visible) +{ + m_d->m_pathInputVisible = visible; + m_d->m_ui.pathLabel->setVisible(visible); + m_d->m_ui.pathChooser->setVisible(visible); +} + +bool NewClassWidget::isPathInputVisible() const +{ + return m_d->m_pathInputVisible; +} + +void NewClassWidget::setClassName(const QString &suggestedName) +{ + if (debugNewClassWidget) + qDebug() << Q_FUNC_INFO << suggestedName << m_d->m_headerExtension << m_d->m_sourceExtension; + m_d->m_ui.classLineEdit->setText(ClassNameValidatingLineEdit::createClassName(suggestedName)); +} + +QString NewClassWidget::className() const +{ + return m_d->m_ui.classLineEdit->text(); +} + +QString NewClassWidget::baseClassName() const +{ + return m_d->m_ui.baseClassComboBox->currentText(); +} + +void NewClassWidget::setBaseClassName(const QString &c) +{ + const int index = m_d->m_ui.baseClassComboBox->findText(c); + if (index != -1) { + m_d->m_ui.baseClassComboBox->setCurrentIndex(index); + suggestClassNameFromBase(); + } +} + +QString NewClassWidget::sourceFileName() const +{ + return m_d->m_ui.sourceFileLineEdit->text(); +} + +QString NewClassWidget::headerFileName() const +{ + return m_d->m_ui.headerFileLineEdit->text(); +} + +QString NewClassWidget::formFileName() const +{ + return m_d->m_ui.formFileLineEdit->text(); +} + +QString NewClassWidget::path() const +{ + return m_d->m_ui.pathChooser->path(); +} + +void NewClassWidget::setPath(const QString &path) +{ + m_d->m_ui.pathChooser->setPath(path); +} + +bool NewClassWidget::namespacesEnabled() const +{ + return m_d->m_ui.classLineEdit->namespacesEnabled(); +} + +void NewClassWidget::setNamespacesEnabled(bool b) +{ + m_d->m_ui.classLineEdit->setNamespacesEnabled(b); +} + +QString NewClassWidget::sourceExtension() const +{ + return m_d->m_sourceExtension; +} + +void NewClassWidget::setSourceExtension(const QString &e) +{ + if (debugNewClassWidget) + qDebug() << Q_FUNC_INFO << e; + m_d->m_sourceExtension = fixSuffix(e); +} + +QString NewClassWidget::headerExtension() const +{ + return m_d->m_headerExtension; +} + +void NewClassWidget::setHeaderExtension(const QString &e) +{ + if (debugNewClassWidget) + qDebug() << Q_FUNC_INFO << e; + m_d->m_headerExtension = fixSuffix(e); +} + +QString NewClassWidget::formExtension() const +{ + return m_d->m_formExtension; +} + +void NewClassWidget::setFormExtension(const QString &e) +{ + if (debugNewClassWidget) + qDebug() << Q_FUNC_INFO << e; + m_d->m_formExtension = fixSuffix(e); +} + +void NewClassWidget::slotValidChanged() +{ + const bool newValid = isValid(); + if (newValid != m_d->m_valid) { + m_d->m_valid = newValid; + emit validChanged(); + } +} + +bool NewClassWidget::isValid(QString *error) const +{ + if (!m_d->m_ui.classLineEdit->isValid()) { + if (error) + *error = m_d->m_ui.classLineEdit->errorMessage(); + return false; + } + + if (isBaseClassInputVisible() && isBaseClassEditable()) { + // TODO: Should this be a ClassNameValidatingComboBox? + QRegExp classNameValidator(QLatin1String("[a-zA-Z_][a-zA-Z0-9_]*(::[a-zA-Z_][a-zA-Z0-9_]*)*")); + const QString baseClass = m_d->m_ui.baseClassComboBox->currentText().trimmed(); + if (!baseClass.isEmpty() && !classNameValidator.exactMatch(baseClass)) { + if (error) + *error = tr("Invalid base class name"); + return false; + } + } + + if (!m_d->m_ui.headerFileLineEdit->isValid()) { + if (error) + *error = tr("Invalid header file name: %1").arg(m_d->m_ui.headerFileLineEdit->errorMessage()); + return false; + } + + if (!m_d->m_ui.sourceFileLineEdit->isValid()) { + if (error) + *error = tr("Invalid source file name: %1").arg(m_d->m_ui.sourceFileLineEdit->errorMessage()); + return false; + } + + if (isFormInputVisible()) { + if (!m_d->m_ui.formFileLineEdit->isValid()) { + if (error) + *error = tr("Invalid form file name: %1").arg(m_d->m_ui.formFileLineEdit->errorMessage()); + return false; + } + } + + if (isPathInputVisible()) { + if (!m_d->m_ui.pathChooser->isValid()) { + if (error) + *error = m_d->m_ui.pathChooser->errorMessage(); + return false; + } + } + return true; +} + +void NewClassWidget::updateFileNames(const QString &baseName) +{ + if (debugNewClassWidget) + qDebug() << Q_FUNC_INFO << baseName << m_d->m_headerExtension << m_d->m_sourceExtension; + const QChar dot = QLatin1Char('.'); + m_d->m_ui.sourceFileLineEdit->setText(baseName + dot + m_d->m_sourceExtension); + m_d->m_ui.headerFileLineEdit->setText(baseName + dot + m_d->m_headerExtension); + m_d->m_ui.formFileLineEdit->setText(baseName + dot + m_d->m_formExtension); +} + +void NewClassWidget::slotActivated() +{ + if (m_d->m_valid) + emit activated(); +} + +QString NewClassWidget::fixSuffix(const QString &suffix) +{ + QString s = suffix; + if (s.startsWith(QLatin1Char('.'))) + s.remove(0, 1); + return s; +} + +// Utility to add a suffix to a file unless the user specified one +static QString ensureSuffix(QString f, const QString &extension) +{ + const QChar dot = QLatin1Char('.'); + if (f.contains(dot)) + return f; + f += dot; + f += extension; + return f; +} + +// If a non-empty name was passed, expand to directory and suffix +static QString expandFileName(const QDir &dir, const QString name, const QString &extension) +{ + if (name.isEmpty()) + return QString(); + return dir.absoluteFilePath(ensureSuffix(name, extension)); +} + +QStringList NewClassWidget::files() const +{ + QStringList rc; + const QDir dir = QDir(path()); + rc.push_back(expandFileName(dir, headerFileName(), headerExtension())); + rc.push_back(expandFileName(dir, sourceFileName(), sourceExtension())); + if (isFormInputVisible()) + rc.push_back(expandFileName(dir, formFileName(), formExtension())); + return rc; +} + + +} // namespace Utils +} // namespace Core diff --git a/src/libs/utils/newclasswidget.h b/src/libs/utils/newclasswidget.h new file mode 100644 index 00000000000..e534189d775 --- /dev/null +++ b/src/libs/utils/newclasswidget.h @@ -0,0 +1,150 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef NEWCLASSWIDGET_H +#define NEWCLASSWIDGET_H + +#include "utils_global.h" + +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE +class QStringList; +QT_END_NAMESPACE + +namespace Core { +namespace Utils { + +struct NewClassWidgetPrivate; + +/* NewClassWidget: Utility widget for 'New Class' wizards. Prompts the user + * to enter a class name (optionally derived from some base class) and file + * names for header, source and form files. Has some smart logic to derive + * the file names from the class name. */ + +class QWORKBENCH_UTILS_EXPORT NewClassWidget : public QWidget +{ + Q_DISABLE_COPY(NewClassWidget) + Q_OBJECT + Q_PROPERTY(bool namespacesEnabled READ namespacesEnabled WRITE setNamespacesEnabled DESIGNABLE true) + Q_PROPERTY(bool baseClassInputVisible READ isBaseClassInputVisible WRITE setBaseClassInputVisible DESIGNABLE true) + Q_PROPERTY(bool baseClassEditable READ isBaseClassEditable WRITE setBaseClassEditable DESIGNABLE false) + Q_PROPERTY(bool formInputVisible READ isFormInputVisible WRITE setFormInputVisible DESIGNABLE true) + Q_PROPERTY(bool pathInputVisible READ isPathInputVisible WRITE setPathInputVisible DESIGNABLE true) + Q_PROPERTY(QString className READ className WRITE setClassName DESIGNABLE true) + Q_PROPERTY(QString baseClassName READ baseClassName WRITE setBaseClassName DESIGNABLE true) + Q_PROPERTY(QString sourceFileName READ sourceFileName DESIGNABLE false) + Q_PROPERTY(QString headerFileName READ headerFileName DESIGNABLE false) + Q_PROPERTY(QString formFileName READ formFileName DESIGNABLE false) + Q_PROPERTY(QString path READ path WRITE setPath DESIGNABLE true) + Q_PROPERTY(QStringList baseClassChoices READ baseClassChoices WRITE setBaseClassChoices DESIGNABLE true) + Q_PROPERTY(QString sourceExtension READ sourceExtension WRITE setSourceExtension DESIGNABLE true) + Q_PROPERTY(QString headerExtension READ headerExtension WRITE setHeaderExtension DESIGNABLE true) + Q_PROPERTY(QString formExtension READ formExtension WRITE setFormExtension DESIGNABLE true) + Q_PROPERTY(bool formInputCheckable READ formInputCheckable WRITE setFormInputCheckable DESIGNABLE true) + Q_PROPERTY(bool formInputChecked READ formInputChecked WRITE setFormInputChecked DESIGNABLE true) + // Utility "USER" property for wizards containing file names. + Q_PROPERTY(QStringList files READ files DESIGNABLE false USER true) +public: + explicit NewClassWidget(QWidget *parent = 0); + ~NewClassWidget(); + + bool namespacesEnabled() const; + bool isBaseClassInputVisible() const; + bool isBaseClassEditable() const; + bool isFormInputVisible() const; + bool isPathInputVisible() const; + bool formInputCheckable() const; + bool formInputChecked() const; + + QString className() const; + QString baseClassName() const; + QString sourceFileName() const; + QString headerFileName() const; + QString formFileName() const; + QString path() const; + QStringList baseClassChoices() const; + QString sourceExtension() const; + QString headerExtension() const; + QString formExtension() const; + + + bool isValid(QString *error = 0) const; + + QStringList files() const; + +signals: + void validChanged(); + void activated(); + +public slots: + void setNamespacesEnabled(bool b); + void setBaseClassInputVisible(bool visible); + void setBaseClassEditable(bool editable); + void setFormInputVisible(bool visible); + void setPathInputVisible(bool visible); + void setFormInputCheckable(bool v); + void setFormInputChecked(bool v); + + /* The name passed into the new class widget will be reformatted to be a + * valid class name. */ + void setClassName(const QString &suggestedName); + void setBaseClassName(const QString &); + void setPath(const QString &path); + void setBaseClassChoices(const QStringList &choices); + void setSourceExtension(const QString &e); + void setHeaderExtension(const QString &e); + void setFormExtension(const QString &e); + + /* Suggest a class name from the base class by stripping the leading 'Q' + * character. This will happen automagically if the base class combo + * changes until the class line edited is manually edited. */ + void suggestClassNameFromBase(); + +private slots: + void updateFileNames(const QString &t); + void slotValidChanged(); + void slotActivated(); + void classNameEdited(); + void slotFormInputChecked(); + +private: + void setFormInputCheckable(bool checkable, bool force); + + QString fixSuffix(const QString &suffix); + NewClassWidgetPrivate *m_d; +}; + +} // namespace Utils +} // namespace Core + +#endif // NEWCLASSWIDGET_H diff --git a/src/libs/utils/newclasswidget.ui b/src/libs/utils/newclasswidget.ui new file mode 100644 index 00000000000..14e0a6574b8 --- /dev/null +++ b/src/libs/utils/newclasswidget.ui @@ -0,0 +1,150 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Core::Utils::NewClassWidget</class> + <widget class="QWidget" name="Core::Utils::NewClassWidget"> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <layout class="QFormLayout" name="formLayout"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::ExpandingFieldsGrow</enum> + </property> + <property name="margin"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="classNameLabel"> + <property name="text"> + <string>Class name:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="Core::Utils::ClassNameValidatingLineEdit" name="classLineEdit"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="baseClassLabel"> + <property name="text"> + <string>Base class:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="baseClassComboBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item row="2" column="0"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1"> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="headerLabel"> + <property name="text"> + <string>Header file:</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="Core::Utils::FileNameValidatingLineEdit" name="headerFileLineEdit"/> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="sourceLabel"> + <property name="text"> + <string>Source file:</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="Core::Utils::FileNameValidatingLineEdit" name="sourceFileLineEdit"/> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="generateFormLabel"> + <property name="text"> + <string>Generate form:</string> + </property> + </widget> + </item> + <item row="6" column="0"> + <widget class="QLabel" name="formLabel"> + <property name="text"> + <string>Form file:</string> + </property> + </widget> + </item> + <item row="6" column="1"> + <widget class="Core::Utils::FileNameValidatingLineEdit" name="formFileLineEdit"/> + </item> + <item row="7" column="0"> + <widget class="QLabel" name="pathLabel"> + <property name="text"> + <string>Path:</string> + </property> + </widget> + </item> + <item row="7" column="1"> + <widget class="Core::Utils::PathChooser" name="pathChooser" native="true"/> + </item> + <item row="5" column="1"> + <widget class="QCheckBox" name="generateFormCheckBox"> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>Core::Utils::PathChooser</class> + <extends>QWidget</extends> + <header location="global">pathchooser.h</header> + <container>1</container> + </customwidget> + <customwidget> + <class>Core::Utils::ClassNameValidatingLineEdit</class> + <extends>QLineEdit</extends> + <header>classnamevalidatinglineedit.h</header> + </customwidget> + <customwidget> + <class>Core::Utils::FileNameValidatingLineEdit</class> + <extends>QLineEdit</extends> + <header location="global">utils/filenamevalidatinglineedit.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp new file mode 100644 index 00000000000..188aa3b126b --- /dev/null +++ b/src/libs/utils/pathchooser.cpp @@ -0,0 +1,185 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "pathchooser.h" +#include "basevalidatinglineedit.h" + +#include <QtGui/QLineEdit> +#include <QtGui/QHBoxLayout> +#include <QtGui/QToolButton> +#include <QtGui/QFileDialog> +#include <QtGui/QDesktopServices> + +#include <QtCore/QFileInfo> +#include <QtCore/QDir> +#include <QtCore/QSettings> +#include <QtCore/QDebug> + +namespace Core { +namespace Utils { + +// ------------------ PathValidatingLineEdit +class PathValidatingLineEdit : public BaseValidatingLineEdit { +public: + explicit PathValidatingLineEdit(QWidget *parent = 0); + +protected: + virtual bool validate(const QString &value, QString *errorMessage) const; +}; + +PathValidatingLineEdit::PathValidatingLineEdit(QWidget *parent) : + BaseValidatingLineEdit(parent) +{ +} + +bool PathValidatingLineEdit::validate(const QString &value, QString *errorMessage) const +{ + return PathChooser::validatePath(value, errorMessage); +} + +// ------------------ PathChooserPrivate +struct PathChooserPrivate { + PathChooserPrivate(); + + PathValidatingLineEdit *m_lineEdit; +}; + +PathChooserPrivate::PathChooserPrivate() : + m_lineEdit(new PathValidatingLineEdit) +{ +} + +PathChooser::PathChooser(QWidget *parent) : + QWidget(parent), + m_d(new PathChooserPrivate) +{ + QHBoxLayout *hLayout = new QHBoxLayout; + hLayout->setContentsMargins(0, 0, 0, 0); + + connect(m_d->m_lineEdit, SIGNAL(validReturnPressed()), this, SIGNAL(returnPressed())); + connect(m_d->m_lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(changed())); + connect(m_d->m_lineEdit, SIGNAL(validChanged()), this, SIGNAL(validChanged())); + + m_d->m_lineEdit->setMinimumWidth(300); + hLayout->addWidget(m_d->m_lineEdit); + + QToolButton *browseButton = new QToolButton; + browseButton->setText(tr("...")); + connect(browseButton, SIGNAL(clicked()), this, SLOT(slotBrowse())); + + hLayout->addWidget(browseButton); + setLayout(hLayout); + setFocusProxy(m_d->m_lineEdit); +} + +PathChooser::~PathChooser() +{ + delete m_d; +} + +QString PathChooser::path() const +{ + return m_d->m_lineEdit->text(); +} + +void PathChooser::setPath(const QString &path) +{ + const QString defaultPath = path.isEmpty() ? homePath() : path; + m_d->m_lineEdit->setText(QDir::toNativeSeparators(defaultPath)); +} + +void PathChooser::slotBrowse() +{ + QString predefined = path(); + if (!predefined.isEmpty() && !QFileInfo(predefined).isDir()) + predefined.clear(); + // Prompt for a directory, delete trailing slashes unless it is "/", only + QString newPath = QFileDialog::getExistingDirectory(this, tr("Choose a path"), predefined); + if (!newPath .isEmpty()) { + if (newPath .size() > 1 && newPath .endsWith(QDir::separator())) + newPath .truncate(newPath .size() - 1); + setPath(newPath); + } +} + +bool PathChooser::isValid() const +{ + return m_d->m_lineEdit->isValid(); +} + +QString PathChooser::errorMessage() const +{ + return m_d->m_lineEdit->errorMessage(); +} + +bool PathChooser::validatePath(const QString &path, QString *errorMessage) +{ + if (path.isEmpty()) { + if (errorMessage) + *errorMessage = tr("The path must not be empty."); + return false; + } + // Must be a directory? + const QFileInfo fi(path); + if (fi.isDir()) + return true; // Happy! + + if (!fi.exists()) { + if (errorMessage) + *errorMessage = tr("The path '%1' does not exist.").arg(path); + return false; + } + // Must be something weird + if (errorMessage) + *errorMessage = tr("The path '%1' is not a directory.").arg(path); + return false; +} + +QString PathChooser::label() +{ + return tr("Path:"); +} + +QString PathChooser::homePath() +{ +#ifdef Q_OS_WIN + // Return 'users/<name>/Documents' on Windows, since Windows explorer + // does not let people actually display the contents of their home + // directory. Alternatively, create a QtCreator-specific directory? + return QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); +#else + return QDir::homePath(); +#endif +} + +} +} diff --git a/src/libs/utils/pathchooser.h b/src/libs/utils/pathchooser.h new file mode 100644 index 00000000000..e09040c4c06 --- /dev/null +++ b/src/libs/utils/pathchooser.h @@ -0,0 +1,90 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PATHCHOOSER_H +#define PATHCHOOSER_H + +#include "utils_global.h" + +#include <QtGui/QWidget> + +namespace Core { +namespace Utils { + +struct PathChooserPrivate; + +/* A Control that let's the user choose a path, consisting of a QLineEdit and + * a "Browse" button. Has some validation logic for embedding into + * QWizardPage. */ + +class QWORKBENCH_UTILS_EXPORT PathChooser : public QWidget +{ + Q_DISABLE_COPY(PathChooser) + Q_OBJECT + Q_PROPERTY(QString path READ path WRITE setPath DESIGNABLE true) + +public: + explicit PathChooser(QWidget *parent = 0); + virtual ~PathChooser(); + + bool isValid() const; + QString errorMessage() const; + + QString path() const; + + // Returns the suggested label title when used in a form layout + static QString label(); + + static bool validatePath(const QString &path, QString *errorMessage = 0); + + // Return the home directory, which needs some fixing under Windows. + static QString homePath(); + +signals: + void validChanged(); + void changed(); + void returnPressed(); + +public slots: + void setPath(const QString &); + +private slots: + void slotBrowse(); + +private: + PathChooserPrivate *m_d; +}; + +} +} + +#endif // PATHCHOOSER_H diff --git a/src/libs/utils/projectintropage.cpp b/src/libs/utils/projectintropage.cpp new file mode 100644 index 00000000000..bc17333fb97 --- /dev/null +++ b/src/libs/utils/projectintropage.cpp @@ -0,0 +1,215 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "projectintropage.h" +#include "filewizardpage.h" +#include "ui_projectintropage.h" + +#include <QtGui/QMessageBox> +#include <QtCore/QDir> +#include <QtCore/QFileInfo> + +namespace Core { +namespace Utils { + +struct ProjectIntroPagePrivate +{ + ProjectIntroPagePrivate(); + Ui::ProjectIntroPage m_ui; + bool m_complete; + // Status label style sheets + const QString m_errorStyleSheet; + const QString m_warningStyleSheet; + const QString m_hintStyleSheet; +}; + +ProjectIntroPagePrivate:: ProjectIntroPagePrivate() : + m_complete(false), + m_errorStyleSheet(QLatin1String("background : red;")), + m_warningStyleSheet(QLatin1String("background : yellow;")), + m_hintStyleSheet() +{ +} + +ProjectIntroPage::ProjectIntroPage(QWidget *parent) : + QWizardPage(parent), + m_d(new ProjectIntroPagePrivate) +{ + m_d->m_ui.setupUi(this); + hideStatusLabel(); + m_d->m_ui.nameLineEdit->setInitialText(tr("<Enter_Name>")); + m_d->m_ui.nameLineEdit->setFocus(Qt::TabFocusReason); + connect(m_d->m_ui.pathChooser, SIGNAL(changed()), this, SLOT(slotChanged())); + connect(m_d->m_ui.nameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(slotChanged())); + connect(m_d->m_ui.pathChooser, SIGNAL(returnPressed()), this, SLOT(slotActivated())); + connect(m_d->m_ui.nameLineEdit, SIGNAL(validReturnPressed()), this, SLOT(slotActivated())); +} + +void ProjectIntroPage::insertControl(int row, QWidget *label, QWidget *control) +{ + m_d->m_ui.formLayout->insertRow(row, label, control); +} + +ProjectIntroPage::~ProjectIntroPage() +{ + delete m_d; +} + +QString ProjectIntroPage::name() const +{ + return m_d->m_ui.nameLineEdit->text(); +} + +QString ProjectIntroPage::path() const +{ + return m_d->m_ui.pathChooser->path(); +} + +void ProjectIntroPage::setPath(const QString &path) +{ + m_d->m_ui.pathChooser->setPath(path); +} + +void ProjectIntroPage::setName(const QString &name) +{ + m_d->m_ui.nameLineEdit->setText(name); +} + +QString ProjectIntroPage::description() const +{ + return m_d->m_ui.descriptionLabel->text(); +} + +void ProjectIntroPage::setDescription(const QString &description) +{ + m_d->m_ui.descriptionLabel->setText(description); +} + +void ProjectIntroPage::changeEvent(QEvent *e) +{ + switch(e->type()) { + case QEvent::LanguageChange: + m_d->m_ui.retranslateUi(this); + break; + default: + break; + } +} + +bool ProjectIntroPage::isComplete() const +{ + return m_d->m_complete; +} + +bool ProjectIntroPage::validate() +{ + // Validate and display status + if (!m_d->m_ui.pathChooser->isValid()) { + displayStatusMessage(Error, m_d->m_ui.pathChooser->errorMessage()); + return false; + } + + // Name valid? Ignore 'DisplayingInitialText' state. + bool nameValid = false; + switch (m_d->m_ui.nameLineEdit->state()) { + case BaseValidatingLineEdit::Invalid: + displayStatusMessage(Error, m_d->m_ui.nameLineEdit->errorMessage()); + return false; + case BaseValidatingLineEdit::DisplayingInitialText: + break; + case BaseValidatingLineEdit::Valid: + nameValid = true; + break; + } + + // Check existence of the directory + QString projectDir = path(); + projectDir += QDir::separator(); + projectDir += m_d->m_ui.nameLineEdit->text(); + const QFileInfo projectDirFile(projectDir); + if (!projectDirFile.exists()) { // All happy + hideStatusLabel(); + return nameValid; + } + + if (projectDirFile.isDir()) { + displayStatusMessage(Warning, tr("The project already exists.")); + return nameValid;; + } + // Not a directory, but something else, likely causing directory creation to fail + displayStatusMessage(Error, tr("A file with that name already exists.")); + return false; +} + +void ProjectIntroPage::slotChanged() +{ + const bool newComplete = validate(); + if (newComplete != m_d->m_complete) { + m_d->m_complete = newComplete; + emit completeChanged(); + } +} + +void ProjectIntroPage::slotActivated() +{ + if (m_d->m_complete) + emit activated(); +} + +bool ProjectIntroPage::validateProjectDirectory(const QString &name, QString *errorMessage) +{ + return ProjectNameValidatingLineEdit::validateProjectName(name, errorMessage); +} + +void ProjectIntroPage::displayStatusMessage(StatusLabelMode m, const QString &s) +{ + switch (m) { + case Error: + m_d->m_ui.stateLabel->setStyleSheet(m_d->m_errorStyleSheet); + break; + case Warning: + m_d->m_ui.stateLabel->setStyleSheet(m_d->m_warningStyleSheet); + break; + case Hint: + m_d->m_ui.stateLabel->setStyleSheet(m_d->m_hintStyleSheet); + break; + } + m_d->m_ui.stateLabel->setText(s); +} + +void ProjectIntroPage::hideStatusLabel() +{ + displayStatusMessage(Hint, QString()); +} + +} +} diff --git a/src/libs/utils/projectintropage.h b/src/libs/utils/projectintropage.h new file mode 100644 index 00000000000..56dcc253272 --- /dev/null +++ b/src/libs/utils/projectintropage.h @@ -0,0 +1,107 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PROJECTINTROPAGE_H +#define PROJECTINTROPAGE_H + +#include "utils_global.h" + +#include <QtGui/QWizardPage> + +namespace Core { +namespace Utils { + +struct ProjectIntroPagePrivate; + +/* Standard wizard page for a single file letting the user choose name + * and path. Looks similar to FileWizardPage, but provides additional + * functionality: + * - Description label at the top for displaying introductory text + * - It does on the fly validation (connected to changed()) and displays + * warnings/errors in a status label at the bottom (the page is complete + * when fully validated, validatePage() is thus not implemented). + * + * Note: Careful when changing projectintropage.ui. It must have main + * geometry cleared and QLayout::SetMinimumSize constraint on the main + * layout, otherwise, QWizard will squeeze it due to its strange expanding + * hacks. */ + +class QWORKBENCH_UTILS_EXPORT ProjectIntroPage : public QWizardPage { + Q_OBJECT + Q_DISABLE_COPY(ProjectIntroPage) + Q_PROPERTY(QString description READ description WRITE setPath DESIGNABLE true) + Q_PROPERTY(QString path READ path WRITE setPath DESIGNABLE true) + Q_PROPERTY(QString name READ name WRITE setName DESIGNABLE true) +public: + explicit ProjectIntroPage(QWidget *parent = 0); + virtual ~ProjectIntroPage(); + + QString name() const; + QString path() const; + QString description() const; + + // Insert an additional control into the form layout for the target. + void insertControl(int row, QWidget *label, QWidget *control); + + virtual bool isComplete() const; + + // Validate a project directory name entry field + static bool validateProjectDirectory(const QString &name, QString *errorMessage); + +signals: + void activated(); + +public slots: + void setPath(const QString &path); + void setName(const QString &name); + void setDescription(const QString &description); + +private slots: + void slotChanged(); + void slotActivated(); + +protected: + virtual void changeEvent(QEvent *e); + +private: + enum StatusLabelMode { Error, Warning, Hint }; + + bool validate(); + void displayStatusMessage(StatusLabelMode m, const QString &); + void hideStatusLabel(); + + ProjectIntroPagePrivate *m_d; +}; + +} +} +#endif // PROJECTINTROPAGE_H diff --git a/src/libs/utils/projectintropage.ui b/src/libs/utils/projectintropage.ui new file mode 100644 index 00000000000..f530b78044e --- /dev/null +++ b/src/libs/utils/projectintropage.ui @@ -0,0 +1,122 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Core::Utils::ProjectIntroPage</class> + <widget class="QWizardPage" name="Core::Utils::ProjectIntroPage"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>208</width> + <height>143</height> + </rect> + </property> + <property name="windowTitle"> + <string>WizardPage</string> + </property> + <property name="title"> + <string>Introduction and project location</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="sizeConstraint"> + <enum>QLayout::SetMinimumSize</enum> + </property> + <item> + <widget class="QLabel" name="descriptionLabel"> + <property name="text"> + <string>TextLabel</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::MinimumExpanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QFrame" name="frame"> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="nameLabel"> + <property name="text"> + <string>Name:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="Core::Utils::ProjectNameValidatingLineEdit" name="nameLineEdit"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="pathLabel"> + <property name="text"> + <string>Path:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="Core::Utils::PathChooser" name="pathChooser" native="true"/> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="QLabel" name="stateLabel"> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>Core::Utils::PathChooser</class> + <extends>QWidget</extends> + <header>pathchooser.h</header> + <container>1</container> + </customwidget> + <customwidget> + <class>Core::Utils::ProjectNameValidatingLineEdit</class> + <extends>QLineEdit</extends> + <header>projectnamevalidatinglineedit.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/src/libs/utils/projectnamevalidatinglineedit.cpp b/src/libs/utils/projectnamevalidatinglineedit.cpp new file mode 100644 index 00000000000..fb979d39345 --- /dev/null +++ b/src/libs/utils/projectnamevalidatinglineedit.cpp @@ -0,0 +1,66 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "projectnamevalidatinglineedit.h" +#include "filenamevalidatinglineedit.h" + +namespace Core { +namespace Utils { + +ProjectNameValidatingLineEdit::ProjectNameValidatingLineEdit(QWidget *parent) : + BaseValidatingLineEdit(parent) +{ +} + +bool ProjectNameValidatingLineEdit::validateProjectName(const QString &name, QString *errorMessage /* = 0*/) +{ + // Validation is file name + checking for dots + if (!FileNameValidatingLineEdit::validateFileName(name, errorMessage)) + return false; + + // We don't want dots in the directory name for some legacy Windows + // reason. Since we are cross-platform, we generally disallow it. + if (name.contains(QLatin1Char('.'))) { + if (errorMessage) + *errorMessage = tr("The name must not contain the '.'-character."); + return false; + } + return true; +} + +bool ProjectNameValidatingLineEdit::validate(const QString &value, QString *errorMessage) const +{ + return validateProjectName(value, errorMessage); +} + +} +} diff --git a/src/libs/utils/projectnamevalidatinglineedit.h b/src/libs/utils/projectnamevalidatinglineedit.h new file mode 100644 index 00000000000..c677cea1414 --- /dev/null +++ b/src/libs/utils/projectnamevalidatinglineedit.h @@ -0,0 +1,56 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PROJECTNAMEVALIDATINGLINEEDIT_H +#define PROJECTNAMEVALIDATINGLINEEDIT_H + +#include "basevalidatinglineedit.h" + +namespace Core { +namespace Utils { + +class QWORKBENCH_UTILS_EXPORT ProjectNameValidatingLineEdit : public BaseValidatingLineEdit { + Q_OBJECT + Q_DISABLE_COPY(ProjectNameValidatingLineEdit) + +public: + explicit ProjectNameValidatingLineEdit(QWidget *parent = 0); + + static bool validateProjectName(const QString &name, QString *errorMessage /* = 0*/); + +protected: + virtual bool validate(const QString &value, QString *errorMessage) const; +}; + +} +} +#endif // PROJECTNAMEVALIDATINGLINEEDIT_H diff --git a/src/libs/utils/qtcolorbutton.cpp b/src/libs/utils/qtcolorbutton.cpp new file mode 100644 index 00000000000..8b54bdda1d4 --- /dev/null +++ b/src/libs/utils/qtcolorbutton.cpp @@ -0,0 +1,290 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "qtcolorbutton.h" +#include <QtGui/QColorDialog> +#include <QtGui/QPainter> +#include <QtCore/QMimeData> +#include <QtGui/QDragEnterEvent> +#include <QtGui/QApplication> + +namespace Core { +namespace Utils { + +class QtColorButtonPrivate +{ + QtColorButton *q_ptr; + Q_DECLARE_PUBLIC(QtColorButton) +public: + QColor m_color; +#ifndef QT_NO_DRAGANDDROP + QColor m_dragColor; + QPoint m_dragStart; + bool m_dragging; +#endif + bool m_backgroundCheckered; + bool m_alphaAllowed; + + void slotEditColor(); + QColor shownColor() const; + QPixmap generatePixmap() const; +}; + +void QtColorButtonPrivate::slotEditColor() +{ + QColor newColor; + if (m_alphaAllowed) { + bool ok; + const QRgb rgba = QColorDialog::getRgba(m_color.rgba(), &ok, q_ptr); + if (!ok) + return; + newColor = QColor::fromRgba(rgba); + } else { + newColor = QColorDialog::getColor(m_color, q_ptr); + if (!newColor.isValid()) + return; + } + if (newColor == q_ptr->color()) + return; + q_ptr->setColor(newColor); + emit q_ptr->colorChanged(m_color); +} + +QColor QtColorButtonPrivate::shownColor() const +{ +#ifndef QT_NO_DRAGANDDROP + if (m_dragging) + return m_dragColor; +#endif + return m_color; +} + +QPixmap QtColorButtonPrivate::generatePixmap() const +{ + QPixmap pix(24, 24); + + int pixSize = 20; + QBrush br(shownColor()); + + QPixmap pm(2 * pixSize, 2 * pixSize); + QPainter pmp(&pm); + pmp.fillRect(0, 0, pixSize, pixSize, Qt::lightGray); + pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::lightGray); + pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::darkGray); + pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::darkGray); + pmp.fillRect(0, 0, 2 * pixSize, 2 * pixSize, shownColor()); + br = QBrush(pm); + + QPainter p(&pix); + int corr = 1; + QRect r = pix.rect().adjusted(corr, corr, -corr, -corr); + p.setBrushOrigin((r.width() % pixSize + pixSize) / 2 + corr, (r.height() % pixSize + pixSize) / 2 + corr); + p.fillRect(r, br); + + p.fillRect(r.width() / 4 + corr, r.height() / 4 + corr, + r.width() / 2, r.height() / 2, + QColor(shownColor().rgb())); + p.drawRect(pix.rect().adjusted(0, 0, -1, -1)); + + return pix; +} + +/////////////// + +QtColorButton::QtColorButton(QWidget *parent) + : QToolButton(parent) +{ + d_ptr = new QtColorButtonPrivate; + d_ptr->q_ptr = this; + d_ptr->m_dragging = false; + d_ptr->m_backgroundCheckered = true; + d_ptr->m_alphaAllowed = true; + + setAcceptDrops(true); + + connect(this, SIGNAL(clicked()), this, SLOT(slotEditColor())); + setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred)); +} + +QtColorButton::~QtColorButton() +{ + delete d_ptr; +} + +void QtColorButton::setColor(const QColor &color) +{ + if (d_ptr->m_color == color) + return; + d_ptr->m_color = color; + update(); +} + +QColor QtColorButton::color() const +{ + return d_ptr->m_color; +} + +void QtColorButton::setBackgroundCheckered(bool checkered) +{ + if (d_ptr->m_backgroundCheckered == checkered) + return; + d_ptr->m_backgroundCheckered = checkered; + update(); +} + +bool QtColorButton::isBackgroundCheckered() const +{ + return d_ptr->m_backgroundCheckered; +} + +void QtColorButton::setAlphaAllowed(bool allowed) +{ + d_ptr->m_alphaAllowed = allowed; +} + +bool QtColorButton::isAlphaAllowed() const +{ + return d_ptr->m_alphaAllowed; +} + +void QtColorButton::paintEvent(QPaintEvent *event) +{ + QToolButton::paintEvent(event); + if (!isEnabled()) + return; + + const int pixSize = 10; + QBrush br(d_ptr->shownColor()); + if (d_ptr->m_backgroundCheckered) { + QPixmap pm(2 * pixSize, 2 * pixSize); + QPainter pmp(&pm); + pmp.fillRect(0, 0, pixSize, pixSize, Qt::white); + pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::white); + pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::black); + pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::black); + pmp.fillRect(0, 0, 2 * pixSize, 2 * pixSize, d_ptr->shownColor()); + br = QBrush(pm); + } + + QPainter p(this); + const int corr = 5; + QRect r = rect().adjusted(corr, corr, -corr, -corr); + p.setBrushOrigin((r.width() % pixSize + pixSize) / 2 + corr, (r.height() % pixSize + pixSize) / 2 + corr); + p.fillRect(r, br); + + //const int adjX = qRound(r.width() / 4.0); + //const int adjY = qRound(r.height() / 4.0); + //p.fillRect(r.adjusted(adjX, adjY, -adjX, -adjY), + // QColor(d_ptr->shownColor().rgb())); + /* + p.fillRect(r.adjusted(0, r.height() * 3 / 4, 0, 0), + QColor(d_ptr->shownColor().rgb())); + p.fillRect(r.adjusted(0, 0, 0, -r.height() * 3 / 4), + QColor(d_ptr->shownColor().rgb())); + */ + /* + const QColor frameColor0(0, 0, 0, qRound(0.2 * (0xFF - d_ptr->shownColor().alpha()))); + p.setPen(frameColor0); + p.drawRect(r.adjusted(adjX, adjY, -adjX - 1, -adjY - 1)); + */ + + const QColor frameColor1(0, 0, 0, 26); + p.setPen(frameColor1); + p.drawRect(r.adjusted(1, 1, -2, -2)); + const QColor frameColor2(0, 0, 0, 51); + p.setPen(frameColor2); + p.drawRect(r.adjusted(0, 0, -1, -1)); +} + +void QtColorButton::mousePressEvent(QMouseEvent *event) +{ +#ifndef QT_NO_DRAGANDDROP + if (event->button() == Qt::LeftButton) + d_ptr->m_dragStart = event->pos(); +#endif + QToolButton::mousePressEvent(event); +} + +void QtColorButton::mouseMoveEvent(QMouseEvent *event) +{ +#ifndef QT_NO_DRAGANDDROP + if (event->buttons() & Qt::LeftButton && + (d_ptr->m_dragStart - event->pos()).manhattanLength() > QApplication::startDragDistance()) { + QMimeData *mime = new QMimeData; + mime->setColorData(color()); + QDrag *drg = new QDrag(this); + drg->setMimeData(mime); + drg->setPixmap(d_ptr->generatePixmap()); + setDown(false); + event->accept(); + drg->start(); + return; + } +#endif + QToolButton::mouseMoveEvent(event); +} + +#ifndef QT_NO_DRAGANDDROP +void QtColorButton::dragEnterEvent(QDragEnterEvent *event) +{ + const QMimeData *mime = event->mimeData(); + if (!mime->hasColor()) + return; + + event->accept(); + d_ptr->m_dragColor = qvariant_cast<QColor>(mime->colorData()); + d_ptr->m_dragging = true; + update(); +} + +void QtColorButton::dragLeaveEvent(QDragLeaveEvent *event) +{ + event->accept(); + d_ptr->m_dragging = false; + update(); +} + +void QtColorButton::dropEvent(QDropEvent *event) +{ + event->accept(); + d_ptr->m_dragging = false; + if (d_ptr->m_dragColor == color()) + return; + setColor(d_ptr->m_dragColor); + emit colorChanged(color()); +} +#endif + +} // namespace Utils +} // namespace Core + +#include "moc_qtcolorbutton.cpp" diff --git a/src/libs/utils/qtcolorbutton.h b/src/libs/utils/qtcolorbutton.h new file mode 100644 index 00000000000..07355c883ec --- /dev/null +++ b/src/libs/utils/qtcolorbutton.h @@ -0,0 +1,84 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef QTCOLORBUTTON_H +#define QTCOLORBUTTON_H + +#include "utils_global.h" + +#include <QtGui/QToolButton> + +namespace Core { +namespace Utils { + +class QWORKBENCH_UTILS_EXPORT QtColorButton : public QToolButton +{ + Q_OBJECT + Q_PROPERTY(bool backgroundCheckered READ isBackgroundCheckered WRITE setBackgroundCheckered) + Q_PROPERTY(bool alphaAllowed READ isAlphaAllowed WRITE setAlphaAllowed) +public: + QtColorButton(QWidget *parent = 0); + ~QtColorButton(); + + bool isBackgroundCheckered() const; + void setBackgroundCheckered(bool checkered); + + bool isAlphaAllowed() const; + void setAlphaAllowed(bool allowed); + + QColor color() const; + +public slots: + void setColor(const QColor &color); + +signals: + void colorChanged(const QColor &color); +protected: + void paintEvent(QPaintEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); +#ifndef QT_NO_DRAGANDDROP + void dragEnterEvent(QDragEnterEvent *event); + void dragLeaveEvent(QDragLeaveEvent *event); + void dropEvent(QDropEvent *event); +#endif +private: + class QtColorButtonPrivate *d_ptr; + friend class QtColorButtonPrivate; + Q_DISABLE_COPY(QtColorButton) + Q_PRIVATE_SLOT(d_ptr, void slotEditColor()) +}; + +} // namespace Utils +} // namespace Core + +#endif // QTCOLORBUTTON_H diff --git a/src/libs/utils/reloadpromptutils.cpp b/src/libs/utils/reloadpromptutils.cpp new file mode 100644 index 00000000000..ca1d9e23ded --- /dev/null +++ b/src/libs/utils/reloadpromptutils.cpp @@ -0,0 +1,62 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "reloadpromptutils.h" +#include <QtGui/QMessageBox> + +using namespace Core; +using namespace Core::Utils; + +QWORKBENCH_UTILS_EXPORT Core::Utils::ReloadPromptAnswer + Core::Utils::reloadPrompt(const QString &fileName, QWidget *parent) +{ + return reloadPrompt(QObject::tr("File Changed"), + QObject::tr("The file %1 has changed outside Qt Creator. Do you want to reload it?").arg(fileName), + parent); +} + +QWORKBENCH_UTILS_EXPORT Core::Utils::ReloadPromptAnswer + Core::Utils::reloadPrompt(const QString &title, const QString &prompt, QWidget *parent) +{ + switch (QMessageBox::question(parent, title, prompt, QMessageBox::Yes|QMessageBox::YesToAll|QMessageBox::No|QMessageBox::NoToAll, + QMessageBox::YesToAll)) { + case QMessageBox::Yes: + return ReloadCurrent; + case QMessageBox::YesToAll: + return ReloadAll; + case QMessageBox::No: + return ReloadSkipCurrent; + default: + break; + } + return ReloadNone; +} diff --git a/src/libs/utils/reloadpromptutils.h b/src/libs/utils/reloadpromptutils.h new file mode 100644 index 00000000000..deaf4b920a6 --- /dev/null +++ b/src/libs/utils/reloadpromptutils.h @@ -0,0 +1,54 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef RELOADPROMPTUTILS_H +#define RELOADPROMPTUTILS_H + +#include "utils_global.h" + +QT_BEGIN_NAMESPACE +class QString; +class QWidget; +QT_END_NAMESPACE + +namespace Core { +namespace Utils { + +enum ReloadPromptAnswer { ReloadCurrent, ReloadAll, ReloadSkipCurrent, ReloadNone }; + +QWORKBENCH_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &fileName, QWidget *parent); +QWORKBENCH_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &title, const QString &prompt, QWidget *parent); + +} // namespace Utils +} // namespace Core + +#endif // RELOADPROMPTUTILS_H diff --git a/src/libs/utils/settingsutils.cpp b/src/libs/utils/settingsutils.cpp new file mode 100644 index 00000000000..ca8de01828e --- /dev/null +++ b/src/libs/utils/settingsutils.cpp @@ -0,0 +1,53 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "settingsutils.h" +#include <QtCore/QString> + +namespace Core { +namespace Utils { + +QWORKBENCH_UTILS_EXPORT QString settingsKey(const QString &category) +{ + QString rc(category); + const QChar underscore = QLatin1Char('_'); + const int size = rc.size(); + for (int i = 0; i < size;i++) { + const QChar c = rc.at(i); + if (!c.isLetterOrNumber() && c != underscore) + rc[i] = underscore; + } + return rc; +} + +} +} diff --git a/src/libs/utils/settingsutils.h b/src/libs/utils/settingsutils.h new file mode 100644 index 00000000000..734a2f02f9d --- /dev/null +++ b/src/libs/utils/settingsutils.h @@ -0,0 +1,48 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef SETTINGSTUTILS_H +#define SETTINGSTUTILS_H + +#include "utils_global.h" + +namespace Core { +namespace Utils { + +// Create a usable settings key from a category, +// for example Editor|C++ -> Editor_C__ +QWORKBENCH_UTILS_EXPORT QString settingsKey(const QString &category); + +} // namespace Utils +} // namespace Core + +#endif // SETTINGSTUTILS_H diff --git a/src/libs/utils/submiteditorwidget.cpp b/src/libs/utils/submiteditorwidget.cpp new file mode 100644 index 00000000000..aeafcd828d5 --- /dev/null +++ b/src/libs/utils/submiteditorwidget.cpp @@ -0,0 +1,305 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "submiteditorwidget.h" +#include "ui_submiteditorwidget.h" + +#include <QtCore/QDebug> +#include <QtCore/QPointer> + +enum { debug= 0 }; + +namespace Core { +namespace Utils { + +struct SubmitEditorWidgetPrivate { + SubmitEditorWidgetPrivate(); + + Ui::SubmitEditorWidget m_ui; + bool m_filesSelected; + bool m_filesChecked; +}; + +SubmitEditorWidgetPrivate::SubmitEditorWidgetPrivate() : + m_filesSelected(false), + m_filesChecked(false) +{ +} + +SubmitEditorWidget::SubmitEditorWidget(QWidget *parent) : + QWidget(parent), + m_d(new SubmitEditorWidgetPrivate) +{ + m_d->m_ui.setupUi(this); + // File List + m_d->m_ui.fileList->setSelectionMode(QAbstractItemView::ExtendedSelection); + connect(m_d->m_ui.fileList, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(triggerDiffSelected())); + connect(m_d->m_ui.fileList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(fileItemChanged(QListWidgetItem*))); + connect(m_d->m_ui.fileList, SIGNAL(itemSelectionChanged()), this, SLOT(fileSelectionChanged())); + + // Text + m_d->m_ui.description->setFont(QFont(QLatin1String("Courier"))); + + setFocusPolicy(Qt::StrongFocus); + setFocusProxy(m_d->m_ui.description); +} + +SubmitEditorWidget::~SubmitEditorWidget() +{ + delete m_d; +} + +void SubmitEditorWidget::registerActions(QAction *editorUndoAction, QAction *editorRedoAction, + QAction *submitAction, QAction *diffAction) +{ + if (editorUndoAction) { + editorUndoAction->setEnabled(m_d->m_ui.description->document()->isUndoAvailable()); + connect(m_d->m_ui.description, SIGNAL(undoAvailable(bool)), editorUndoAction, SLOT(setEnabled(bool))); + connect(editorUndoAction, SIGNAL(triggered()), m_d->m_ui.description, SLOT(undo())); + } + if (editorRedoAction) { + editorRedoAction->setEnabled(m_d->m_ui.description->document()->isRedoAvailable()); + connect(m_d->m_ui.description, SIGNAL(redoAvailable(bool)), editorRedoAction, SLOT(setEnabled(bool))); + connect(editorRedoAction, SIGNAL(triggered()), m_d->m_ui.description, SLOT(redo())); + } + + if (submitAction) { + if (debug) + qDebug() << submitAction << m_d->m_ui.fileList->count() << "items" << m_d->m_filesChecked; + submitAction->setEnabled(m_d->m_filesChecked); + connect(this, SIGNAL(fileCheckStateChanged(bool)), submitAction, SLOT(setEnabled(bool))); + } + if (diffAction) { + if (debug) + qDebug() << diffAction << m_d->m_filesSelected; + diffAction->setEnabled(m_d->m_filesSelected); + connect(this, SIGNAL(fileSelectionChanged(bool)), diffAction, SLOT(setEnabled(bool))); + connect(diffAction, SIGNAL(triggered()), this, SLOT(triggerDiffSelected())); + } +} + +void SubmitEditorWidget::unregisterActions(QAction *editorUndoAction, QAction *editorRedoAction, + QAction *submitAction, QAction *diffAction) +{ + if (editorUndoAction) { + disconnect(m_d->m_ui.description, SIGNAL(undoAvailableChanged(bool)), editorUndoAction, SLOT(setEnabled(bool))); + disconnect(editorUndoAction, SIGNAL(triggered()), m_d->m_ui.description, SLOT(undo())); + } + if (editorRedoAction) { + disconnect(m_d->m_ui.description, SIGNAL(redoAvailableChanged(bool)), editorRedoAction, SLOT(setEnabled(bool))); + disconnect(editorRedoAction, SIGNAL(triggered()), m_d->m_ui.description, SLOT(redo())); + } + + if (submitAction) + disconnect(this, SIGNAL(fileCheckStateChanged(bool)), submitAction, SLOT(setEnabled(bool))); + + if (diffAction) { + disconnect(this, SIGNAL(fileSelectionChanged(bool)), diffAction, SLOT(setEnabled(bool))); + disconnect(diffAction, SIGNAL(triggered()), this, SLOT(triggerDiffSelected())); + } +} + + +QString SubmitEditorWidget::trimmedDescriptionText() const +{ + // Make sure we have one terminating NL + QString text = descriptionText().trimmed(); + text += QLatin1Char('\n'); + return text; +} + +QString SubmitEditorWidget::descriptionText() const +{ + return m_d->m_ui.description->toPlainText(); +} + +void SubmitEditorWidget::setDescriptionText(const QString &text) +{ + m_d->m_ui.description->setPlainText(text); +} + +QStringList SubmitEditorWidget::fileList() const +{ + QStringList rc; + const int count = m_d->m_ui.fileList->count(); + for (int i = 0; i < count; i++) + rc.push_back(m_d->m_ui.fileList->item(i)->text()); + return rc; +} + +void SubmitEditorWidget::addFilesUnblocked(const QStringList &list, bool checked, bool userCheckable) +{ + if (debug) + qDebug() << Q_FUNC_INFO << list << checked << userCheckable; + foreach (const QString &f, list) { + QListWidgetItem *item = new QListWidgetItem(f); + item->setCheckState(checked ? Qt::Checked : Qt::Unchecked); + if (!userCheckable) + item->setFlags(item->flags() & ~Qt::ItemIsUserCheckable); + m_d->m_ui.fileList->addItem(item); + } +} + +void SubmitEditorWidget::addFiles(const QStringList &list, bool checked, bool userCheckable) +{ + if (list.empty()) + return; + + const bool blocked = m_d->m_ui.fileList->blockSignals(true); + addFilesUnblocked(list, checked, userCheckable); + m_d->m_ui.fileList->blockSignals(blocked); + // Did we gain any checked files..update action accordingly + if (!m_d->m_filesChecked && checked) { + m_d->m_filesChecked = true; + emit fileCheckStateChanged(m_d->m_filesChecked); + } +} + +void SubmitEditorWidget::setFileList(const QStringList &list) +{ + // Trigger enabling of menu action + m_d->m_ui.fileList->clearSelection(); + + const bool blocked = m_d->m_ui.fileList->blockSignals(true); + m_d->m_ui.fileList->clear(); + if (!list.empty()) { + addFilesUnblocked(list, true, true); + // Checked files added? + if (!m_d->m_filesChecked) { + m_d->m_filesChecked = true; + emit fileCheckStateChanged(m_d->m_filesChecked); + } + } + m_d->m_ui.fileList->blockSignals(blocked); +} + +static bool containsCheckState(const QListWidget *lw, Qt::CheckState cs) +{ + const int count = lw->count(); + for (int i = 0; i < count; i++) + if (lw->item(i)->checkState() == cs) + return true; + return false; +} + +QStringList SubmitEditorWidget::selectedFiles() const +{ + QStringList rc; + const int count = m_d->m_ui.fileList->count(); + for (int i = 0; i < count; i++) { + const QListWidgetItem *item = m_d->m_ui.fileList->item(i); + if (item->isSelected()) + rc.push_back(item->text()); + } + return rc; +} + +QStringList SubmitEditorWidget::checkedFiles() const +{ + QStringList rc; + const int count = m_d->m_ui.fileList->count(); + for (int i = 0; i < count; i++) { + const QListWidgetItem *item = m_d->m_ui.fileList->item(i); + if (item->checkState() == Qt::Checked) + rc.push_back(item->text()); + } + return rc; +} + +QPlainTextEdit *SubmitEditorWidget::descriptionEdit() const +{ + return m_d->m_ui.description; +} + +void SubmitEditorWidget::triggerDiffSelected() +{ + const QStringList sel = selectedFiles(); + if (!sel.empty()) + emit diffSelected(sel); +} + +void SubmitEditorWidget::fileItemChanged(QListWidgetItem *item) +{ + const Qt::CheckState st = item->checkState(); + if (debug) + qDebug() << Q_FUNC_INFO << st << item->text() << m_d->m_filesChecked; + // Enable the actions according to check state + switch (st) { + case Qt::Unchecked: // Item was unchecked: Any checked items left? + if (m_d->m_filesChecked && !containsCheckState(m_d->m_ui.fileList, Qt::Checked)) { + m_d->m_filesChecked = false; + emit fileCheckStateChanged(m_d->m_filesChecked); + } + break; + case Qt::Checked: + // Item was Checked. First one? + if (!m_d->m_filesChecked) { + m_d->m_filesChecked = true; + emit fileCheckStateChanged(m_d->m_filesChecked); + } + break; + case Qt::PartiallyChecked: // Errm? + break; + } +} + +void SubmitEditorWidget::fileSelectionChanged() +{ + const bool newFilesSelected = !m_d->m_ui.fileList->selectedItems().empty(); + if (debug) + qDebug() << Q_FUNC_INFO << newFilesSelected; + if (m_d->m_filesSelected != newFilesSelected) { + m_d->m_filesSelected = newFilesSelected; + emit fileSelectionChanged(m_d->m_filesSelected); + if (debug) + qDebug() << Q_FUNC_INFO << m_d->m_filesSelected; + } +} + +void SubmitEditorWidget::changeEvent(QEvent *e) +{ + switch(e->type()) { + case QEvent::LanguageChange: + m_d->m_ui.retranslateUi(this); + break; + default: + break; + } +} + +void SubmitEditorWidget::insertTopWidget(QWidget *w) +{ + m_d->m_ui.vboxLayout->insertWidget(0, w); +} + +} // namespace Utils +} // namespace Core diff --git a/src/libs/utils/submiteditorwidget.h b/src/libs/utils/submiteditorwidget.h new file mode 100644 index 00000000000..3c40ccecba7 --- /dev/null +++ b/src/libs/utils/submiteditorwidget.h @@ -0,0 +1,122 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef SUBMITEDITORWIDGET_H +#define SUBMITEDITORWIDGET_H + +#include "utils_global.h" + +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE +class QPlainTextEdit; +class QListWidgetItem; +class QAction; +QT_END_NAMESPACE + +namespace Core { +namespace Utils { + +struct SubmitEditorWidgetPrivate; + +/* The submit editor presents the commit message in a text editor and an + * checkable list of modified files in a list window. The user can delete + * files from the list by pressing unchecking them or diff the selection + * by doubleclicking. + * + * Additionally, standard creator actions can be registered: + * Undo/redo will be set up to work with the description editor. + * Submit will be set up to be enabled according to checkstate. + * Diff will be set up to trigger diffSelected(). + * + * Note that the actions are connected by signals; in the rare event that there + * are several instances of the SubmitEditorWidget belonging to the same + * context active, the actions must be registered/unregistered in the editor + * change event. + * Care should be taken to ensure the widget is deleted properly when the + * editor closes. */ + +class QWORKBENCH_UTILS_EXPORT SubmitEditorWidget : public QWidget { + Q_OBJECT + Q_DISABLE_COPY(SubmitEditorWidget) + Q_PROPERTY(QString descriptionText READ descriptionText WRITE setDescriptionText DESIGNABLE true) + Q_PROPERTY(QStringList fileList READ fileList WRITE setFileList DESIGNABLE true) +public: + explicit SubmitEditorWidget(QWidget *parent = 0); + virtual ~SubmitEditorWidget(); + + void registerActions(QAction *editorUndoAction, QAction *editorRedoAction, + QAction *submitAction = 0, QAction *diffAction = 0); + void unregisterActions(QAction *editorUndoAction, QAction *editorRedoAction, + QAction *submitAction = 0, QAction *diffAction = 0); + + QString descriptionText() const; + void setDescriptionText(const QString &text); + // Should be used to normalize newlines. + QString trimmedDescriptionText() const; + + // The raw file list + QStringList fileList() const; + void addFiles(const QStringList&, bool checked = true, bool userCheckable = true); + void setFileList(const QStringList&); + + // Files to be included in submit + QStringList checkedFiles() const; + + // Selected files for diff + QStringList selectedFiles() const; + + QPlainTextEdit *descriptionEdit() const; + +signals: + void diffSelected(const QStringList &); + void fileSelectionChanged(bool someFileSelected); + void fileCheckStateChanged(bool someFileChecked); + +protected: + virtual void changeEvent(QEvent *e); + void insertTopWidget(QWidget *w); + +private slots: + void triggerDiffSelected(); + void fileItemChanged(QListWidgetItem *); + void fileSelectionChanged(); + +private: + void addFilesUnblocked(const QStringList &list, bool checked, bool userCheckable); + + SubmitEditorWidgetPrivate *m_d; +}; + +} +} +#endif // SUBMITEDITORWIDGET_H diff --git a/src/libs/utils/submiteditorwidget.ui b/src/libs/utils/submiteditorwidget.ui new file mode 100644 index 00000000000..1a30e8b7919 --- /dev/null +++ b/src/libs/utils/submiteditorwidget.ui @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Core::Utils::SubmitEditorWidget</class> + <widget class="QWidget" name="Core::Utils::SubmitEditorWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>582</width> + <height>502</height> + </rect> + </property> + <property name="windowTitle"> + <string>Subversion Submit</string> + </property> + <layout class="QVBoxLayout"> + <item> + <widget class="QGroupBox" name="descriptionBox"> + <property name="title"> + <string>Des&cription</string> + </property> + <property name="flat"> + <bool>true</bool> + </property> + <layout class="QGridLayout"> + <item row="0" column="0"> + <widget class="QPlainTextEdit" name="description"> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>F&iles</string> + </property> + <property name="flat"> + <bool>true</bool> + </property> + <layout class="QGridLayout"> + <item row="0" column="0"> + <widget class="QListWidget" name="fileList"> + <property name="font"> + <font/> + </property> + <property name="textElideMode"> + <enum>Qt::ElideNone</enum> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/libs/utils/synchronousprocess.cpp b/src/libs/utils/synchronousprocess.cpp new file mode 100644 index 00000000000..71bcdffb6cc --- /dev/null +++ b/src/libs/utils/synchronousprocess.cpp @@ -0,0 +1,356 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ + +#include "synchronousprocess.h" + +#include <QtCore/QDebug> +#include <QtCore/QTimer> +#include <QtCore/QEventLoop> +#include <QtCore/QTextCodec> + +#include <QtGui/QApplication> + +enum { debug = 0 }; + +enum { defaultMaxHangTimerCount = 10 }; + +namespace Core { +namespace Utils { + +// ----------- SynchronousProcessResponse +SynchronousProcessResponse::SynchronousProcessResponse() : + result(StartFailed), + exitCode(-1) +{ +} + +void SynchronousProcessResponse::clear() +{ + result = StartFailed; + exitCode = -1; + stdOut.clear(); + stdErr.clear(); +} + +QWORKBENCH_UTILS_EXPORT QDebug operator<<(QDebug str, const SynchronousProcessResponse& r) +{ + QDebug nsp = str.nospace(); + nsp << "SynchronousProcessResponse: result=" << r.result << " ex=" << r.exitCode << '\n' + << r.stdOut.size() << " bytes stdout, stderr=" << r.stdErr << '\n'; + return str; +} + +// Data for one channel buffer (stderr/stdout) +struct ChannelBuffer { + ChannelBuffer(); + void clearForRun(); + QByteArray linesRead(); + + QByteArray data; + bool firstData; + bool bufferedSignalsEnabled; + bool firstBuffer; + int bufferPos; +}; + +ChannelBuffer::ChannelBuffer() : + firstData(true), + bufferedSignalsEnabled(false), + firstBuffer(true), + bufferPos(0) +{ +} + +void ChannelBuffer::clearForRun() +{ + firstData = true; + firstBuffer = true; + bufferPos = 0; +} + +/* Check for complete lines read from the device and return them, moving the + * buffer position. This is based on the assumption that '\n' is the new line + * marker in any sane codec. */ +QByteArray ChannelBuffer::linesRead() +{ + // Any new lines? + const int lastLineIndex = data.lastIndexOf('\n'); + if (lastLineIndex == -1 || lastLineIndex <= bufferPos) + return QByteArray(); + const int nextBufferPos = lastLineIndex + 1; + const QByteArray lines = data.mid(bufferPos, nextBufferPos - bufferPos); + bufferPos = nextBufferPos; + return lines; +} + +// ----------- SynchronousProcessPrivate +struct SynchronousProcessPrivate { + SynchronousProcessPrivate(); + void clearForRun(); + + QTextCodec *m_stdOutCodec; + QProcess m_process; + QTimer m_timer; + QEventLoop m_eventLoop; + SynchronousProcessResponse m_result; + int m_hangTimerCount; + int m_maxHangTimerCount; + + ChannelBuffer m_stdOut; + ChannelBuffer m_stdErr; +}; + +SynchronousProcessPrivate::SynchronousProcessPrivate() : + m_stdOutCodec(0), + m_hangTimerCount(0), + m_maxHangTimerCount(defaultMaxHangTimerCount) +{ +} + +void SynchronousProcessPrivate::clearForRun() +{ + m_hangTimerCount = 0; + m_stdOut.clearForRun(); + m_stdErr.clearForRun(); + m_result.clear(); +} + +// ----------- SynchronousProcess +SynchronousProcess::SynchronousProcess() : + m_d(new SynchronousProcessPrivate) +{ + m_d->m_timer.setInterval(1000); + connect(&m_d->m_timer, SIGNAL(timeout()), this, SLOT(slotTimeout())); + connect(&m_d->m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finished(int,QProcess::ExitStatus))); + connect(&m_d->m_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError))); + connect(&m_d->m_process, SIGNAL(readyReadStandardOutput()), + this, SLOT(stdOutReady())); + connect(&m_d->m_process, SIGNAL(readyReadStandardError()), + this, SLOT(stdErrReady())); +} + +SynchronousProcess::~SynchronousProcess() +{ + delete m_d; +} + +void SynchronousProcess::setTimeout(int timeoutMS) +{ + m_d->m_maxHangTimerCount = qMax(2, timeoutMS / 1000); +} + +int SynchronousProcess::timeout() const +{ + return 1000 * m_d->m_maxHangTimerCount; +} + +void SynchronousProcess::setStdOutCodec(QTextCodec *c) +{ + m_d->m_stdOutCodec = c; +} + +QTextCodec *SynchronousProcess::stdOutCodec() const +{ + return m_d->m_stdOutCodec; +} + +bool SynchronousProcess::stdOutBufferedSignalsEnabled() const +{ + return m_d->m_stdOut.bufferedSignalsEnabled; +} + +void SynchronousProcess::setStdOutBufferedSignalsEnabled(bool v) +{ + m_d->m_stdOut.bufferedSignalsEnabled = v; +} + +bool SynchronousProcess::stdErrBufferedSignalsEnabled() const +{ + return m_d->m_stdErr.bufferedSignalsEnabled; +} + +void SynchronousProcess::setStdErrBufferedSignalsEnabled(bool v) +{ + m_d->m_stdErr.bufferedSignalsEnabled = v; +} + +QStringList SynchronousProcess::environment() const +{ + return m_d->m_process.environment(); +} + +void SynchronousProcess::setEnvironment(const QStringList &e) +{ + m_d->m_process.setEnvironment(e); +} + +SynchronousProcessResponse SynchronousProcess::run(const QString &binary, + const QStringList &args) +{ + if (debug) + qDebug() << '>' << Q_FUNC_INFO << binary << args; + + m_d->clearForRun(); + m_d->m_timer.start(); + + QApplication::setOverrideCursor(Qt::WaitCursor); + + m_d->m_process.start(binary, args, QIODevice::ReadOnly); + m_d->m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents); + if (m_d->m_result.result == SynchronousProcessResponse::Finished || m_d->m_result.result == SynchronousProcessResponse::FinishedError) { + processStdOut(false); + processStdErr(false); + } + + m_d->m_result.stdOut = convertStdOut(m_d->m_stdOut.data); + m_d->m_result.stdErr = convertStdErr(m_d->m_stdErr.data); + + m_d->m_timer.stop(); + QApplication::restoreOverrideCursor(); + + if (debug) + qDebug() << '<' << Q_FUNC_INFO << binary << m_d->m_result; + return m_d->m_result; +} + +void SynchronousProcess::slotTimeout() +{ + if (++m_d->m_hangTimerCount > m_d->m_maxHangTimerCount) { + m_d->m_process.kill(); + m_d->m_result.result = SynchronousProcessResponse::Hang; + } + + if (debug) + qDebug() << Q_FUNC_INFO << m_d->m_hangTimerCount; +} + +void SynchronousProcess::finished(int exitCode, QProcess::ExitStatus e) +{ + if (debug) + qDebug() << Q_FUNC_INFO << exitCode << e; + m_d->m_hangTimerCount = 0; + switch (e) { + case QProcess::NormalExit: + m_d->m_result.result = exitCode ? SynchronousProcessResponse::FinishedError : SynchronousProcessResponse::Finished; + m_d->m_result.exitCode = exitCode; + break; + case QProcess::CrashExit: + m_d->m_result.result = SynchronousProcessResponse::TerminatedAbnormally; + m_d->m_result.exitCode = -1; + break; + } + m_d->m_eventLoop.quit(); +} + +void SynchronousProcess::error(QProcess::ProcessError e) +{ + m_d->m_hangTimerCount = 0; + if (debug) + qDebug() << Q_FUNC_INFO << e; + m_d->m_result.result = SynchronousProcessResponse::StartFailed; + m_d->m_eventLoop.quit(); +} + +void SynchronousProcess::stdOutReady() +{ + m_d->m_hangTimerCount = 0; + processStdOut(true); +} + +void SynchronousProcess::stdErrReady() +{ + m_d->m_hangTimerCount = 0; + processStdErr(true); +} + +QString SynchronousProcess::convertStdErr(const QByteArray &ba) +{ + return QString::fromLocal8Bit(ba).remove(QLatin1Char('\r')); +} + +QString SynchronousProcess::convertStdOut(const QByteArray &ba) const +{ + QString stdOut = m_d->m_stdOutCodec ? m_d->m_stdOutCodec->toUnicode(ba) : QString::fromLocal8Bit(ba); + return stdOut.remove(QLatin1Char('\r')); +} + +void SynchronousProcess::processStdOut(bool emitSignals) +{ + // Handle binary data + const QByteArray ba = m_d->m_process.readAllStandardOutput(); + if (debug > 1) + qDebug() << Q_FUNC_INFO << emitSignals << ba; + if (!ba.isEmpty()) { + m_d->m_stdOut.data += ba; + if (emitSignals) { + // Emit binary signals + emit stdOut(ba, m_d->m_stdOut.firstData); + m_d->m_stdOut.firstData = false; + // Buffered. Emit complete lines? + if (m_d->m_stdOut.bufferedSignalsEnabled) { + const QByteArray lines = m_d->m_stdOut.linesRead(); + if (!lines.isEmpty()) { + emit stdOutBuffered(convertStdOut(lines), m_d->m_stdOut.firstBuffer); + m_d->m_stdOut.firstBuffer = false; + } + } + } + } +} + +void SynchronousProcess::processStdErr(bool emitSignals) +{ + // Handle binary data + const QByteArray ba = m_d->m_process.readAllStandardError(); + if (debug > 1) + qDebug() << Q_FUNC_INFO << emitSignals << ba; + if (!ba.isEmpty()) { + m_d->m_stdErr.data += ba; + if (emitSignals) { + // Emit binary signals + emit stdErr(ba, m_d->m_stdErr.firstData); + m_d->m_stdErr.firstData = false; + if (m_d->m_stdErr.bufferedSignalsEnabled) { + // Buffered. Emit complete lines? + const QByteArray lines = m_d->m_stdErr.linesRead(); + if (!lines.isEmpty()) { + emit stdErrBuffered(convertStdErr(lines), m_d->m_stdErr.firstBuffer); + m_d->m_stdErr.firstBuffer = false; + } + } + } + } +} + +} +} diff --git a/src/libs/utils/synchronousprocess.h b/src/libs/utils/synchronousprocess.h new file mode 100644 index 00000000000..9458655d6bf --- /dev/null +++ b/src/libs/utils/synchronousprocess.h @@ -0,0 +1,139 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef SYNCHRONOUSPROCESS_H +#define SYNCHRONOUSPROCESS_H + +#include <QtCore/QObject> +#include <QtCore/QProcess> +#include <QtCore/QStringList> + +#include "utils_global.h" + +QT_BEGIN_NAMESPACE +class QTextCodec; +class QDebug; +class QByteArray; +QT_END_NAMESPACE + +namespace Core { +namespace Utils { + +struct SynchronousProcessPrivate; + +/* Result of SynchronousProcess execution */ +struct QWORKBENCH_UTILS_EXPORT SynchronousProcessResponse { + enum Result { + // Finished with return code 0 + Finished, + // Finished with return code != 0 + FinishedError, + // Process terminated abnormally (kill) + TerminatedAbnormally, + // Executable could not be started + StartFailed, + // Hang, no output after time out + Hang }; + + SynchronousProcessResponse(); + void clear(); + + Result result; + int exitCode; + QString stdOut; + QString stdErr; +}; + +QWORKBENCH_UTILS_EXPORT QDebug operator<<(QDebug str, const SynchronousProcessResponse &); + +/* SynchronousProcess: Runs a synchronous process in its own event loop + * that blocks only user input events. Thus, it allows for the gui to + * repaint and append output to log windows. + * + * The stdOut(), stdErr() signals are emitted unbuffered as the process + * writes them. + * + * The stdOutBuffered(), stdErrBuffered() signals are emitted with complete + * lines based on the '\n' marker if they are enabled using + * stdOutBufferedSignalsEnabled()/setStdErrBufferedSignalsEnabled(). + * They would typically be used for log windows. */ + +class QWORKBENCH_UTILS_EXPORT SynchronousProcess : public QObject { + Q_OBJECT +public: + SynchronousProcess(); + virtual ~SynchronousProcess(); + + /* Timeout for hanging processes (no reaction on stderr/stdout)*/ + void setTimeout(int timeoutMS); + int timeout() const; + + void setStdOutCodec(QTextCodec *c); + QTextCodec *stdOutCodec() const; + + bool stdOutBufferedSignalsEnabled() const; + void setStdOutBufferedSignalsEnabled(bool); + + bool stdErrBufferedSignalsEnabled() const; + void setStdErrBufferedSignalsEnabled(bool); + + QStringList environment() const; + void setEnvironment(const QStringList &); + + SynchronousProcessResponse run(const QString &binary, const QStringList &args); + +signals: + void stdOut(const QByteArray &data, bool firstTime); + void stdErr(const QByteArray &data, bool firstTime); + + void stdOutBuffered(const QString &data, bool firstTime); + void stdErrBuffered(const QString &data, bool firstTime); + +private slots: + void slotTimeout(); + void finished(int exitCode, QProcess::ExitStatus e); + void error(QProcess::ProcessError); + void stdOutReady(); + void stdErrReady(); + +private: + void processStdOut(bool emitSignals); + void processStdErr(bool emitSignals); + static QString convertStdErr(const QByteArray &); + QString convertStdOut(const QByteArray &) const; + + SynchronousProcessPrivate *m_d; +}; + +} +} +#endif diff --git a/src/libs/utils/utils.pri b/src/libs/utils/utils.pri new file mode 100644 index 00000000000..4e173f2cad1 --- /dev/null +++ b/src/libs/utils/utils.pri @@ -0,0 +1 @@ +LIBS *= -l$$qtLibraryTarget(Utils) diff --git a/src/libs/utils/utils.pro b/src/libs/utils/utils.pro new file mode 100644 index 00000000000..d98ca1d889b --- /dev/null +++ b/src/libs/utils/utils.pro @@ -0,0 +1,53 @@ +TEMPLATE = lib +TARGET = Utils + +DEFINES += QWORKBENCH_UTILS_LIBRARY + +include(../../qworkbenchlibrary.pri) + +SOURCES += \ + reloadpromptutils.cpp \ + settingsutils.cpp \ + filesearch.cpp \ + pathchooser.cpp \ + filewizardpage.cpp \ + filewizarddialog.cpp \ + projectintropage.cpp \ + basevalidatinglineedit.cpp \ + filenamevalidatinglineedit.cpp \ + projectnamevalidatinglineedit.cpp \ + codegeneration.cpp \ + newclasswidget.cpp \ + classnamevalidatinglineedit.cpp \ + linecolumnlabel.cpp \ + fancylineedit.cpp \ + qtcolorbutton.cpp \ + submiteditorwidget.cpp \ + synchronousprocess.cpp + +HEADERS += \ + utils_global.h \ + reloadpromptutils.h \ + settingsutils.h \ + filesearch.h \ + listutils.h \ + pathchooser.h \ + filewizardpage.h \ + filewizarddialog.h \ + projectintropage.h \ + basevalidatinglineedit.h \ + filenamevalidatinglineedit.h \ + projectnamevalidatinglineedit.h \ + codegeneration.h \ + newclasswidget.h \ + classnamevalidatinglineedit.h \ + linecolumnlabel.h \ + fancylineedit.h \ + qtcolorbutton.h \ + submiteditorwidget.h \ + synchronousprocess.h + +FORMS += filewizardpage.ui \ + projectintropage.ui \ + newclasswidget.ui \ + submiteditorwidget.ui diff --git a/src/libs/utils/utils_global.h b/src/libs/utils/utils_global.h new file mode 100644 index 00000000000..3a91f77a2b9 --- /dev/null +++ b/src/libs/utils/utils_global.h @@ -0,0 +1,57 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +/**************************************************************************** +** +** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved. +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $LICENSE$ +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef UTILS_GLOBAL_H +#define UTILS_GLOBAL_H + +#include <QtCore/qglobal.h> + +#if defined(QWORKBENCH_UTILS_LIBRARY) +# define QWORKBENCH_UTILS_EXPORT Q_DECL_EXPORT +#else +# define QWORKBENCH_UTILS_EXPORT Q_DECL_IMPORT +#endif + +#endif // UTILS_GLOBAL_H |