diff --git a/doc/qtcreator.qdoc b/doc/qtcreator.qdoc index a1f7ab3ed6f5acd617dd177f1ca21ff3923f4e41..4521b7e2fa4317c8eec094fc53e23be12ebfcc7b 100644 --- a/doc/qtcreator.qdoc +++ b/doc/qtcreator.qdoc @@ -814,21 +814,26 @@ a pointer to some private data structure, you will see a list of children, signals and slots. - Similarily, instead of showing a bunch of pointers and ints, - a QHash or QMap will display its contents in an orderly fashion, - a QFileInfo will expose e.g. access data, and the otherwise - "opaque" QVariant gives access to the "real" contents. - - The \gui{Locals and Watchers View} can be used to change the - contents of variables of simple data types like int or float - while the program is stopped. To do so, click into the 'Value' - column, modify the value there, and hit \key{Return}. + Similarly, instead of displaying many pointers and integers, Qt Creator's + debugger will display the contents of a QHash or QMap in an orderly manner. + Also, the debugger will display access data for QFileInfo and provide + access to the "real" contents of QVariant. + + The \gui{Locals and Watchers} view can be used to change the contents of + variables of simple data types such as \c int or \c float when the program + is stopped. To do so, click on the \gui Value column, modify the value + with the inplace editor, and hit \key Enter (or \key Return). - \section2 Modules - The \gui{Modules View} is hidden by default and only useful in + By default, the \gui Modules view is hidden as it is only useful with the + experimental delayed debug information loading feature. You can turn this + feature on by selecting \gui{Fast Debugger Start} + + + + The \gui Modules view is hidden by default and only useful in connection with the experimental feature of delayed debug information loading. This feature is accessible by selecting \gui{Debug} and \gui{Fast Debugger Start}. When using the @@ -849,29 +854,28 @@ commands + \section1 A Walkthrough for the Debugger Frontend - \section1 A short walk through the debugger frontend - - In our \l{Writing a Simple Program with Qt Creator}{TextFinder} - example, we read a text file into a QString and then display it with a - QTextEdit. Suppose, you would like to look at this QString, \c{line}, - and see what data it actually stores. Follow the steps described below - to place a break point and view the QString object's data. + In our \l{Writing a Simple Program with Qt Creator}{TextFinder} example, we + read a text file into a QString and then display it with a QTextEdit. + Suppose, you would like to look at this QString, \c{line}, and see what + data it actually stores. Follow the steps described below to place a + breakpoint and view the QString object's data. \table \row - \i \inlineimage qtcreator-setting-breakpoint1.png + \i \inlineimage qtcreator-setting-breakpoint1.png \i \bold{Setting a Breakpoint} First, we set a breakpoint on the line where we invoke - \l{QTextEdit::}{setPlainText()} by clicking between the line number and - the window border. Then, select \gui{Start Debugging} from the - \gui{Debug} menu or press \key{F5}. + \l{QTextEdit::}{setPlainText()} by clicking between the line number and the + window border. Then, select \gui{Start Debugging} from the \gui{Debug} menu + or press \key{F5}. \endtable Breakpoints are visible in the \gui{Breakpoints} view, shown below, in - \gui{Debug} mode. If you wish to remove a breakpoint, simply right - click on it and select \gui{Delete breakpoint} from the context menu. + \gui{Debug} mode. If you wish to remove a breakpoint, simply right-click on + it and select \gui{Delete breakpoint} from the context menu. \image qtcreator-setting-breakpoint2.png @@ -880,10 +884,10 @@ \image qtcreator-watcher.png - Suppose we modify our \c{on_findButton_clicked()} function to move back - to the start of the document and continue searching once the cursor - hits the end of the document. Adding this functionality can be done - with the code snippet below: + Suppose we modify our \c{on_findButton_clicked()} function to move back to + the start of the document and continue searching once the cursor hits the + end of the document. Adding this functionality can be done with the code + snippet below: \code void TextFinder::on_findButton_clicked() @@ -915,9 +919,9 @@ } \endcode - However, if you compile and run this code, the application will not - work correctly due to a logic error. To locate this logic error, you - can step through the code using the following buttons: + However, if you compile and run this code, the application will not work + correctly due to a logic error. To locate this logic error, you can step + through the code using the following buttons: \image qtcreator-debugging-buttons.png */ @@ -931,20 +935,20 @@ \title Tips and Tricks - \bold{Quick mode switch} + \bold{Quickly Switching between Modes} You can quickly switch between modes by pressing \key{Ctrl+1}, - \key{Ctrl+2}, etc. + \key{Ctrl+2}, and so on. - \bold{Other keyboard shortcuts} + \bold{Keyboard Shortcuts} - There are a lot of other \l{keyboard-shortcuts}{keyboard shortcuts}. + Qt Creator provides a lot of useful keyboard shortcuts. A complete list can + be found \l{Keyboard Shortcuts}{here}. - \bold{Command line} + \bold{Running Qt Creator from the Command Line} - You can start Qt Creator from a command prompt with an already - existing session or \c{.pro} file by giving the name as argument on the - command line. + You can start Qt Creator from a command prompt with an existing session or + \c{.pro} file by giving the name as argument on the command line. \bold{Sidebar} diff --git a/shared/cplusplus/Scope.cpp b/shared/cplusplus/Scope.cpp index 2c1b986b2c9f48d5afc19a08f5bcb0fc7b90f629..47221da121f58bd39c596bdba6e6b7f69d0067cb 100644 --- a/shared/cplusplus/Scope.cpp +++ b/shared/cplusplus/Scope.cpp @@ -292,6 +292,7 @@ Use *Scope::useAt(unsigned index) const void Scope::addUse(unsigned sourceOffset, Name *name) { +#ifdef CPLUSPLUS_WITH_USES if (++_useCount == _allocatedUses) { _allocatedUses += 4; _uses = reinterpret_cast<Use *>(realloc(_uses, _allocatedUses * sizeof(Use))); @@ -303,6 +304,7 @@ void Scope::addUse(unsigned sourceOffset, Name *name) else lastVisibleSymbol = _symbols[_symbolCount]; _uses[_useCount].init(sourceOffset, name, lastVisibleSymbol); +#endif } CPLUSPLUS_END_NAMESPACE diff --git a/shared/help/help.pri b/shared/help/help.pri index 9503d085938b6ae619b5d2567fa3fe8a163ec88a..dff0ae7699b673175d3571ba8d4ffa952340805e 100644 --- a/shared/help/help.pri +++ b/shared/help/help.pri @@ -9,7 +9,8 @@ HEADERS += \ $$PWD/helpviewer.h \ $$PWD/contentwindow.h \ $$PWD/bookmarkmanager.h \ - $$PWD/../namespace_global.h + $$PWD/../namespace_global.h \ + $$PWD/indexwindow.h SOURCES += \ $$PWD/filternamedialog.cpp \ @@ -19,7 +20,7 @@ SOURCES += \ $$PWD/contentwindow.cpp \ $$PWD/bookmarkmanager.cpp -FORMS += \ +FORMS += \ $$PWD/filternamedialog.ui \ $$PWD/topicchooser.ui \ $$PWD/bookmarkdialog.ui diff --git a/src/libs/cplusplus/Icons.cpp b/src/libs/cplusplus/Icons.cpp index 94b6469ea46b74a85b739bc5512f030d63a90ae9..3b7ee24da3cc595af3b13d1336e24612ffa7df18 100644 --- a/src/libs/cplusplus/Icons.cpp +++ b/src/libs/cplusplus/Icons.cpp @@ -61,11 +61,11 @@ Icons::Icons() { } -QIcon Icons::iconForSymbol(Symbol *symbol) const +QIcon Icons::iconForSymbol(const Symbol *symbol) const { if (symbol->isFunction() || (symbol->isDeclaration() && symbol->type()->isFunction())) { - Function *function = symbol->asFunction(); + const Function *function = symbol->asFunction(); if (!function) function = symbol->type()->asFunction(); diff --git a/src/libs/cplusplus/Icons.h b/src/libs/cplusplus/Icons.h index c49bcde12d145dba778329830f3413846d29f376..6d4e0bb25d66fe6274bf13d1def75f78fac28097 100644 --- a/src/libs/cplusplus/Icons.h +++ b/src/libs/cplusplus/Icons.h @@ -47,7 +47,7 @@ class CPLUSPLUS_EXPORT Icons public: Icons(); - QIcon iconForSymbol(Symbol *symbol) const; + QIcon iconForSymbol(const Symbol *symbol) const; QIcon keywordIcon() const; QIcon macroIcon() const; diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index 019cbfff1ff1656321b595a49c702992ced15950..cfcd06cacd7067b55000916460c59aa08dcb5c83 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -235,9 +235,9 @@ bool ResolveExpression::visit(ExpressionListAST *) return false; } -bool ResolveExpression::visit(BinaryExpressionAST *) +bool ResolveExpression::visit(BinaryExpressionAST *ast) { - // nothing to do. + accept(ast->left_expression); return false; } diff --git a/src/libs/utils/filenamevalidatinglineedit.cpp b/src/libs/utils/filenamevalidatinglineedit.cpp index 57a0ed7a5f91577946807db122112559ffe75a0c..5b308f5ce4728eef5823a2c82be842180438e5e3 100644 --- a/src/libs/utils/filenamevalidatinglineedit.cpp +++ b/src/libs/utils/filenamevalidatinglineedit.cpp @@ -33,26 +33,65 @@ #include "filenamevalidatinglineedit.h" +#include <QtCore/QRegExp> +#include <QtCore/QDebug> + namespace Core { namespace Utils { +// 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 QRegExp &windowsDeviceNoSubDirPattern() +{ + static const QRegExp rc(QLatin1String("CON|AUX|PRN|COM1|COM2|LPT1|LPT2|NUL"), + Qt::CaseInsensitive); + Q_ASSERT(rc.isValid()); + return rc; +} + +static const QRegExp &windowsDeviceSubDirPattern() +{ + static const QRegExp rc(QLatin1String(".*[/\\\\]CON|.*[/\\\\]AUX|.*[/\\\\]PRN|.*[/\\\\]COM1|.*[/\\\\]COM2|.*[/\\\\]LPT1|.*[/\\\\]LPT2|.*[/\\\\]NUL"), + Qt::CaseInsensitive); + Q_ASSERT(rc.isValid()); + return rc; +} + +// ----------- FileNameValidatingLineEdit FileNameValidatingLineEdit::FileNameValidatingLineEdit(QWidget *parent) : - BaseValidatingLineEdit(parent) + BaseValidatingLineEdit(parent), + m_allowDirectories(false), + m_unused(0) +{ +} + +bool FileNameValidatingLineEdit::allowDirectories() const { + return m_allowDirectories; +} +void FileNameValidatingLineEdit::setAllowDirectories(bool v) +{ + m_allowDirectories = v; } /* Validate a file base name, check for forbidden characters/strings. */ -static const char *notAllowedChars = "/?:&\\*\"|#%<> "; -static const char *notAllowedSubStrings[] = {".."}; +#ifdef Q_OS_WIN +# define SLASHES "/\\" +#else +# define SLASHES "/" +#endif -// 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" }; +static const char *notAllowedCharsSubDir = "?:&*\"|#%<> "; +static const char *notAllowedCharsNoSubDir = "?:&*\"|#%<> "SLASHES; -bool FileNameValidatingLineEdit::validateFileName(const QString &name, QString *errorMessage /* = 0*/) +static const char *notAllowedSubStrings[] = {".."}; + +bool FileNameValidatingLineEdit::validateFileName(const QString &name, + bool allowDirectories, + QString *errorMessage /* = 0*/) { if (name.isEmpty()) { if (errorMessage) @@ -60,6 +99,7 @@ bool FileNameValidatingLineEdit::validateFileName(const QString &name, QString * return false; } // Characters + const char *notAllowedChars = allowDirectories ? notAllowedCharsSubDir : notAllowedCharsNoSubDir; for (const char *c = notAllowedChars; *c; c++) if (name.contains(QLatin1Char(*c))) { if (errorMessage) @@ -76,22 +116,22 @@ bool FileNameValidatingLineEdit::validateFileName(const QString &name, QString * 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; - } + // Windows devices + bool matchesWinDevice = windowsDeviceNoSubDirPattern().exactMatch(name); + if (!matchesWinDevice && allowDirectories) + matchesWinDevice = windowsDeviceSubDirPattern().exactMatch(name); + if (matchesWinDevice) { + if (errorMessage) + *errorMessage = tr("The name must not match that of a MS Windows device. (%1)."). + arg(windowsDeviceNoSubDirPattern().pattern().replace(QLatin1Char('|'), QLatin1Char(','))); + return false; } return true; } bool FileNameValidatingLineEdit::validate(const QString &value, QString *errorMessage) const { - return validateFileName(value, errorMessage); + return validateFileName(value, m_allowDirectories, errorMessage); } } // namespace Utils diff --git a/src/libs/utils/filenamevalidatinglineedit.h b/src/libs/utils/filenamevalidatinglineedit.h index 5476e3cd5e936ec5c4084fe911526153dc092673..042a48fc5f19f5d1bd5a6df02aed5c29a3b0f2f2 100644 --- a/src/libs/utils/filenamevalidatinglineedit.h +++ b/src/libs/utils/filenamevalidatinglineedit.h @@ -43,14 +43,23 @@ class QWORKBENCH_UTILS_EXPORT FileNameValidatingLineEdit : public BaseValidating { Q_OBJECT Q_DISABLE_COPY(FileNameValidatingLineEdit) - + Q_PROPERTY(bool allowDirectories READ allowDirectories WRITE setAllowDirectories) public: explicit FileNameValidatingLineEdit(QWidget *parent = 0); - static bool validateFileName(const QString &name, QString *errorMessage /* = 0*/); + static bool validateFileName(const QString &name, + bool allowDirectories = false, + QString *errorMessage = 0); + + bool allowDirectories() const; + void setAllowDirectories(bool v); protected: virtual bool validate(const QString &value, QString *errorMessage) const; + +private: + bool m_allowDirectories; + void *m_unused; }; } // namespace Utils diff --git a/src/libs/utils/filewizardpage.cpp b/src/libs/utils/filewizardpage.cpp index 8a12e4c0f3c98a016aa1deedd3093243840b61af..3e85b34d44b729142ff233b5f16f2d37cdc06e23 100644 --- a/src/libs/utils/filewizardpage.cpp +++ b/src/libs/utils/filewizardpage.cpp @@ -123,7 +123,7 @@ void FileWizardPage::slotActivated() bool FileWizardPage::validateBaseName(const QString &name, QString *errorMessage /* = 0*/) { - return FileNameValidatingLineEdit::validateFileName(name, errorMessage); + return FileNameValidatingLineEdit::validateFileName(name, false, errorMessage); } } // namespace Utils diff --git a/src/libs/utils/newclasswidget.cpp b/src/libs/utils/newclasswidget.cpp index df7d81e7b39c9b854fc53cef019de68935d897f0..b34ee40d4fe9469745edd98531560335b682f5ff 100644 --- a/src/libs/utils/newclasswidget.cpp +++ b/src/libs/utils/newclasswidget.cpp @@ -346,6 +346,21 @@ void NewClassWidget::setFormExtension(const QString &e) m_d->m_formExtension = fixSuffix(e); } +bool NewClassWidget::allowDirectories() const +{ + return m_d->m_ui.headerFileLineEdit->allowDirectories(); +} + +void NewClassWidget::setAllowDirectories(bool v) +{ + // We keep all in sync + if (allowDirectories() != v) { + m_d->m_ui.sourceFileLineEdit->setAllowDirectories(v); + m_d->m_ui.headerFileLineEdit->setAllowDirectories(v); + m_d->m_ui.formFileLineEdit->setAllowDirectories(v); + } +} + void NewClassWidget::slotValidChanged() { const bool newValid = isValid(); diff --git a/src/libs/utils/newclasswidget.h b/src/libs/utils/newclasswidget.h index 04c2aaf58a4f4143ba521955e85e474f87fc943e..40c850d28e94b55809cc91a3d74961a0b8d24bed 100644 --- a/src/libs/utils/newclasswidget.h +++ b/src/libs/utils/newclasswidget.h @@ -73,6 +73,7 @@ class QWORKBENCH_UTILS_EXPORT NewClassWidget : public QWidget 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) + Q_PROPERTY(bool allowDirectories READ allowDirectories WRITE setAllowDirectories) // Utility "USER" property for wizards containing file names. Q_PROPERTY(QStringList files READ files DESIGNABLE false USER true) public: @@ -97,7 +98,7 @@ public: QString sourceExtension() const; QString headerExtension() const; QString formExtension() const; - + bool allowDirectories() const; bool isValid(QString *error = 0) const; @@ -125,6 +126,7 @@ public slots: void setSourceExtension(const QString &e); void setHeaderExtension(const QString &e); void setFormExtension(const QString &e); + void setAllowDirectories(bool v); /* Suggest a class name from the base class by stripping the leading 'Q' * character. This will happen automagically if the base class combo diff --git a/src/libs/utils/pathchooser.h b/src/libs/utils/pathchooser.h index 7ae60a255bf17c7d55d24121e3ec823e24cbb93c..ab821d5df1eebffd60f53336c2f43ebb46b782d4 100644 --- a/src/libs/utils/pathchooser.h +++ b/src/libs/utils/pathchooser.h @@ -30,6 +30,7 @@ ** version 1.2, included in the file GPL_EXCEPTION.txt in this package. ** ***************************************************************************/ + #ifndef PATHCHOOSER_H #define PATHCHOOSER_H diff --git a/src/libs/utils/projectnamevalidatinglineedit.cpp b/src/libs/utils/projectnamevalidatinglineedit.cpp index df77af8e832a21e41746e99c6199bcaa5a9ca1fb..4160bc18792f8a24714fc35fe431415117f0e90c 100644 --- a/src/libs/utils/projectnamevalidatinglineedit.cpp +++ b/src/libs/utils/projectnamevalidatinglineedit.cpp @@ -45,7 +45,7 @@ ProjectNameValidatingLineEdit::ProjectNameValidatingLineEdit(QWidget *parent) bool ProjectNameValidatingLineEdit::validateProjectName(const QString &name, QString *errorMessage /* = 0*/) { // Validation is file name + checking for dots - if (!FileNameValidatingLineEdit::validateFileName(name, errorMessage)) + if (!FileNameValidatingLineEdit::validateFileName(name, false, errorMessage)) return false; // We don't want dots in the directory name for some legacy Windows diff --git a/src/libs/utils/synchronousprocess.cpp b/src/libs/utils/synchronousprocess.cpp index 078373aa20837842dc505edbf791703539c73a06..6a1b2efa8403d49a73c39712b054a1396717edff 100644 --- a/src/libs/utils/synchronousprocess.cpp +++ b/src/libs/utils/synchronousprocess.cpp @@ -125,6 +125,7 @@ struct SynchronousProcessPrivate { SynchronousProcessResponse m_result; int m_hangTimerCount; int m_maxHangTimerCount; + bool m_startFailure; ChannelBuffer m_stdOut; ChannelBuffer m_stdErr; @@ -133,7 +134,8 @@ struct SynchronousProcessPrivate { SynchronousProcessPrivate::SynchronousProcessPrivate() : m_stdOutCodec(0), m_hangTimerCount(0), - m_maxHangTimerCount(defaultMaxHangTimerCount) + m_maxHangTimerCount(defaultMaxHangTimerCount), + m_startFailure(false) { } @@ -143,6 +145,7 @@ void SynchronousProcessPrivate::clearForRun() m_stdOut.clearForRun(); m_stdErr.clearForRun(); m_result.clear(); + m_startFailure = false; } // ----------- SynchronousProcess @@ -221,22 +224,26 @@ SynchronousProcessResponse SynchronousProcess::run(const QString &binary, qDebug() << '>' << Q_FUNC_INFO << binary << args; m_d->clearForRun(); - m_d->m_timer.start(); - - QApplication::setOverrideCursor(Qt::WaitCursor); + // On Windows, start failure is triggered immediately if the + // executable cannot be found in the path. Do not start the + // event loop in that case. 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); - } + if (!m_d->m_startFailure) { + m_d->m_timer.start(); + QApplication::setOverrideCursor(Qt::WaitCursor); + 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_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(); + m_d->m_timer.stop(); + QApplication::restoreOverrideCursor(); + } if (debug) qDebug() << '<' << Q_FUNC_INFO << binary << m_d->m_result; @@ -246,12 +253,14 @@ SynchronousProcessResponse SynchronousProcess::run(const QString &binary, void SynchronousProcess::slotTimeout() { if (++m_d->m_hangTimerCount > m_d->m_maxHangTimerCount) { + if (debug) + qDebug() << Q_FUNC_INFO << "HANG detected, killing"; m_d->m_process.kill(); m_d->m_result.result = SynchronousProcessResponse::Hang; + } else { + if (debug) + qDebug() << Q_FUNC_INFO << m_d->m_hangTimerCount; } - - if (debug) - qDebug() << Q_FUNC_INFO << m_d->m_hangTimerCount; } void SynchronousProcess::finished(int exitCode, QProcess::ExitStatus e) @@ -265,7 +274,9 @@ void SynchronousProcess::finished(int exitCode, QProcess::ExitStatus e) m_d->m_result.exitCode = exitCode; break; case QProcess::CrashExit: - m_d->m_result.result = SynchronousProcessResponse::TerminatedAbnormally; + // Was hang detected before and killed? + if (m_d->m_result.result != SynchronousProcessResponse::Hang) + m_d->m_result.result = SynchronousProcessResponse::TerminatedAbnormally; m_d->m_result.exitCode = -1; break; } @@ -277,7 +288,10 @@ 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; + // Was hang detected before and killed? + if (m_d->m_result.result != SynchronousProcessResponse::Hang) + m_d->m_result.result = SynchronousProcessResponse::StartFailed; + m_d->m_startFailure = true; m_d->m_eventLoop.quit(); } diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index 59222acc419685bae0994a0aca0e75fb4c632721..1d9050705496bc05501ed25a3a22cec105f034ce 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -127,6 +127,7 @@ MainWindow::MainWindow() : m_mimeDatabase(new MimeDatabase), m_navigationWidget(0), m_rightPaneWidget(0), + m_versionDialog(0), m_activeContext(0), m_pluginManager(0), m_outputPane(new OutputPane(m_globalContext)), @@ -1085,8 +1086,20 @@ void MainWindow::openRecentFile() void MainWindow::aboutQtCreator() { - VersionDialog versionDialog(this); - versionDialog.exec(); + if (!m_versionDialog) { + m_versionDialog = new VersionDialog(this); + connect(m_versionDialog, SIGNAL(finished(int)), + this, SLOT(destroyVersionDialog())); + } + m_versionDialog->show(); +} + +void MainWindow::destroyVersionDialog() +{ + if (m_versionDialog) { + m_versionDialog->deleteLater(); + m_versionDialog = 0; + } } void MainWindow::aboutPlugins() diff --git a/src/plugins/coreplugin/mainwindow.h b/src/plugins/coreplugin/mainwindow.h index 180b932d710bffe7d0b1e71cd5d85ecd937fda41..a8edd089972489c1076ddf1359d078969ec6aa2e 100644 --- a/src/plugins/coreplugin/mainwindow.h +++ b/src/plugins/coreplugin/mainwindow.h @@ -83,6 +83,7 @@ class OutputPane; class ProgressManager; class ShortcutSettings; class ViewManager; +class VersionDialog; class CORE_EXPORT MainWindow : public QMainWindow { @@ -160,6 +161,7 @@ private slots: void aboutPlugins(); void updateFocusWidget(QWidget *old, QWidget *now); void toggleNavigation(); + void destroyVersionDialog(); private: void updateContextObject(IContext *context); @@ -190,6 +192,7 @@ private: NavigationWidget *m_navigationWidget; RightPaneWidget *m_rightPaneWidget; Core::BaseView *m_outputView; + VersionDialog *m_versionDialog; IContext * m_activeContext; diff --git a/src/plugins/cppeditor/cppclasswizard.cpp b/src/plugins/cppeditor/cppclasswizard.cpp index 6730f5b9ed9c388184b1d6040bb55cfe433b0bda..652eec535f18aa4221e7bb1055e780a14a569979 100644 --- a/src/plugins/cppeditor/cppclasswizard.cpp +++ b/src/plugins/cppeditor/cppclasswizard.cpp @@ -73,6 +73,7 @@ ClassNamePage::ClassNamePage(const QString &sourceSuffix, m_newClassWidget->setBaseClassEditable(true); m_newClassWidget->setFormInputVisible(false); m_newClassWidget->setNamespacesEnabled(true); + m_newClassWidget->setAllowDirectories(true); connect(m_newClassWidget, SIGNAL(validChanged()), this, SLOT(slotValidChanged())); diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 254e9341de66b16c24f814dfadeecd1ec0a7170d..da52bb3d6016a367647e00aa59197607fa8d19fa 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -206,6 +206,7 @@ void CPPEditor::createToolBar(CPPEditorEditable *editable) connect(m_methodCombo, SIGNAL(activated(int)), this, SLOT(jumpToMethod(int))); connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateMethodBoxIndex())); + connect(m_methodCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateMethodBoxToolTip())); connect(file(), SIGNAL(changed()), this, SLOT(updateFileName())); @@ -355,10 +356,16 @@ void CPPEditor::updateMethodBoxIndex() if (lastIndex.isValid()) { bool blocked = m_methodCombo->blockSignals(true); m_methodCombo->setCurrentIndex(lastIndex.row()); + updateMethodBoxToolTip(); (void) m_methodCombo->blockSignals(blocked); } } +void CPPEditor::updateMethodBoxToolTip() +{ + m_methodCombo->setToolTip(m_methodCombo->currentText()); +} + static bool isCompatible(Name *name, Name *otherName) { if (NameId *nameId = name->asNameId()) { diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index e6c6d1aa8633cd807179308b2761685119a0a247..2420bcf4e5e441d67834d5d9d0a612dbbad09f06 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -115,7 +115,7 @@ private slots: void updateFileName(); void jumpToMethod(int index); void updateMethodBoxIndex(); - + void updateMethodBoxToolTip(); void onDocumentUpdated(CPlusPlus::Document::Ptr doc); private: diff --git a/src/plugins/cpptools/cppclassesfilter.cpp b/src/plugins/cpptools/cppclassesfilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6aa6734fca90b2c0b2d672e8bdaa532975766f4c --- /dev/null +++ b/src/plugins/cpptools/cppclassesfilter.cpp @@ -0,0 +1,50 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** 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 "cppclassesfilter.h" + +using namespace CppTools::Internal; + +CppClassesFilter::CppClassesFilter(CppModelManager *manager, Core::EditorManager *editorManager) + : CppQuickOpenFilter(manager, editorManager) +{ + setShortcutString("c"); + setIncludedByDefault(false); + + search.setSymbolsToSearchFor(SearchSymbols::Classes); + search.setSeparateScope(true); +} + +CppClassesFilter::~CppClassesFilter() +{ +} diff --git a/src/plugins/help/indexwindow.h b/src/plugins/cpptools/cppclassesfilter.h similarity index 58% rename from src/plugins/help/indexwindow.h rename to src/plugins/cpptools/cppclassesfilter.h index 51ebb06653d197fa2fd1b74f5bcdf1bcc44031c8..ba936eab869fe76cf9b9a0b9ef1ac5f0f266965e 100644 --- a/src/plugins/help/indexwindow.h +++ b/src/plugins/cpptools/cppclassesfilter.h @@ -31,52 +31,28 @@ ** ***************************************************************************/ -#ifndef INDEXWINDOW_H -#define INDEXWINDOW_H +#ifndef CPPCLASSESFILTER_H +#define CPPCLASSESFILTER_H -#include <QtCore/QUrl> -#include <QtGui/QWidget> -#include <QtGui/QLineEdit> +#include <cppquickopenfilter.h> -QT_BEGIN_NAMESPACE +namespace CppTools { +namespace Internal { -class QHelpIndexWidget; -class QHelpEngine; - -class IndexWindow : public QWidget +class CppClassesFilter : public CppQuickOpenFilter { Q_OBJECT public: - IndexWindow(QHelpEngine *helpEngine, QWidget *parent = 0); - ~IndexWindow(); - - void setSearchLineEditText(const QString &text); - QString searchLineEditText() const - { - return m_searchLineEdit->text(); - } - -signals: - void linkActivated(const QUrl &link); - void linksActivated(const QMap<QString, QUrl> &links, - const QString &keyword); - void escapePressed(); - -private slots: - void filterIndices(const QString &filter); - void enableSearchLineEdit(); - void disableSearchLineEdit(); - -private: - bool eventFilter(QObject *obj, QEvent *e); - void focusInEvent(QFocusEvent *e); + CppClassesFilter(CppModelManager *manager, Core::EditorManager *editorManager); + ~CppClassesFilter(); - QLineEdit *m_searchLineEdit; - QHelpIndexWidget *m_indexWidget; - QHelpEngine *m_helpEngine; + QString trName() const { return tr("Classes"); } + QString name() const { return QLatin1String("Classes"); } + Priority priority() const { return Medium; } }; -QT_END_NAMESPACE +} // namespace Internal +} // namespace CppTools -#endif // INDEXWINDOW_H +#endif // CPPCLASSESFILTER_H diff --git a/src/plugins/cpptools/cpphoverhandler.cpp b/src/plugins/cpptools/cpphoverhandler.cpp index 37b63bda9c23f4adf11670e34062efaded814a18..16ed8a9215039009e6d47403939d02d996824f83 100644 --- a/src/plugins/cpptools/cpphoverhandler.cpp +++ b/src/plugins/cpptools/cpphoverhandler.cpp @@ -60,7 +60,7 @@ using namespace CppTools::Internal; CppHoverHandler::CppHoverHandler(CppModelManager *manager, QObject *parent) - : QObject(parent), m_manager(manager) + : QObject(parent), m_manager(manager), m_helpEngineNeedsSetup(false) { QFileInfo fi(ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()->settings()->fileName()); m_helpEngine = new QHelpEngineCore(fi.absolutePath() @@ -68,6 +68,7 @@ CppHoverHandler::CppHoverHandler(CppModelManager *manager, QObject *parent) //m_helpEngine->setAutoSaveFilter(false); m_helpEngine->setupData(); m_helpEngine->setCurrentFilter(tr("Unfiltered")); + m_helpEngineNeedsSetup = m_helpEngine->registeredDocumentations().count() == 0; } void CppHoverHandler::updateContextHelpId(TextEditor::ITextEditor *editor, int pos) @@ -234,6 +235,12 @@ void CppHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, in } } + if (m_helpEngineNeedsSetup + && m_helpEngine->registeredDocumentations().count() > 0) { + m_helpEngine->setupData(); + m_helpEngineNeedsSetup = false; + } + if (!m_helpId.isEmpty() && !m_helpEngine->linksForIdentifier(m_helpId).isEmpty()) { m_toolTip = QString(QLatin1String("<table><tr><td valign=middle><nobr>%1</td>" "<td><img src=\":/cpptools/images/f1.svg\"></td></tr></table>")).arg(Qt::escape(m_toolTip)); diff --git a/src/plugins/cpptools/cpphoverhandler.h b/src/plugins/cpptools/cpphoverhandler.h index 9aaa17cb0f88e1e47c04ebca1a96114f53f6917b..d1de5277b1241468b5dfdfbeff5d9ec14ea49927 100644 --- a/src/plugins/cpptools/cpphoverhandler.h +++ b/src/plugins/cpptools/cpphoverhandler.h @@ -68,6 +68,7 @@ private: QHelpEngineCore *m_helpEngine; QString m_helpId; QString m_toolTip; + bool m_helpEngineNeedsSetup; }; } // namespace Internal diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index ccaff0bcfe5cf2e40a43a815004953f11c9a3607..042b93cc74d064a0bf007f29f587c79791a9355d 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -129,9 +129,12 @@ public: void setProjectFiles(const QStringList &files) { m_projectFiles = files; } - void operator()(QString &fileName) + void run(QString &fileName) { sourceNeeded(fileName, IncludeGlobal); } + void operator()(QString &fileName) + { run(fileName); } + protected: bool includeFile(const QString &absoluteFilePath, QByteArray *result) { @@ -254,7 +257,7 @@ protected: } virtual void startExpandingMacro(unsigned offset, - const rpp::Macro ¯o, + const rpp::Macro &, const QByteArray &originalText) { if (! m_currentDoc) @@ -264,7 +267,7 @@ protected: m_currentDoc->addMacroUse(offset, originalText.length()); } - virtual void stopExpandingMacro(unsigned offset, const rpp::Macro ¯o) + virtual void stopExpandingMacro(unsigned, const rpp::Macro &) { if (! m_currentDoc) return; @@ -409,6 +412,8 @@ CppModelManager::CppModelManager(QObject *parent) : CppModelManagerInterface(parent), m_core(ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()) { + m_dirty = true; + m_projectExplorer = ExtensionSystem::PluginManager::instance() ->getObject<ProjectExplorer::ProjectExplorerPlugin>(); @@ -417,6 +422,9 @@ CppModelManager::CppModelManager(QObject *parent) : ProjectExplorer::SessionManager *session = m_projectExplorer->session(); Q_ASSERT(session != 0); + connect(session, SIGNAL(projectAdded(ProjectExplorer::Project*)), + this, SLOT(onProjectAdded(ProjectExplorer::Project*))); + connect(session, SIGNAL(aboutToRemoveProject(ProjectExplorer::Project *)), this, SLOT(onAboutToRemoveProject(ProjectExplorer::Project *))); @@ -448,7 +456,7 @@ Document::Ptr CppModelManager::document(const QString &fileName) CppModelManager::DocumentTable CppModelManager::documents() { return m_documents; } -QStringList CppModelManager::projectFiles() const +QStringList CppModelManager::updateProjectFiles() const { QStringList files; QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects); @@ -460,7 +468,7 @@ QStringList CppModelManager::projectFiles() const return files; } -QStringList CppModelManager::includePaths() const +QStringList CppModelManager::updateIncludePaths() const { QStringList includePaths; QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects); @@ -472,7 +480,7 @@ QStringList CppModelManager::includePaths() const return includePaths; } -QStringList CppModelManager::frameworkPaths() const +QStringList CppModelManager::updateFrameworkPaths() const { QStringList frameworkPaths; QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects); @@ -484,7 +492,7 @@ QStringList CppModelManager::frameworkPaths() const return frameworkPaths; } -QByteArray CppModelManager::definedMacros() const +QByteArray CppModelManager::updateDefinedMacros() const { QByteArray macros; QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects); @@ -496,7 +504,7 @@ QByteArray CppModelManager::definedMacros() const return macros; } -QMap<QString, QByteArray> CppModelManager::buildWorkingCopyList() const +QMap<QString, QByteArray> CppModelManager::buildWorkingCopyList() { QMap<QString, QByteArray> workingCopy; QMapIterator<TextEditor::ITextEditor *, CppEditorSupport *> it(m_editorSupport); @@ -527,8 +535,14 @@ QFuture<void> CppModelManager::refreshSourceFiles(const QStringList &sourceFiles if (! sourceFiles.isEmpty() && qgetenv("QTCREATOR_NO_CODE_INDEXER").isNull()) { const QMap<QString, QByteArray> workingCopy = buildWorkingCopyList(); - QFuture<void> result = QtConcurrent::run(&CppModelManager::parse, this, - sourceFiles, workingCopy); + CppPreprocessor *preproc = new CppPreprocessor(this); + preproc->setProjectFiles(projectFiles()); + preproc->setIncludePaths(includePaths()); + preproc->setFrameworkPaths(frameworkPaths()); + preproc->setWorkingCopy(workingCopy); + + QFuture<void> result = QtConcurrent::run(&CppModelManager::parse, + preproc, sourceFiles); if (sourceFiles.count() > 1) { m_core->progressManager()->addTask(result, tr("Indexing"), @@ -669,28 +683,35 @@ void CppModelManager::onDocumentUpdated(Document::Ptr doc) sel.cursor = c; selections.append(sel); } - ed->setExtraExtraSelections(selections); + ed->setExtraSelections(TextEditor::BaseTextEditor::CodeWarningsSelection, selections); break; } } } +void CppModelManager::onProjectAdded(ProjectExplorer::Project *) +{ + m_dirty = true; +} + void CppModelManager::onAboutToRemoveProject(ProjectExplorer::Project *project) { + m_dirty = true; m_projects.remove(project); GC(); } void CppModelManager::onSessionUnloaded() { - if (m_core->progressManager()) + if (m_core->progressManager()) { m_core->progressManager()->cancelTasks(CppTools::Constants::TASK_INDEX); + m_dirty = true; + } } void CppModelManager::parse(QFutureInterface<void> &future, - CppModelManager *model, - QStringList files, - QMap<QString, QByteArray> workingCopy) + CppPreprocessor *preproc, + QStringList files) { Q_ASSERT(! files.isEmpty()); @@ -699,14 +720,8 @@ void CppModelManager::parse(QFutureInterface<void> &future, future.setProgressRange(0, files.size()); - CppPreprocessor preproc(model); - preproc.setWorkingCopy(workingCopy); - preproc.setProjectFiles(model->projectFiles()); - preproc.setIncludePaths(model->includePaths()); - preproc.setFrameworkPaths(model->frameworkPaths()); - QString conf = QLatin1String(pp_configuration_file); - (void) preproc(conf); + (void) preproc->run(conf); const int STEP = 10; @@ -725,7 +740,7 @@ void CppModelManager::parse(QFutureInterface<void> &future, #endif QString fileName = files.at(i); - preproc(fileName); + preproc->run(fileName); if (! (i % STEP)) // Yields execution of the current thread. QThread::yieldCurrentThread(); @@ -739,6 +754,8 @@ void CppModelManager::parse(QFutureInterface<void> &future, // Restore the previous thread priority. QThread::currentThread()->setPriority(QThread::NormalPriority); + + delete preproc; } void CppModelManager::GC() @@ -746,7 +763,7 @@ void CppModelManager::GC() DocumentTable documents = m_documents; QSet<QString> processed; - QStringList todo = m_projectFiles; + QStringList todo = projectFiles(); while (! todo.isEmpty()) { QString fn = todo.last(); diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index 187187cc5d313586293cd3fdb0e7d5186dc30c01..a91a414e4803e2464a68a149b5f1eac9ae43068a 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -58,6 +58,7 @@ namespace CppTools { namespace Internal { class CppEditorSupport; +class CppPreprocessor; class CppHoverHandler; class CppModelManager : public CppModelManagerInterface @@ -97,18 +98,54 @@ private Q_SLOTS: void onDocumentUpdated(CPlusPlus::Document::Ptr doc); void onAboutToRemoveProject(ProjectExplorer::Project *project); void onSessionUnloaded(); + void onProjectAdded(ProjectExplorer::Project *project); private: - QMap<QString, QByteArray> buildWorkingCopyList() const; - QStringList projectFiles() const; - QStringList includePaths() const; - QStringList frameworkPaths() const; - QByteArray definedMacros() const; + QMap<QString, QByteArray> buildWorkingCopyList(); + + QStringList projectFiles() + { + ensureUpdated(); + return m_projectFiles; + } + + QStringList includePaths() + { + ensureUpdated(); + return m_includePaths; + } + + QStringList frameworkPaths() + { + ensureUpdated(); + return m_frameworkPaths; + } + + QByteArray definedMacros() + { + ensureUpdated(); + return m_definedMacros; + } + + QStringList updateProjectFiles() const; + QStringList updateIncludePaths() const; + QStringList updateFrameworkPaths() const; + QByteArray updateDefinedMacros() const; + + void ensureUpdated() { + if (! m_dirty) + return; + + m_projectFiles = updateProjectFiles(); + m_includePaths = updateIncludePaths(); + m_frameworkPaths = updateFrameworkPaths(); + m_definedMacros = updateDefinedMacros(); + m_dirty = false; + } static void parse(QFutureInterface<void> &future, - CppModelManager *model, - QStringList files, - QMap<QString, QByteArray> workingCopy); + CppPreprocessor *preproc, + QStringList files); private: Core::ICore *m_core; @@ -116,8 +153,12 @@ private: CppHoverHandler *m_hoverHandler; DocumentTable m_documents; - // List of available source files + // cache + bool m_dirty; QStringList m_projectFiles; + QStringList m_includePaths; + QStringList m_frameworkPaths; + QByteArray m_definedMacros; // editor integration QMap<TextEditor::ITextEditor *, CppEditorSupport *> m_editorSupport; diff --git a/src/plugins/cpptools/cppquickopenfilter.cpp b/src/plugins/cpptools/cppquickopenfilter.cpp index 9470ec46039a57c77e3d1499b71c3e457f01c190..a1f1a9b3713e00c76a967d2922dad17875c48034 100644 --- a/src/plugins/cpptools/cppquickopenfilter.cpp +++ b/src/plugins/cpptools/cppquickopenfilter.cpp @@ -32,172 +32,13 @@ ***************************************************************************/ #include "cppquickopenfilter.h" +#include "cppmodelmanager.h" -#include <Literals.h> -#include <Symbols.h> -#include <SymbolVisitor.h> -#include <Scope.h> -#include <cplusplus/Overview.h> -#include <cplusplus/Icons.h> - +#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/ieditor.h> #include <texteditor/itexteditor.h> #include <texteditor/basetexteditor.h> -#include <QtCore/QMultiMap> - -#include <functional> - -using namespace CPlusPlus; - -namespace CppTools { -namespace Internal { - -class SearchSymbols: public std::unary_function<Document::Ptr, QList<ModelItemInfo> >, - protected SymbolVisitor -{ - Overview overview; - Icons icons; - QList<ModelItemInfo> items; - -public: - QList<ModelItemInfo> operator()(Document::Ptr doc) - { return operator()(doc, QString()); } - - QList<ModelItemInfo> operator()(Document::Ptr doc, const QString &scope) - { - QString previousScope = switchScope(scope); - items.clear(); - for (unsigned i = 0; i < doc->globalSymbolCount(); ++i) { - accept(doc->globalSymbolAt(i)); - } - (void) switchScope(previousScope); - return items; - } - -protected: - using SymbolVisitor::visit; - - void accept(Symbol *symbol) - { Symbol::visitSymbol(symbol, this); } - - QString switchScope(const QString &scope) - { - QString previousScope = _scope; - _scope = scope; - return previousScope; - } - - virtual bool visit(Enum *symbol) - { - QString name = symbolName(symbol); - QString previousScope = switchScope(name); - QIcon icon = icons.iconForSymbol(symbol); - Scope *members = symbol->members(); - items.append(ModelItemInfo(name, QString(), ModelItemInfo::Enum, - QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()), - symbol->line(), - icon)); - for (unsigned i = 0; i < members->symbolCount(); ++i) { - accept(members->symbolAt(i)); - } - (void) switchScope(previousScope); - return false; - } - - virtual bool visit(Function *symbol) - { - QString name = symbolName(symbol); - QString type = overview.prettyType(symbol->type()); - QIcon icon = icons.iconForSymbol(symbol); - items.append(ModelItemInfo(name, type, ModelItemInfo::Method, - QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()), - symbol->line(), - icon)); - return false; - } - - virtual bool visit(Namespace *symbol) - { - QString name = symbolName(symbol); - QString previousScope = switchScope(name); - Scope *members = symbol->members(); - for (unsigned i = 0; i < members->symbolCount(); ++i) { - accept(members->symbolAt(i)); - } - (void) switchScope(previousScope); - return false; - } -#if 0 - // This visit method would make function declaration be included in QuickOpen - virtual bool visit(Declaration *symbol) - { - if (symbol->type()->isFunction()) { - QString name = symbolName(symbol); - QString type = overview.prettyType(symbol->type()); - //QIcon icon = ...; - items.append(ModelItemInfo(name, type, ModelItemInfo::Method, - QString::fromUtf8(symbol->fileName(), symbol->line()), - symbol->line())); - } - return false; - } -#endif - virtual bool visit(Class *symbol) - { - QString name = symbolName(symbol); - QString previousScope = switchScope(name); - QIcon icon = icons.iconForSymbol(symbol); - items.append(ModelItemInfo(name, QString(), ModelItemInfo::Class, - QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()), - symbol->line(), - icon)); - Scope *members = symbol->members(); - for (unsigned i = 0; i < members->symbolCount(); ++i) { - accept(members->symbolAt(i)); - } - (void) switchScope(previousScope); - return false; - } - - QString symbolName(Symbol *symbol) const - { - QString name = _scope; - if (! name.isEmpty()) - name += QLatin1String("::"); - QString symbolName = overview.prettyName(symbol->name()); - if (symbolName.isEmpty()) { - QString type; - if (symbol->isNamespace()) { - type = QLatin1String("namespace"); - } else if (symbol->isEnum()) { - type = QLatin1String("enum"); - } else if (Class *c = symbol->asClass()) { - if (c->isUnion()) { - type = QLatin1String("union"); - } else if (c->isStruct()) { - type = QLatin1String("struct"); - } else { - type = QLatin1String("class"); - } - } else { - type = QLatin1String("symbol"); - } - symbolName = QLatin1String("<anonymous "); - symbolName += type; - symbolName += QLatin1String(">"); - } - name += symbolName; - return name; - } - -private: - QString _scope; -}; - -} // namespace Internal -} // namespace CppTools - using namespace CppTools::Internal; CppQuickOpenFilter::CppQuickOpenFilter(CppModelManager *manager, Core::EditorManager *editorManager) @@ -225,9 +66,8 @@ void CppQuickOpenFilter::onDocumentUpdated(CPlusPlus::Document::Ptr doc) void CppQuickOpenFilter::onAboutToRemoveFiles(const QStringList &files) { - foreach (QString file, files) { + foreach (const QString &file, files) m_searchList.remove(file); - } } void CppQuickOpenFilter::refresh(QFutureInterface<void> &future) @@ -245,7 +85,6 @@ QList<QuickOpen::FilterEntry> CppQuickOpenFilter::matchesFor(const QString &orig return entries; bool hasWildcard = (entry.contains('*') || entry.contains('?')); - SearchSymbols search; QMutableMapIterator<QString, Info> it(m_searchList); while (it.hasNext()) { it.next(); @@ -276,6 +115,5 @@ QList<QuickOpen::FilterEntry> CppQuickOpenFilter::matchesFor(const QString &orig void CppQuickOpenFilter::accept(QuickOpen::FilterEntry selection) const { ModelItemInfo info = qvariant_cast<CppTools::Internal::ModelItemInfo>(selection.internalData); - TextEditor::BaseTextEditor::openEditorAt(info.fileName, info.line); } diff --git a/src/plugins/cpptools/cppquickopenfilter.h b/src/plugins/cpptools/cppquickopenfilter.h index bf6696a02af24ed690d286177e6ed9746e206112..12eaacb3f980d194b7c1e69416dbd6d8ec2b3504 100644 --- a/src/plugins/cpptools/cppquickopenfilter.h +++ b/src/plugins/cpptools/cppquickopenfilter.h @@ -34,45 +34,18 @@ #ifndef CPPQUICKOPENFILTER_H #define CPPQUICKOPENFILTER_H -#include "cppmodelmanager.h" -#include <cplusplus/CppDocument.h> -#include <coreplugin/editormanager/editormanager.h> +#include "searchsymbols.h" + #include <quickopen/iquickopenfilter.h> -#include <QtGui/QIcon> -#include <QFile> -#include <QMetaType> + +namespace Core { +class EditorManager; +} namespace CppTools { namespace Internal { -struct ModelItemInfo -{ - enum ItemType { Enum, Class, Method }; - - ModelItemInfo() - { } - - ModelItemInfo(const QString &symbolName, - const QString &symbolType, - ItemType type, - const QString &fileName, - int line, - const QIcon &icon) - : symbolName(symbolName), - symbolType(symbolType), - type(type), - fileName(fileName), - line(line), - icon(icon) - { } - - QString symbolName; - QString symbolType; - ItemType type; - QString fileName; - int line; - QIcon icon; -}; +class CppModelManager; class CppQuickOpenFilter : public QuickOpen::IQuickOpenFilter { @@ -82,12 +55,15 @@ public: ~CppQuickOpenFilter(); QString trName() const { return tr("Classes and Methods"); } - QString name() const { return "Classes and Methods"; } + QString name() const { return QLatin1String("Classes and Methods"); } Priority priority() const { return Medium; } QList<QuickOpen::FilterEntry> matchesFor(const QString &entry); void accept(QuickOpen::FilterEntry selection) const; void refresh(QFutureInterface<void> &future); +protected: + SearchSymbols search; + private slots: void onDocumentUpdated(CPlusPlus::Document::Ptr doc); void onAboutToRemoveFiles(const QStringList &files); @@ -114,6 +90,4 @@ private: } // namespace Internal } // namespace CppTools -Q_DECLARE_METATYPE(CppTools::Internal::ModelItemInfo) - #endif // CPPQUICKOPENFILTER_H diff --git a/src/plugins/cpptools/cpptools.cpp b/src/plugins/cpptools/cpptools.cpp index 423ddf3016d0d4a967dffd0d4a7e236163aa9793..957f0cae9b07ed7bf97842baaf316c2dd7bd53a2 100644 --- a/src/plugins/cpptools/cpptools.cpp +++ b/src/plugins/cpptools/cpptools.cpp @@ -32,6 +32,7 @@ ***************************************************************************/ #include "cpptools.h" +#include "cppclassesfilter.h" #include "cppcodecompletion.h" #include "cpphoverhandler.h" #include "cppmodelmanager.h" @@ -87,6 +88,7 @@ bool CppToolsPlugin::initialize(const QStringList & /*arguments*/, QString *) CppQuickOpenFilter *quickOpenFilter = new CppQuickOpenFilter(m_modelManager, m_core->editorManager()); addAutoReleasedObject(quickOpenFilter); + addAutoReleasedObject(new CppClassesFilter(m_modelManager, m_core->editorManager())); // Menus Core::IActionContainer *mtools = am->actionContainer(Core::Constants::M_TOOLS); diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro index 17b72496a92f3a8c398e8bc3972da1983a7b8230..8a096900ebf699ba9f0712eafb670660ebffb113 100644 --- a/src/plugins/cpptools/cpptools.pro +++ b/src/plugins/cpptools/cpptools.pro @@ -4,31 +4,27 @@ include(../../qworkbenchplugin.pri) include(../../plugins/quickopen/quickopen.pri) include(cpptools_dependencies.pri) -#DEFINES += QT_NO_CAST_FROM_ASCII +# DEFINES += QT_NO_CAST_FROM_ASCII DEFINES += QT_NO_CAST_TO_ASCII -unix:QMAKE_CXXFLAGS_DEBUG+=-O3 - +unix:QMAKE_CXXFLAGS_DEBUG += -O3 INCLUDEPATH += . - DEFINES += CPPTOOLS_LIBRARY - CONFIG += help include(rpp/rpp.pri)|error("Can't find RPP") - -HEADERS += \ - cpptools_global.h \ - cppquickopenfilter.h - -SOURCES += \ - cppquickopenfilter.cpp \ - cpptoolseditorsupport.cpp +HEADERS += cpptools_global.h \ + cppquickopenfilter.h \ + cppclassesfilter.h \ + searchsymbols.h +SOURCES += cppquickopenfilter.cpp \ + cpptoolseditorsupport.cpp \ + cppclassesfilter.cpp \ + searchsymbols.cpp # Input SOURCES += cpptools.cpp \ cppmodelmanager.cpp \ cppcodecompletion.cpp \ cpphoverhandler.cpp - HEADERS += cpptools.h \ cppmodelmanager.h \ cppcodecompletion.h \ @@ -36,5 +32,4 @@ HEADERS += cpptools.h \ cppmodelmanagerinterface.h \ cpptoolseditorsupport.h \ cpptoolsconstants.h - RESOURCES += cpptools.qrc diff --git a/src/plugins/cpptools/searchsymbols.cpp b/src/plugins/cpptools/searchsymbols.cpp new file mode 100644 index 0000000000000000000000000000000000000000..670d0d6d471e892f9e70b3752899d8463ecf3a8b --- /dev/null +++ b/src/plugins/cpptools/searchsymbols.cpp @@ -0,0 +1,204 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** 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 "searchsymbols.h" + +#include <Literals.h> +#include <Scope.h> + +using namespace CPlusPlus; +using namespace CppTools::Internal; + +SearchSymbols::SearchSymbols(): + symbolsToSearchFor(Classes | Functions | Enums), + separateScope(false) +{ +} + +void SearchSymbols::setSymbolsToSearchFor(SymbolTypes types) +{ + symbolsToSearchFor = types; +} + +void SearchSymbols::setSeparateScope(bool separateScope) +{ + this->separateScope = separateScope; +} + +QList<ModelItemInfo> SearchSymbols::operator()(Document::Ptr doc, const QString &scope) +{ + QString previousScope = switchScope(scope); + items.clear(); + for (unsigned i = 0; i < doc->globalSymbolCount(); ++i) { + accept(doc->globalSymbolAt(i)); + } + (void) switchScope(previousScope); + return items; +} + +QString SearchSymbols::switchScope(const QString &scope) +{ + QString previousScope = _scope; + _scope = scope; + return previousScope; +} + +bool SearchSymbols::visit(Enum *symbol) +{ + if (!(symbolsToSearchFor & Enums)) + return false; + + QString name = symbolName(symbol); + QString scopedName = scopedSymbolName(name); + QString previousScope = switchScope(scopedName); + appendItem(separateScope ? name : scopedName, + separateScope ? previousScope : QString(), + ModelItemInfo::Enum, symbol); + Scope *members = symbol->members(); + for (unsigned i = 0; i < members->symbolCount(); ++i) { + accept(members->symbolAt(i)); + } + (void) switchScope(previousScope); + return false; +} + +bool SearchSymbols::visit(Function *symbol) +{ + if (!(symbolsToSearchFor & Functions)) + return false; + + QString name = symbolName(symbol); + QString scopedName = scopedSymbolName(name); + QString type = overview.prettyType(symbol->type(), + separateScope ? symbol->name() : 0); + appendItem(separateScope ? type : scopedName, + separateScope ? _scope : type, + ModelItemInfo::Method, symbol); + return false; +} + +bool SearchSymbols::visit(Namespace *symbol) +{ + QString name = findOrInsert(scopedSymbolName(symbol)); + QString previousScope = switchScope(name); + Scope *members = symbol->members(); + for (unsigned i = 0; i < members->symbolCount(); ++i) { + accept(members->symbolAt(i)); + } + (void) switchScope(previousScope); + return false; +} + +#if 0 +bool SearchSymbols::visit(Declaration *symbol) +{ + if (symbol->type()->isFunction()) { + QString name = scopedSymbolName(symbol); + QString type = overview.prettyType(symbol->type()); + appendItems(name, type, ModelItemInfo::Method, symbol->fileName()); + } + return false; +} +#endif + +bool SearchSymbols::visit(Class *symbol) +{ + if (!(symbolsToSearchFor & Classes)) + return false; + + QString name = symbolName(symbol); + QString scopedName = scopedSymbolName(name); + QString previousScope = switchScope(scopedName); + appendItem(separateScope ? name : scopedName, + separateScope ? previousScope : QString(), + ModelItemInfo::Class, symbol); + Scope *members = symbol->members(); + for (unsigned i = 0; i < members->symbolCount(); ++i) { + accept(members->symbolAt(i)); + } + (void) switchScope(previousScope); + return false; +} + +QString SearchSymbols::scopedSymbolName(const QString &symbolName) const +{ + QString name = _scope; + if (! name.isEmpty()) + name += QLatin1String("::"); + name += symbolName; + return name; +} + +QString SearchSymbols::scopedSymbolName(const Symbol *symbol) const +{ + return scopedSymbolName(symbolName(symbol)); +} + +QString SearchSymbols::symbolName(const Symbol *symbol) const +{ + QString symbolName = overview.prettyName(symbol->name()); + if (symbolName.isEmpty()) { + QString type; + if (symbol->isNamespace()) { + type = QLatin1String("namespace"); + } else if (symbol->isEnum()) { + type = QLatin1String("enum"); + } else if (const Class *c = symbol->asClass()) { + if (c->isUnion()) { + type = QLatin1String("union"); + } else if (c->isStruct()) { + type = QLatin1String("struct"); + } else { + type = QLatin1String("class"); + } + } else { + type = QLatin1String("symbol"); + } + symbolName = QLatin1String("<anonymous "); + symbolName += type; + symbolName += QLatin1String(">"); + } + return symbolName; +} + +void SearchSymbols::appendItem(const QString &name, + const QString &info, + ModelItemInfo::ItemType type, + const CPlusPlus::Symbol *symbol) +{ + const QIcon icon = icons.iconForSymbol(symbol); + items.append(ModelItemInfo(name, info, type, + QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()), + symbol->line(), + icon)); +} diff --git a/src/plugins/cpptools/searchsymbols.h b/src/plugins/cpptools/searchsymbols.h new file mode 100644 index 0000000000000000000000000000000000000000..d82f285972162ddf332d0cc278ecd5d2b41404ca --- /dev/null +++ b/src/plugins/cpptools/searchsymbols.h @@ -0,0 +1,145 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** 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 SEARCHSYMBOLS_H +#define SEARCHSYMBOLS_H + +#include <cplusplus/CppDocument.h> +#include <cplusplus/Icons.h> +#include <cplusplus/Overview.h> +#include <Symbols.h> +#include <SymbolVisitor.h> + +#include <QIcon> +#include <QMetaType> +#include <QString> + +namespace CppTools { +namespace Internal { + +struct ModelItemInfo +{ + enum ItemType { Enum, Class, Method }; + + ModelItemInfo() + { } + + ModelItemInfo(const QString &symbolName, + const QString &symbolType, + ItemType type, + const QString &fileName, + int line, + const QIcon &icon) + : symbolName(symbolName), + symbolType(symbolType), + type(type), + fileName(fileName), + line(line), + icon(icon) + { } + + QString symbolName; + QString symbolType; + ItemType type; + QString fileName; + int line; + QIcon icon; +}; + +class SearchSymbols: public std::unary_function<CPlusPlus::Document::Ptr, QList<ModelItemInfo> >, + protected CPlusPlus::SymbolVisitor +{ +public: + enum SymbolType { + Classes = 0x1, + Functions = 0x2, + Enums = 0x4 + }; + Q_DECLARE_FLAGS(SymbolTypes, SymbolType) + + SearchSymbols(); + + void setSymbolsToSearchFor(SymbolTypes types); + void setSeparateScope(bool separateScope); + + QList<ModelItemInfo> operator()(CPlusPlus::Document::Ptr doc) + { return operator()(doc, QString()); } + + QList<ModelItemInfo> operator()(CPlusPlus::Document::Ptr doc, const QString &scope); + +protected: + using SymbolVisitor::visit; + + void accept(CPlusPlus::Symbol *symbol) + { CPlusPlus::Symbol::visitSymbol(symbol, this); } + + QString switchScope(const QString &scope); + virtual bool visit(CPlusPlus::Enum *symbol); + virtual bool visit(CPlusPlus::Function *symbol); + virtual bool visit(CPlusPlus::Namespace *symbol); +#if 0 + // This visit method would make function declaration be included in QuickOpen + virtual bool visit(CPlusPlus::Declaration *symbol); +#endif + virtual bool visit(CPlusPlus::Class *symbol); + + QString scopedSymbolName(const QString &symbolName) const; + QString scopedSymbolName(const CPlusPlus::Symbol *symbol) const; + QString symbolName(const CPlusPlus::Symbol *symbol) const; + void appendItem(const QString &name, + const QString &info, + ModelItemInfo::ItemType type, + const CPlusPlus::Symbol *symbol); + +private: + QString findOrInsert(const QString &s) + { return *strings.insert(s); } + + QSet<QString> strings; // Used to avoid QString duplication + + QString _scope; + CPlusPlus::Overview overview; + CPlusPlus::Icons icons; + QList<ModelItemInfo> items; + SymbolTypes symbolsToSearchFor; + bool separateScope; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(SearchSymbols::SymbolTypes) + +} // namespace Internal +} // namespace CppTools + +Q_DECLARE_METATYPE(CppTools::Internal::ModelItemInfo) + +#endif // SEARCHSYMBOLS_H diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 42551168fe20e1e72e0e934797bfd9c7b0c16ffe..a94b1fb0931e3ac551f4fb815126b947ec998b80 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -317,10 +317,20 @@ void DebuggerManager::init() m_debugDumpersAction = new QAction(this); m_debugDumpersAction->setText(tr("Debug Custom Dumpers")); + m_debugDumpersAction->setToolTip(tr("This is an internal tool to " + "make debugging the Custom Data Dumper code easier. " + "Using this action is in general not needed unless you " + "want do debug Qt Creator itself.")); m_debugDumpersAction->setCheckable(true); m_skipKnownFramesAction = new QAction(this); m_skipKnownFramesAction->setText(tr("Skip Known Frames When Stepping")); + m_skipKnownFramesAction->setToolTip(tr("After checking this option" + "'Step Into' combines in certain situations several steps, " + "leading to 'less noisy' debugging. So will, e.g., the atomic " + "reference counting code be skipped, and a single 'Step Into' " + "for a signal emission will end up directly in the slot connected " + "to it")); m_skipKnownFramesAction->setCheckable(true); m_useCustomDumpersAction = new QAction(this); @@ -330,13 +340,6 @@ void DebuggerManager::init() m_useCustomDumpersAction->setCheckable(true); m_useCustomDumpersAction->setChecked(true); - m_useCustomDumpersAction = new QAction(this); - m_useCustomDumpersAction->setText(tr("Use Custom Display for Qt Objects")); - m_useCustomDumpersAction->setToolTip(tr("Checking this will make the debugger " - "try to use code to format certain data (QObject, QString, ...) nicely. ")); - m_useCustomDumpersAction->setCheckable(true); - m_useCustomDumpersAction->setChecked(true); - m_useFastStartAction = new QAction(this); m_useFastStartAction->setText(tr("Fast Debugger Start")); m_useFastStartAction->setToolTip(tr("Checking this will make the debugger " diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 80d0a046fc3179f334fa054f8ba1abcd59500cdd..1802c018001c8674588fc031600f7eb2480d41cc 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -1276,7 +1276,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) m_currentFrame = frame.findChild("addr").data() + '%' + frame.findChild("func").data() + '%'; - QApplication::alert(q->mainWindow(), 200); + QApplication::alert(q->mainWindow(), 3000); sendCommand("-file-list-exec-source-files", GdbQuerySources); sendCommand("-break-list", BreakList); QVariant var = QVariant::fromValue<GdbMi>(data); diff --git a/src/plugins/designer/cpp/formclasswizardpage.cpp b/src/plugins/designer/cpp/formclasswizardpage.cpp index d076753374b666ef632c4a97a1f2394857993bae..eac7271b404dd48488d17e9ac56bc4d6b2541703 100644 --- a/src/plugins/designer/cpp/formclasswizardpage.cpp +++ b/src/plugins/designer/cpp/formclasswizardpage.cpp @@ -63,6 +63,7 @@ FormClassWizardPage::FormClassWizardPage(QWidget * parent) : m_ui->newClassWidget->setBaseClassInputVisible(false); m_ui->newClassWidget->setNamespacesEnabled(true); + m_ui->newClassWidget->setAllowDirectories(true); connect(m_ui->newClassWidget, SIGNAL(validChanged()), this, SLOT(slotValidChanged())); diff --git a/src/plugins/find/basetextfind.cpp b/src/plugins/find/basetextfind.cpp index 63740d36527380a654cd3ea5027c6d19e66a0528..6598a47e6f3085409ba899c3f13f4903dd3ffe55 100644 --- a/src/plugins/find/basetextfind.cpp +++ b/src/plugins/find/basetextfind.cpp @@ -162,7 +162,10 @@ int BaseTextFind::replaceAll(const QString &before, const QString &after, QTextDocument::FindFlags findFlags) { QTextCursor editCursor = textCursor(); - editCursor.movePosition(QTextCursor::Start); + if (!m_findScope.isNull()) + editCursor.setPosition(m_findScope.selectionStart()); + else + editCursor.movePosition(QTextCursor::Start); editCursor.beginEditBlock(); int count = 0; QTextCursor found; diff --git a/src/plugins/git/commitdata.cpp b/src/plugins/git/commitdata.cpp index 60e2173a660ab315b406c5c79313d256a934f107..7ea937233c7e115e901b56ff72d58809edcece29 100644 --- a/src/plugins/git/commitdata.cpp +++ b/src/plugins/git/commitdata.cpp @@ -80,16 +80,16 @@ void CommitData::clear() panelInfo.clear(); panelData.clear(); - commitFiles.clear(); - notUpdatedFiles.clear(); + stagedFiles.clear(); + unstagedFiles.clear(); untrackedFiles.clear(); } QDebug operator<<(QDebug d, const CommitData &data) { d << data.panelInfo << data.panelData; - d.nospace() << "Commit: " << data.commitFiles << " Not updated: " - << data.notUpdatedFiles << " Untracked: " << data.untrackedFiles; + d.nospace() << "Commit: " << data.stagedFiles << " Not updated: " + << data.unstagedFiles << " Untracked: " << data.untrackedFiles; return d; } diff --git a/src/plugins/git/commitdata.h b/src/plugins/git/commitdata.h index 9cd5a83eb16c3e01fec0950c6ef3675354c440bb..b535168f6f357e56e7aa3877313ea9871febeee8 100644 --- a/src/plugins/git/commitdata.h +++ b/src/plugins/git/commitdata.h @@ -71,8 +71,8 @@ struct CommitData void clear(); GitSubmitEditorPanelInfo panelInfo; GitSubmitEditorPanelData panelData; - QStringList commitFiles; - QStringList notUpdatedFiles; + QStringList stagedFiles; + QStringList unstagedFiles; QStringList untrackedFiles; }; diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 7d87ce27827838b4971155378b8b4281695a5151..a1668e60cebcf93343e54862c30a7f429cf933dd 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -35,6 +35,7 @@ #include "gitplugin.h" #include "gitconstants.h" #include "commitdata.h" +#include "gitsubmiteditor.h" #include <coreplugin/icore.h> #include <coreplugin/coreconstants.h> @@ -51,7 +52,9 @@ #include <QtCore/QFuture> #include <QtCore/QTime> -#include <QtGui/QErrorMessage> +#include <QtGui/QMessageBox> +#include <QtGui/QMainWindow> // for msg box parent +#include <QtGui/QPushButton> using namespace Git; using namespace Git::Internal; @@ -77,12 +80,24 @@ inline Core::IEditor* locateEditor(const Core::ICore *core, const char *property return 0; } +static inline QString msgRepositoryNotFound(const QString &dir) +{ + return GitClient::tr("Unable to determine the repository for %1.").arg(dir); +} + +static inline QString msgParseFilesFailed() +{ + return GitClient::tr("Unable to parse the file output."); +} + +// Format a command for the status window static QString formatCommand(const QString &binary, const QStringList &args) { const QString timeStamp = QTime::currentTime().toString(QLatin1String("HH:mm")); return GitClient::tr("%1 Executing: %2 %3\n").arg(timeStamp, binary, args.join(QString(QLatin1Char(' ')))); } +// ---------------- GitClient GitClient::GitClient(GitPlugin* plugin, Core::ICore *core) : m_msgWait(tr("Waiting for data...")), m_plugin(plugin), @@ -311,6 +326,19 @@ bool GitClient::synchronousAdd(const QString &workingDirectory, const QStringLis bool GitClient::synchronousReset(const QString &workingDirectory, const QStringList &files) +{ + QString errorMessage; + const bool rc = synchronousReset(workingDirectory, files, &errorMessage); + if (!rc) { + m_plugin->outputWindow()->append(errorMessage); + m_plugin->outputWindow()->popup(false); + } + return rc; +} + +bool GitClient::synchronousReset(const QString &workingDirectory, + const QStringList &files, + QString *errorMessage) { if (Git::Constants::debug) qDebug() << Q_FUNC_INFO << workingDirectory << files; @@ -325,9 +353,25 @@ bool GitClient::synchronousReset(const QString &workingDirectory, // Note that git exits with 1 even if the operation is successful // Assume real failure if the output does not contain "foo.cpp modified" if (!rc && !output.contains(QLatin1String("modified"))) { - const QString errorMessage = tr("Unable to reset %n file(s) in %1: %2", 0, files.size()). - arg(workingDirectory, QString::fromLocal8Bit(errorText)); - m_plugin->outputWindow()->append(errorMessage); + *errorMessage = tr("Unable to reset %n file(s) in %1: %2", 0, files.size()).arg(workingDirectory, QString::fromLocal8Bit(errorText)); + return false; + } + return true; +} + +bool GitClient::synchronousCheckout(const QString &workingDirectory, + const QStringList &files, + QString *errorMessage) +{ + if (Git::Constants::debug) + qDebug() << Q_FUNC_INFO << workingDirectory << files; + QByteArray outputText; + QByteArray errorText; + QStringList arguments; + arguments << QLatin1String("checkout") << QLatin1String("--") << files; + const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText); + if (!rc) { + *errorMessage = tr("Unable to checkout %n file(s) in %1: %2", 0, files.size()).arg(workingDirectory, QString::fromLocal8Bit(errorText)); return false; } return true; @@ -365,16 +409,18 @@ void GitClient::executeGit(const QString &workingDirectory, const QStringList &a command->execute(arguments, workingDirectory, environment); } -bool GitClient::synchronousGit(const QString &workingDirectory - , const QStringList &arguments - , QByteArray* outputText - , QByteArray* errorText) +bool GitClient::synchronousGit(const QString &workingDirectory, + const QStringList &arguments, + QByteArray* outputText, + QByteArray* errorText, + bool logCommandToWindow) { if (Git::Constants::debug) qDebug() << "synchronousGit" << workingDirectory << arguments; const QString binary = QLatin1String(kGitCommand); - m_plugin->outputWindow()->append(formatCommand(binary, arguments)); + if (logCommandToWindow) + m_plugin->outputWindow()->append(formatCommand(binary, arguments)); QProcess process; process.setWorkingDirectory(workingDirectory); @@ -456,10 +502,11 @@ GitClient::StatusResult GitClient::gitStatus(const QString &workingDirectory, #<tab>modified:<blanks>git.pro \endcode */ -static bool parseFiles(const QStringList &lines, CommitData *d) +static bool parseFiles(const QString &output, CommitData *d) { enum State { None, CommitFiles, NotUpdatedFiles, UntrackedFiles }; + const QStringList lines = output.split(QLatin1Char('\n')); const QString branchIndicator = QLatin1String(kBranchIndicatorC); const QString commitIndicator = QLatin1String("# Changes to be committed:"); const QString notUpdatedIndicator = QLatin1String("# Changed but not updated:"); @@ -492,10 +539,10 @@ static bool parseFiles(const QStringList &lines, CommitData *d) const QString fileSpec = line.mid(2).trimmed(); switch (s) { case CommitFiles: - d->commitFiles.push_back(trimFileSpecification(fileSpec)); + d->stagedFiles.push_back(trimFileSpecification(fileSpec)); break; case NotUpdatedFiles: - d->notUpdatedFiles.push_back(trimFileSpecification(fileSpec)); + d->unstagedFiles.push_back(trimFileSpecification(fileSpec)); break; case UntrackedFiles: d->untrackedFiles.push_back(QLatin1String("untracked: ") + fileSpec); @@ -509,7 +556,7 @@ static bool parseFiles(const QStringList &lines, CommitData *d) } } } - return !d->commitFiles.empty() || !d->notUpdatedFiles.empty() || !d->untrackedFiles.empty(); + return !d->stagedFiles.empty() || !d->unstagedFiles.empty() || !d->untrackedFiles.empty(); } bool GitClient::getCommitData(const QString &workingDirectory, @@ -525,7 +572,7 @@ bool GitClient::getCommitData(const QString &workingDirectory, // Find repo const QString repoDirectory = GitClient::findRepositoryForDirectory(workingDirectory); if (repoDirectory.isEmpty()) { - *errorMessage = tr("Unable to determine the repository for %1.").arg(workingDirectory); + *errorMessage = msgRepositoryNotFound(workingDirectory); return false; } @@ -551,7 +598,7 @@ bool GitClient::getCommitData(const QString &workingDirectory, case StatusChanged: break; case StatusUnchanged: - *errorMessage = tr("There are no modified files."); + *errorMessage = msgNoChangedFiles(); return false; case StatusFailed: return false; @@ -575,9 +622,8 @@ bool GitClient::getCommitData(const QString &workingDirectory, // # // # list of files... - const QStringList lines = output.split(QLatin1Char('\n')); - if (!parseFiles(lines, d)) { - *errorMessage = tr("Unable to parse the file output."); + if (!parseFiles(output, d)) { + *errorMessage = msgParseFilesFailed(); return false; } @@ -638,6 +684,129 @@ bool GitClient::addAndCommit(const QString &repositoryDirectory, return rc; } +static inline bool askWithInformativeText(QWidget *parent, + const QString &title, + const QString &msg, + const QString &inf, + bool defaultValue) +{ + QMessageBox msgBox(QMessageBox::Question, title, msg, QMessageBox::Yes|QMessageBox::No, parent); + msgBox.setInformativeText(inf); + msgBox.setDefaultButton(defaultValue ? QMessageBox::Yes : QMessageBox::No); + return msgBox.exec() == QMessageBox::Yes; +} + +/* Revert: This function can be called with a file list (to revert single + * files) or a single directory (revert all). Qt Creator currently has only + * 'revert single' in its VCS menus, but the code is prepared to deal with + * reverting a directory pending a sophisticated selection dialog in the + * VCSBase plugin. */ + +GitClient::RevertResult GitClient::revertI(QStringList files, bool *ptrToIsDirectory, QString *errorMessage) +{ + if (Git::Constants::debug) + qDebug() << Q_FUNC_INFO << files; + + if (files.empty()) + return RevertCanceled; + + // Figure out the working directory + const QFileInfo firstFile(files.front()); + const bool isDirectory = firstFile.isDir(); + if (ptrToIsDirectory) + *ptrToIsDirectory = isDirectory; + const QString workingDirectory = isDirectory ? firstFile.absoluteFilePath() : firstFile.absolutePath(); + + const QString repoDirectory = GitClient::findRepositoryForDirectory(workingDirectory); + if (repoDirectory.isEmpty()) { + *errorMessage = msgRepositoryNotFound(workingDirectory); + return RevertFailed; + } + + // Check for changes + QString output; + switch (gitStatus(repoDirectory, false, &output, errorMessage)) { + case StatusChanged: + break; + case StatusUnchanged: + return RevertUnchanged; + case StatusFailed: + return RevertFailed; + } + CommitData d; + if (!parseFiles(output, &d)) { + *errorMessage = msgParseFilesFailed(); + return RevertFailed; + } + + // If we are looking at files, make them relative to the repository + // directory to match them in the status output list. + if (!isDirectory) { + const QDir repoDir(repoDirectory); + const QStringList::iterator cend = files.end(); + for (QStringList::iterator it = files.begin(); it != cend; ++it) + *it = repoDir.relativeFilePath(*it); + } + + // From the status output, determine all modified [un]staged files. + const QString modifiedPattern = QLatin1String("modified: "); + const QStringList allStagedFiles = GitSubmitEditor::statusListToFileList(d.stagedFiles.filter(modifiedPattern)); + const QStringList allUnstagedFiles = GitSubmitEditor::statusListToFileList(d.unstagedFiles.filter(modifiedPattern)); + // Unless a directory was passed, filter all modified files for the + // argument file list. + QStringList stagedFiles = allStagedFiles; + QStringList unstagedFiles = allUnstagedFiles; + if (!isDirectory) { + const QSet<QString> filesSet = files.toSet(); + stagedFiles = allStagedFiles.toSet().intersect(filesSet).toList(); + unstagedFiles = allUnstagedFiles.toSet().intersect(filesSet).toList(); + } + if (Git::Constants::debug) + qDebug() << Q_FUNC_INFO << d.stagedFiles << d.unstagedFiles << allStagedFiles << allUnstagedFiles << stagedFiles << unstagedFiles; + + if (stagedFiles.empty() && unstagedFiles.empty()) + return RevertUnchanged; + + // Ask to revert (to do: Handle lists with a selection dialog) + const QMessageBox::StandardButton answer + = QMessageBox::question(m_core->mainWindow(), + tr("Revert"), + tr("The file has been changed. Do you want to revert it?"), + QMessageBox::Yes|QMessageBox::No, + QMessageBox::No); + if (answer == QMessageBox::No) + return RevertCanceled; + + // Unstage the staged files + if (!stagedFiles.empty() && !synchronousReset(repoDirectory, stagedFiles, errorMessage)) + return RevertFailed; + // Finally revert! + if (!synchronousCheckout(repoDirectory, stagedFiles + unstagedFiles, errorMessage)) + return RevertFailed; + return RevertOk; +} + +void GitClient::revert(const QStringList &files) +{ + bool isDirectory; + QString errorMessage; + switch (revertI(files, &isDirectory, &errorMessage)) { + case RevertOk: + case RevertCanceled: + break; + case RevertUnchanged: { + const QString msg = (isDirectory || files.size() > 1) ? msgNoChangedFiles() : tr("The file is not modified."); + m_plugin->outputWindow()->append(msg); + m_plugin->outputWindow()->popup(); + } + break; + case RevertFailed: + m_plugin->outputWindow()->append(errorMessage); + m_plugin->outputWindow()->popup(); + break; + } +} + void GitClient::pull(const QString &workingDirectory) { executeGit(workingDirectory, QStringList(QLatin1String("pull")), m_plugin->outputWindow(), 0, true); @@ -648,6 +817,11 @@ void GitClient::push(const QString &workingDirectory) executeGit(workingDirectory, QStringList(QLatin1String("push")), m_plugin->outputWindow(), 0, true); } +QString GitClient::msgNoChangedFiles() +{ + return tr("There are no modified files."); +} + void GitClient::stash(const QString &workingDirectory) { // Check for changes and stash @@ -657,7 +831,7 @@ void GitClient::stash(const QString &workingDirectory) executeGit(workingDirectory, QStringList(QLatin1String("stash")), m_plugin->outputWindow(), 0, true); break; case StatusUnchanged: - m_plugin->outputWindow()->append(tr("There are no modified files.")); + m_plugin->outputWindow()->append(msgNoChangedFiles()); m_plugin->outputWindow()->popup(); break; case StatusFailed: @@ -694,8 +868,8 @@ QString GitClient::readConfig(const QString &workingDirectory, const QStringList arguments << QLatin1String("config") << configVar; QByteArray outputText; - if (synchronousGit(workingDirectory, arguments, &outputText)) - return QString::fromLocal8Bit(outputText); + if (synchronousGit(workingDirectory, arguments, &outputText, 0, false)) + return QString::fromLocal8Bit(outputText).remove(QLatin1Char('\r')); return QString(); } diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 5be276a7877f6d1f1fc82149d74fe0f812b74017..efc767e54095e98e8be96022f1bd5ed04cf4989f 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -90,11 +90,14 @@ public: void addFile(const QString &workingDirectory, const QString &fileName); bool synchronousAdd(const QString &workingDirectory, const QStringList &files); bool synchronousReset(const QString &workingDirectory, const QStringList &files); + bool synchronousReset(const QString &workingDirectory, const QStringList &files, QString *errorMessage); + bool synchronousCheckout(const QString &workingDirectory, const QStringList &files, QString *errorMessage); void pull(const QString &workingDirectory); void push(const QString &workingDirectory); void stash(const QString &workingDirectory); void stashPop(const QString &workingDirectory); + void revert(const QStringList &files); void branchList(const QString &workingDirectory); void stashList(const QString &workingDirectory); @@ -113,19 +116,21 @@ public: const QStringList &checkedFiles, const QStringList &origCommitFiles); + enum StatusResult { StatusChanged, StatusUnchanged, StatusFailed }; + StatusResult gitStatus(const QString &workingDirectory, + bool untracked, + QString *output = 0, + QString *errorMessage = 0); + GitSettings settings() const; void setSettings(const GitSettings &s); + static QString msgNoChangedFiles(); + public slots: void show(const QString &source, const QString &id); private: - enum StatusResult { StatusChanged, StatusUnchanged, StatusFailed }; - StatusResult gitStatus(const QString &workingDirectory, - bool untracked, - QString *output = 0, - QString *errorMessage = 0); - VCSBase::VCSBaseEditor *createVCSEditor(const QString &kind, QString title, const QString &source, @@ -141,9 +146,13 @@ private: bool outputToWindow = false); bool synchronousGit(const QString &workingDirectory, - const QStringList &arguments, - QByteArray* outputText = 0, - QByteArray* errorText = 0); + const QStringList &arguments, + QByteArray* outputText = 0, + QByteArray* errorText = 0, + bool logCommandToWindow = true); + + enum RevertResult { RevertOk, RevertUnchanged, RevertCanceled, RevertFailed }; + RevertResult revertI(QStringList files, bool *isDirectory, QString *errorMessage); const QString m_msgWait; GitPlugin *m_plugin; diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index ef57b9bb12a830b97c6870e2aadb7889a47ff04b..ebce0f7c452dbf9624a7186d3aded21a0fe056d0 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -118,7 +118,9 @@ GitPlugin::GitPlugin() : m_undoFileAction(0), m_undoProjectAction(0), m_showAction(0), - m_addAction(0), + m_stageAction(0), + m_unstageAction(0), + m_revertAction(0), m_commitAction(0), m_pullAction(0), m_pushAction(0), @@ -311,11 +313,23 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *error_message) connect(m_undoFileAction, SIGNAL(triggered()), this, SLOT(undoFileChanges())); gitContainer->addAction(command); - m_addAction = new QAction(tr("Add File"), this); - command = actionManager->registerAction(m_addAction, "Git.Add", globalcontext); + m_stageAction = new QAction(tr("Stage file for commit"), this); + command = actionManager->registerAction(m_stageAction, "Git.Stage", globalcontext); command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+A"))); command->setAttribute(Core::ICommand::CA_UpdateText); - connect(m_addAction, SIGNAL(triggered()), this, SLOT(addFile())); + connect(m_stageAction, SIGNAL(triggered()), this, SLOT(stageFile())); + gitContainer->addAction(command); + + m_unstageAction = new QAction(tr("Unstage file from commit"), this); + command = actionManager->registerAction(m_unstageAction, "Git.Unstage", globalcontext); + command->setAttribute(Core::ICommand::CA_UpdateText); + connect(m_unstageAction, SIGNAL(triggered()), this, SLOT(unstageFile())); + gitContainer->addAction(command); + + m_revertAction = new QAction(tr("Revert..."), this); + command = actionManager->registerAction(m_revertAction, "Git.Revert", globalcontext); + command->setAttribute(Core::ICommand::CA_UpdateText); + connect(m_revertAction, SIGNAL(triggered()), this, SLOT(revertFile())); gitContainer->addAction(command); gitContainer->addAction(createSeparator(actionManager, globalcontext, QLatin1String("Git.Sep.Project"), this)); @@ -537,14 +551,28 @@ void GitPlugin::undoProjectChanges() m_gitClient->hardReset(workingDirectory, QString()); } -void GitPlugin::addFile() +void GitPlugin::stageFile() { - QFileInfo fileInfo = currentFile(); - QString fileName = fileInfo.fileName(); - QString workingDirectory = fileInfo.absolutePath(); + const QFileInfo fileInfo = currentFile(); + const QString fileName = fileInfo.fileName(); + const QString workingDirectory = fileInfo.absolutePath(); m_gitClient->addFile(workingDirectory, fileName); } +void GitPlugin::unstageFile() +{ + const QFileInfo fileInfo = currentFile(); + const QString fileName = fileInfo.fileName(); + const QString workingDirectory = fileInfo.absolutePath(); + m_gitClient->synchronousReset(workingDirectory, QStringList(fileName)); +} + +void GitPlugin::revertFile() +{ + const QFileInfo fileInfo = currentFile(); + m_gitClient->revert(QStringList(fileInfo.absoluteFilePath())); +} + void GitPlugin::startCommit() { if (m_changeTmpFile) { @@ -570,7 +598,7 @@ void GitPlugin::startCommit() // Store repository for diff and the original list of // files to be able to unstage files the user unchecks m_submitRepository = data.panelInfo.repository; - m_submitOrigCommitFiles = GitSubmitEditor::statusListToFileList(data.commitFiles); + m_submitOrigCommitFiles = GitSubmitEditor::statusListToFileList(data.stagedFiles); if (Git::Constants::debug) qDebug() << Q_FUNC_INFO << data << commitTemplate; @@ -602,7 +630,7 @@ Core::IEditor *GitPlugin::openSubmitEditor(const QString &fileName, const Commit Q_ASSERT(submitEditor); // The actions are for some reason enabled by the context switching // mechanism. Disable them correctly. - m_submitCurrentAction->setEnabled(!cd.commitFiles.empty()); + m_submitCurrentAction->setEnabled(!cd.stagedFiles.empty()); m_diffSelectedFilesAction->setEnabled(false); m_undoAction->setEnabled(false); m_redoAction->setEnabled(false); @@ -722,7 +750,9 @@ void GitPlugin::updateActions() m_logAction->setText(tr("Log %1").arg(fileName)); m_blameAction->setText(tr("Blame %1").arg(fileName)); m_undoFileAction->setText(tr("Undo changes for %1").arg(fileName)); - m_addAction->setText(tr("Add %1").arg(fileName)); + m_stageAction->setText(tr("Stage %1 for commit").arg(fileName)); + m_unstageAction->setText(tr("Unstage %1 from commit").arg(fileName)); + m_revertAction->setText(tr("Revert %1...").arg(fileName)); if (repository.isEmpty()) { // If the file is not in a repository, the corresponding project will // be neither and we can disable everything and return @@ -731,7 +761,9 @@ void GitPlugin::updateActions() m_logAction->setEnabled(false); m_blameAction->setEnabled(false); m_undoFileAction->setEnabled(false); - m_addAction->setEnabled(false); + m_stageAction->setEnabled(false); + m_unstageAction->setEnabled(false); + m_revertAction->setEnabled(false); m_diffProjectAction->setEnabled(false); m_diffProjectAction->setText(tr("Diff Project")); m_statusProjectAction->setText(tr("Status Project")); @@ -747,7 +779,9 @@ void GitPlugin::updateActions() m_logAction->setEnabled(true); m_blameAction->setEnabled(true); m_undoFileAction->setEnabled(true); - m_addAction->setEnabled(true); + m_stageAction->setEnabled(true); + m_unstageAction->setEnabled(true); + m_revertAction->setEnabled(true); } if (m_projectExplorer && m_projectExplorer->currentNode() diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h index 3da8ff26cec6c1ad194613864a02f330a7edf7a2..adff899e505564dc680a3a9dc4ac161bcae306a0 100644 --- a/src/plugins/git/gitplugin.h +++ b/src/plugins/git/gitplugin.h @@ -116,7 +116,9 @@ private slots: void logProject(); void undoFileChanges(); void undoProjectChanges(); - void addFile(); + void stageFile(); + void unstageFile(); + void revertFile(); void showCommit(); void startCommit(); @@ -144,7 +146,9 @@ private: QAction *m_undoFileAction; QAction *m_undoProjectAction; QAction *m_showAction; - QAction *m_addAction; + QAction *m_stageAction; + QAction *m_unstageAction; + QAction *m_revertAction; QAction *m_commitAction; QAction *m_pullAction; QAction *m_pushAction; diff --git a/src/plugins/git/gitsubmiteditor.cpp b/src/plugins/git/gitsubmiteditor.cpp index 516dc6570b73c7b9e62d72e0fb0d01def65c0513..db854f3e3c6d406bd20f3ff2ca98cd6203645ca0 100644 --- a/src/plugins/git/gitsubmiteditor.cpp +++ b/src/plugins/git/gitsubmiteditor.cpp @@ -67,9 +67,9 @@ void GitSubmitEditor::setCommitData(const CommitData &d) submitEditorWidget()->setPanelData(d.panelData); submitEditorWidget()->setPanelInfo(d.panelInfo); - addFiles(d.commitFiles, true, true); + addFiles(d.stagedFiles, true, true); // Not Updated: Initially unchecked - addFiles(d.notUpdatedFiles, false, true); + addFiles(d.unstagedFiles, false, true); addFiles(d.untrackedFiles, false, true); } diff --git a/src/plugins/help/help.pro b/src/plugins/help/help.pro index 1148606cab73e847a7b8bb75ce359cae31a93c21..b2e9a1dbd613cec02e2b73ed04d1cd6c7e1eaa3d 100644 --- a/src/plugins/help/help.pro +++ b/src/plugins/help/help.pro @@ -16,8 +16,8 @@ HEADERS += helpplugin.h \ searchwidget.h \ helpfindsupport.h \ help_global.h \ - helpindexfilter.h \ - indexwindow.h + helpindexfilter.h + SOURCES += helpplugin.cpp \ docsettingspage.cpp \ filtersettingspage.cpp \ @@ -26,6 +26,7 @@ SOURCES += helpplugin.cpp \ searchwidget.cpp \ helpfindsupport.cpp \ helpindexfilter.cpp + FORMS += docsettingspage.ui \ filtersettingspage.ui RESOURCES += help.qrc diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index 2de31700a867462dba9d8a17017cf8d81e990096..dc28901b7050540b8dc028165ccf658308a0c493 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -405,17 +405,17 @@ void PerforcePlugin::extensionsInitialized() void PerforcePlugin::openCurrentFile() { - runP4Cmd(QStringList() << QLatin1String("edit") << currentFileName(), QStringList(), true); + vcsOpen(currentFileName()); } void PerforcePlugin::addCurrentFile() { - runP4Cmd(QStringList() << QLatin1String("add") << currentFileName(), QStringList(), true); + vcsAdd(currentFileName()); } void PerforcePlugin::deleteCurrentFile() { - runP4Cmd(QStringList() << QLatin1String("delete") << currentFileName(), QStringList(), true); + vcsDelete(currentFileName()); } void PerforcePlugin::revertCurrentFile() @@ -426,7 +426,7 @@ void PerforcePlugin::revertCurrentFile() QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(m_coreInstance, fileName); QStringList args; args << QLatin1String("diff") << QLatin1String("-sa"); - PerforceResponse result = runP4Cmd(args, QStringList(), false, true, codec); + PerforceResponse result = runP4Cmd(args, QStringList(), CommandToWindow|StdErrToWindow|ErrorToWindow, codec); if (result.error) return; @@ -444,7 +444,7 @@ void PerforcePlugin::revertCurrentFile() foreach (Core::IFile *file, files) { fm->blockFileChange(file); } - PerforceResponse result2 = runP4Cmd(QStringList() << QLatin1String("revert") << fileName, QStringList(), true); + PerforceResponse result2 = runP4Cmd(QStringList() << QLatin1String("revert") << fileName, QStringList(), CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow); Core::IFile::ReloadBehavior tempBehavior = Core::IFile::ReloadAll; foreach (Core::IFile *file, files) { @@ -489,7 +489,7 @@ void PerforcePlugin::printOpenedFileList() Core::IEditor *e = m_coreInstance->editorManager()->currentEditor(); if (e) e->widget()->setFocus(); - PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("opened"), QStringList(), true); + PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("opened"), QStringList(), CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow); } #ifdef USE_P4_API @@ -522,7 +522,8 @@ void PerforcePlugin::submit() return; } - PerforceResponse result = runP4Cmd(QStringList()<< QLatin1String("change") << QLatin1String("-o"), QStringList(), false); + PerforceResponse result = runP4Cmd(QStringList()<< QLatin1String("change") << QLatin1String("-o"), QStringList(), + CommandToWindow|StdErrToWindow|ErrorToWindow); if (result.error) { delete m_changeTmpFile; m_changeTmpFile = 0; @@ -550,7 +551,8 @@ void PerforcePlugin::submit() foreach (const QString &f, files) nativeFiles << QDir::toNativeSeparators(f); - PerforceResponse result2 = runP4Cmd(QStringList(QLatin1String("fstat")), nativeFiles, false); + PerforceResponse result2 = runP4Cmd(QStringList(QLatin1String("fstat")), nativeFiles, + CommandToWindow|StdErrToWindow|ErrorToWindow); if (result2.error) { delete m_changeTmpFile; m_changeTmpFile = 0; @@ -597,8 +599,10 @@ void PerforcePlugin::printPendingChanges() PendingChangesDialog dia(pendingChangesData(), m_coreInstance->mainWindow()); qApp->restoreOverrideCursor(); if (dia.exec() == QDialog::Accepted) { - int i = dia.changeNumber(); - PerforceResponse result = runP4Cmd(QStringList()<<"submit"<<"-c"<<QString::number(i), QStringList(), true); + const int i = dia.changeNumber(); + QStringList args(QLatin1String("submit")); + args << QLatin1String("-c") << QString::number(i); + runP4Cmd(args, QStringList(), CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow); } } @@ -628,7 +632,8 @@ void PerforcePlugin::annotate(const QString &fileName) QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(m_coreInstance, fileName); QStringList args; args << QLatin1String("annotate") << QLatin1String("-cqi") << fileName; - const PerforceResponse result = runP4Cmd(args, QStringList(), false, true, codec); + const PerforceResponse result = runP4Cmd(args, QStringList(), + CommandToWindow|StdErrToWindow|ErrorToWindow, codec); if (!result.error) { const QFileInfo fi(fileName); showOutputInEditor(tr("p4 annotate %1").arg(fi.fileName()), result.stdOut, VCSBase::AnnotateOutput, codec); @@ -654,7 +659,8 @@ void PerforcePlugin::filelog(const QString &fileName) QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(m_coreInstance, fileName); QStringList args; args << QLatin1String("filelog") << QLatin1String("-li") << fileName; - const PerforceResponse result = runP4Cmd(args, QStringList(), false, true, codec); + const PerforceResponse result = runP4Cmd(args, QStringList(), + CommandToWindow|StdErrToWindow|ErrorToWindow, codec); if (!result.error) { const QFileInfo fi(fileName); showOutputInEditor(tr("p4 filelog %1").arg(fi.fileName()), result.stdOut, VCSBase::LogOutput, codec); @@ -718,18 +724,19 @@ bool PerforcePlugin::managesDirectory(const QString &directory) const QStringList args; args << QLatin1String("fstat") << QLatin1String("-m1") << p4Path; - const PerforceResponse result = runP4Cmd(args, QStringList(), false, false); + const PerforceResponse result = runP4Cmd(args, QStringList(), 0u); return result.stdOut.contains("depotFile") || result.stdErr.contains("... - no such file(s)"); } QString PerforcePlugin::findTopLevelForDirectory(const QString & /* dir */) const { // First check with p4 client -o - PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("client") << QLatin1String("-o"), QStringList(), false, false); + PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("client") << QLatin1String("-o"), QStringList(), 0u); if (result.error) return QString::null; QRegExp regExp(QLatin1String("(\\n|\\r\\n|\\r)Root:\\s*(.*)(\\n|\\r\\n|\\r)")); + Q_ASSERT(regExp.isValid()); regExp.setMinimal(true); if (regExp.indexIn(result.stdOut) != -1) { QString file = regExp.cap(2).trimmed(); @@ -741,20 +748,24 @@ QString PerforcePlugin::findTopLevelForDirectory(const QString & /* dir */) cons bool PerforcePlugin::vcsOpen(const QString &fileName) { - PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("edit") << QDir::toNativeSeparators(fileName), QStringList(), true); + PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("edit") << QDir::toNativeSeparators(fileName), QStringList(), + CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow); return !result.error; } bool PerforcePlugin::vcsAdd(const QString &fileName) { - PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("add") << fileName, QStringList(), true); + PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("add") << fileName, QStringList(), + CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow); return !result.error; } bool PerforcePlugin::vcsDelete(const QString &fileName) { - PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("revert") << fileName, QStringList(), true); - PerforceResponse result2 = runP4Cmd(QStringList() << QLatin1String("delete") << fileName, QStringList(), true); + PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("revert") << fileName, QStringList(), + CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow); + PerforceResponse result2 = runP4Cmd(QStringList() << QLatin1String("delete") << fileName, QStringList(), + CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow); // TODO need to carefully parse the actual messages from perforce // or do a fstat before to decide what to do @@ -767,8 +778,7 @@ bool PerforcePlugin::vcsDelete(const QString &fileName) PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args, const QStringList &extraArgs, - bool showStdOutInOutputWindow, - bool showStdErrInOutputWindow, + unsigned logFlags, QTextCodec *outputCodec) const { if (Perforce::Constants::debug) @@ -801,12 +811,14 @@ PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args, } actualArgs << args; - response.command = m_settings.p4Command; - response.command += blank; - response.command += actualArgs.join(QString(blank)); - const QString timeStamp = QTime::currentTime().toString(QLatin1String("HH:mm")); - const QString outputText = tr("%1 Executing: %2\n").arg(timeStamp, response.command); - showOutput(outputText, false); + if (logFlags & CommandToWindow) { + QString command = m_settings.p4Command; + command += blank; + command += actualArgs.join(QString(blank)); + const QString timeStamp = QTime::currentTime().toString(QLatin1String("HH:mm")); + const QString outputText = tr("%1 Executing: %2\n").arg(timeStamp, command); + showOutput(outputText, false); + } // Run, connect stderr to the output window Core::Utils::SynchronousProcess process; @@ -815,13 +827,13 @@ PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args, process.setEnvironment(environment()); // connect stderr to the output window if desired - if (showStdErrInOutputWindow) { + if (logFlags & StdErrToWindow) { process.setStdErrBufferedSignalsEnabled(true); connect(&process, SIGNAL(stdErrBuffered(QString,bool)), m_perforceOutputWindow, SLOT(append(QString,bool))); } // connect stdout to the output window if desired - if (showStdOutInOutputWindow) { + if (logFlags & StdOutToWindow) { process.setStdOutBufferedSignalsEnabled(true); connect(&process, SIGNAL(stdOutBuffered(QString,bool)), m_perforceOutputWindow, SLOT(append(QString,bool))); } @@ -847,13 +859,15 @@ PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args, response.message = tr("Could not start perforce '%1'. Please check your settings in the preferences.").arg(m_settings.p4Command); break; case Core::Utils::SynchronousProcessResponse::Hang: - response.message = tr("Subversion did not respond within timeout limit (%1 ms).").arg(p4Timeout ); + response.message = tr("Perforce did not respond within timeout limit (%1 ms).").arg(p4Timeout ); break; } - if (response.error) - m_perforceOutputWindow->append(response.message, true); - - + if (response.error) { + if (Perforce::Constants::debug) + qDebug() << response.message; + if (logFlags & ErrorToWindow) + m_perforceOutputWindow->append(response.message, true); + } return response; } @@ -923,7 +937,7 @@ void PerforcePlugin::p4Diff(const QStringList &files, QString diffname) } } - const PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("diff") << QLatin1String("-du"), files, false, codec); + const PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("diff") << QLatin1String("-du"), files, CommandToWindow|StdErrToWindow|ErrorToWindow, codec); if (result.error) return; @@ -948,7 +962,7 @@ void PerforcePlugin::describe(const QString & source, const QString &n) QTextCodec *codec = source.isEmpty() ? static_cast<QTextCodec *>(0) : VCSBase::VCSBaseEditor::getCodec(m_coreInstance, source); QStringList args; args << QLatin1String("describe") << QLatin1String("-du") << n; - const PerforceResponse result = runP4Cmd(args, QStringList(), codec); + const PerforceResponse result = runP4Cmd(args, QStringList(), CommandToWindow|StdErrToWindow|ErrorToWindow, codec); if (!result.error) showOutputInEditor(tr("p4 describe %1").arg(n), result.stdOut, VCSBase::DiffOutput, codec); } diff --git a/src/plugins/perforce/perforceplugin.h b/src/plugins/perforce/perforceplugin.h index 4c088563324ae8999d279b5c8607b3300aeabec2..7a4e23077794ef89599d00b3818d537fb118c46a 100644 --- a/src/plugins/perforce/perforceplugin.h +++ b/src/plugins/perforce/perforceplugin.h @@ -86,7 +86,6 @@ private: struct PerforceResponse { bool error; - QString command; QString stdOut; QString stdErr; QString message; @@ -161,12 +160,15 @@ private: Core::IEditor *showOutputInEditor(const QString& title, const QString output, int editorType, QTextCodec *codec = 0); + + // Verbosity flags for runP4Cmd. + enum RunLogFlags { CommandToWindow = 0x1, StdOutToWindow = 0x2, StdErrToWindow = 0x4, ErrorToWindow = 0x8 }; + // args are passed as command line arguments // extra args via a tempfile and the option -x "temp-filename" PerforceResponse runP4Cmd(const QStringList &args, const QStringList &extraArgs = QStringList(), - bool showStdOutInOutputWindow = false, - bool showStdErrInOutputWindow = true, + unsigned logFlags = CommandToWindow|StdErrToWindow|ErrorToWindow, QTextCodec *outputCodec = 0) const; void openFiles(const QStringList &files); diff --git a/src/plugins/projectexplorer/projectwizardpage.ui b/src/plugins/projectexplorer/projectwizardpage.ui index bc31f8c49e14461349c331e8397241300803197a..7c21ec5a91099229862a773163eec8784be9e8bf 100644 --- a/src/plugins/projectexplorer/projectwizardpage.ui +++ b/src/plugins/projectexplorer/projectwizardpage.ui @@ -104,8 +104,9 @@ <widget class="QLabel" name="filesLabel"> <property name="text"> <string>The following files will be added: -f1 -f2 + + + </string> </property> <property name="textInteractionFlags"> diff --git a/src/plugins/qt4projectmanager/wizards/consoleappwizarddialog.cpp b/src/plugins/qt4projectmanager/wizards/consoleappwizarddialog.cpp index 14965f50187675bf5c69cec9cc2ddc79032c16ff..1090673284f08a4d50278b104b826541e71c9208 100644 --- a/src/plugins/qt4projectmanager/wizards/consoleappwizarddialog.cpp +++ b/src/plugins/qt4projectmanager/wizards/consoleappwizarddialog.cpp @@ -35,6 +35,7 @@ #include "consoleappwizard.h" #include "modulespage.h" +#include <QtCore/QDebug> #include <utils/projectintropage.h> namespace Qt4ProjectManager { @@ -51,13 +52,11 @@ ConsoleAppWizardDialog::ConsoleAppWizardDialog(const QString &templateName, setWindowIcon(icon); setWindowTitle(templateName); Core::BaseFileWizard::setupWizard(this); - setOptions(QWizard::IndependentPages | QWizard::HaveNextButtonOnLastPage); m_introPage->setDescription(tr("This wizard generates a Qt4 console application " "project. The application derives from QCoreApplication and does not " "present a GUI. You can press 'Finish' at any point in time.")); - m_introPage->setFinalPage(true); addPage(m_introPage); m_modulesPage->setModuleSelected(QLatin1String("core")); diff --git a/src/plugins/qt4projectmanager/wizards/guiappwizarddialog.cpp b/src/plugins/qt4projectmanager/wizards/guiappwizarddialog.cpp index 7b1ba073d34e6203a1f2cb720d6dafac79c2faed..621a3b6ba92072de3d411f1713ac6515166102c6 100644 --- a/src/plugins/qt4projectmanager/wizards/guiappwizarddialog.cpp +++ b/src/plugins/qt4projectmanager/wizards/guiappwizarddialog.cpp @@ -63,7 +63,6 @@ GuiAppWizardDialog::GuiAppWizardDialog(const QString &templateName, setWindowIcon(icon); setWindowTitle(templateName); Core::BaseFileWizard::setupWizard(this); - setOptions(QWizard::IndependentPages); m_introPage->setDescription(tr("This wizard generates a Qt4 GUI application " "project. The application derives by default from QApplication " diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index df5fe4108081d78eb945061deb5e236cd5ce2b25..49d29b75c93e5f8fe030fb7e6d38de05808c8f8b 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -79,6 +79,7 @@ #include <QtGui/QToolBar> #include <QtGui/QToolTip> #include <QtGui/QInputDialog> +#include <QtGui/QMenu> using namespace TextEditor; using namespace TextEditor::Internal; @@ -487,10 +488,6 @@ ITextEditable *BaseTextEditor::editableInterface() const d->m_editable, SIGNAL(contentsChanged())); connect(this, SIGNAL(changed()), d->m_editable, SIGNAL(changed())); - connect(this, - SIGNAL(markRequested(TextEditor::ITextEditor *, int)), - d->m_editable, - SIGNAL(markRequested(TextEditor::ITextEditor *, int))); } return d->m_editable; } @@ -501,7 +498,8 @@ void BaseTextEditor::currentEditorChanged(Core::IEditor *editor) if (editor == d->m_editable) { if (d->m_document->hasDecodingError()) { Core::EditorManager::instance()->showEditorInfoBar(QLatin1String(Constants::SELECT_ENCODING), - tr("<b>Error:</b> Could not decode \"%1\" with \"%2\"-encoding. Editing not possible.").arg(displayName()).arg(QString::fromLatin1(d->m_document->codec()->name())), + tr("<b>Error:</b> Could not decode \"%1\" with \"%2\"-encoding. Editing not possible.") + .arg(displayName()).arg(QString::fromLatin1(d->m_document->codec()->name())), tr("Select Encoding"), this, SLOT(selectEncoding())); } @@ -531,7 +529,6 @@ void BaseTextEditor::selectEncoding() } } - void DocumentMarker::updateMark(ITextMark *mark) { TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(document->documentLayout()); @@ -598,8 +595,79 @@ void BaseTextEditor::slotSelectionChanged() viewport()->update(); if (!d->m_inBlockSelectionMode) d->m_blockSelectionExtraX = 0; + if (!d->m_selectBlockAnchor.isNull() && !textCursor().hasSelection()) + d->m_selectBlockAnchor = QTextCursor(); +} + +void BaseTextEditor::gotoBlockStart() +{ + QTextCursor cursor = textCursor(); + if (TextBlockUserData::findPreviousOpenParenthesis(&cursor, false)) + setTextCursor(cursor); +} + +void BaseTextEditor::gotoBlockEnd() +{ + QTextCursor cursor = textCursor(); + if (TextBlockUserData::findNextClosingParenthesis(&cursor, false)) + setTextCursor(cursor); +} + +void BaseTextEditor::gotoBlockStartWithSelection() +{ + QTextCursor cursor = textCursor(); + if (TextBlockUserData::findPreviousOpenParenthesis(&cursor, true)) + setTextCursor(cursor); +} + +void BaseTextEditor::gotoBlockEndWithSelection() +{ + QTextCursor cursor = textCursor(); + if (TextBlockUserData::findNextClosingParenthesis(&cursor, true)) + setTextCursor(cursor); } +void BaseTextEditor::selectBlockUp() +{ + QTextCursor cursor = textCursor(); + if (!cursor.hasSelection()) + d->m_selectBlockAnchor = cursor; + else + cursor.setPosition(cursor.selectionStart()); + + + if (!TextBlockUserData::findPreviousOpenParenthesis(&cursor, false)) + return; + if (!TextBlockUserData::findNextClosingParenthesis(&cursor, true)) + return; + setTextCursor(cursor); +} + +void BaseTextEditor::selectBlockDown() +{ + QTextCursor tc = textCursor(); + QTextCursor cursor = d->m_selectBlockAnchor; + + if (!tc.hasSelection() || cursor.isNull()) + return; + tc.setPosition(tc.selectionStart()); + + forever { + QTextCursor ahead = cursor; + if (!TextBlockUserData::findPreviousOpenParenthesis(&ahead, false)) + break; + if (ahead.position() <= tc.position()) + break; + cursor = ahead; + } + if ( cursor != d->m_selectBlockAnchor) + TextBlockUserData::findNextClosingParenthesis(&cursor, true); + + setTextCursor(cursor); +} + + + void BaseTextEditor::keyPressEvent(QKeyEvent *e) { @@ -633,6 +701,11 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) e->accept(); return; } + } else if (e == QKeySequence::Paste) { + if (!ro) { + d->removeBlockSelection(); + // continue + } } } @@ -693,6 +766,8 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) break; case Qt::Key_Home: if (!(e == QKeySequence::MoveToStartOfDocument) && !(e == QKeySequence::SelectStartOfDocument)) { + if ((e->modifiers() & (Qt::AltModifier | Qt::ShiftModifier)) == (Qt::AltModifier | Qt::ShiftModifier)) + d->m_lastEventWasBlockSelectionEvent = true; handleHomeKey(e->modifiers() & Qt::ShiftModifier); e->accept(); return; @@ -708,6 +783,7 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) return; } // fall through + case Qt::Key_End: case Qt::Key_Right: case Qt::Key_Left: #ifndef Q_OS_MAC @@ -795,6 +871,15 @@ skip_event: delete e; } +void BaseTextEditor::setTextCursor(const QTextCursor &cursor) +{ + // workaround for QTextControl bug + bool selectionChange = cursor.hasSelection() || textCursor().hasSelection(); + QPlainTextEdit::setTextCursor(cursor); + if (selectionChange) + slotSelectionChanged(); +} + void BaseTextEditor::gotoLine(int line, int column) { const int blockNumber = line - 1; @@ -2343,6 +2428,12 @@ void BaseTextEditor::extraAreaMouseEvent(QMouseEvent *e) } else { d->extraAreaToggleMarkBlockNumber = cursor.blockNumber(); } + } else if (e->button() == Qt::RightButton) { + QMenu * contextMenu = new QMenu(this); + emit d->m_editable->markContextMenuRequested(editableInterface(), cursor.blockNumber(), contextMenu); + if (!contextMenu->isEmpty()) + contextMenu->exec(e->globalPos()); + delete contextMenu; } } else if (d->extraAreaSelectionAnchorBlockNumber >= 0) { QTextCursor selection = cursor; @@ -2377,7 +2468,7 @@ void BaseTextEditor::extraAreaMouseEvent(QMouseEvent *e) d->extraAreaToggleMarkBlockNumber = -1; if (cursor.blockNumber() == n) { int line = n + 1; - emit markRequested(editableInterface(), line); + emit d->m_editable->markRequested(editableInterface(), line); } } } @@ -2386,6 +2477,9 @@ void BaseTextEditor::extraAreaMouseEvent(QMouseEvent *e) void BaseTextEditor::slotCursorPositionChanged() { QList<QTextEdit::ExtraSelection> extraSelections; + setExtraSelections(ParenthesesMatchingSelection, extraSelections); // clear + if (d->m_parenthesesMatchingEnabled) + d->m_parenthesesMatchingTimer->start(50); if (d->m_highlightCurrentLine) { QTextEdit::ExtraSelection sel; @@ -2396,11 +2490,7 @@ void BaseTextEditor::slotCursorPositionChanged() extraSelections.append(sel); } - if (d->m_parenthesesMatchingEnabled) - d->m_parenthesesMatchingTimer->start(50); - - d->m_extraSelections = extraSelections; - setExtraSelections(d->m_extraSelections + d->m_extraExtraSelections); + setExtraSelections(CurrentLineSelection, extraSelections); } QTextBlock TextBlockUserData::testCollapse(const QTextBlock& block) @@ -2908,6 +2998,61 @@ TextBlockUserData::MatchType TextBlockUserData::checkClosedParenthesis(QTextCurs } } + +bool TextBlockUserData::findPreviousOpenParenthesis(QTextCursor *cursor, bool select) +{ + QTextBlock block = cursor->block(); + int position = cursor->position(); + int ignore = 0; + while (block.isValid()) { + Parentheses parenList = TextEditDocumentLayout::parentheses(block); + if (!parenList.isEmpty()) { + for (int i = parenList.count()-1; i >= 0; --i) { + Parenthesis paren = parenList.at(i); + if (block == cursor->block() && position - block.position() <= paren.pos + 1) + continue; + if (paren.type == Parenthesis::Closed) { + ++ignore; + } else if (ignore > 0) { + --ignore; + } else { + cursor->setPosition(block.position() + paren.pos, select ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor); + return true; + } + } + } + block = block.previous(); + } + return false; +} + +bool TextBlockUserData::findNextClosingParenthesis(QTextCursor *cursor, bool select) +{ + QTextBlock block = cursor->block(); + int position = cursor->position(); + int ignore = 0; + while (block.isValid()) { + Parentheses parenList = TextEditDocumentLayout::parentheses(block); + if (!parenList.isEmpty()) { + for (int i = 0; i < parenList.count(); ++i) { + Parenthesis paren = parenList.at(i); + if (block == cursor->block() && position - block.position() >= paren.pos) + continue; + if (paren.type == Parenthesis::Opened) { + ++ignore; + } else if (ignore > 0) { + --ignore; + } else { + cursor->setPosition(block.position() + paren.pos+1, select ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor); + return true; + } + } + } + block = block.next(); + } + return false; +} + TextBlockUserData::MatchType TextBlockUserData::matchCursorBackward(QTextCursor *cursor) { cursor->clearSelection(); @@ -2987,7 +3132,7 @@ void BaseTextEditor::_q_matchParentheses() if (backwardMatchType == TextBlockUserData::NoMatch && forwardMatchType == TextBlockUserData::NoMatch) return; - QList<QTextEdit::ExtraSelection> extraSelections = d->m_extraSelections; + QList<QTextEdit::ExtraSelection> extraSelections; if (backwardMatch.hasSelection()) { QTextEdit::ExtraSelection sel; @@ -3040,8 +3185,7 @@ void BaseTextEditor::_q_matchParentheses() } extraSelections.append(sel); } - d->m_extraSelections = extraSelections; - setExtraSelections(d->m_extraSelections + d->m_extraExtraSelections); + setExtraSelections(ParenthesesMatchingSelection, extraSelections); } void BaseTextEditor::setActionHack(QObject *hack) @@ -3088,15 +3232,21 @@ void BaseTextEditor::deleteLine() cut(); } -void BaseTextEditor::setExtraExtraSelections(const QList<QTextEdit::ExtraSelection> &selections) +void BaseTextEditor::setExtraSelections(ExtraSelectionKind kind, const QList<QTextEdit::ExtraSelection> &selections) { - d->m_extraExtraSelections = selections; - setExtraSelections(d->m_extraSelections + d->m_extraExtraSelections); + if (selections.isEmpty() && d->m_extraSelections[kind].isEmpty()) + return; + d->m_extraSelections[kind] = selections; + + QList<QTextEdit::ExtraSelection> all; + for (int i = 0; i < NExtraSelectionKinds; ++i) + all += d->m_extraSelections[i]; + QPlainTextEdit::setExtraSelections(all); } -QList<QTextEdit::ExtraSelection> BaseTextEditor::extraExtraSelections() const +QList<QTextEdit::ExtraSelection> BaseTextEditor::extraSelections(ExtraSelectionKind kind) const { - return d->m_extraExtraSelections; + return d->m_extraSelections[kind]; } @@ -3152,13 +3302,16 @@ void BaseTextEditor::collapse() TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout()); Q_ASSERT(documentLayout); QTextBlock block = textCursor().block(); + qDebug() << "collapse at block" << block.blockNumber(); while (block.isValid()) { - if (TextBlockUserData::canCollapse(block)) { - if ((block.next().userState()) >> 8 == (textCursor().block().userState() >> 8)) + qDebug() << "test block" << block.blockNumber(); + if (TextBlockUserData::canCollapse(block) && block.next().isVisible()) { + if ((block.next().userState()) >> 8 <= (textCursor().block().userState() >> 8)) break; } block = block.previous(); } + qDebug() << "found" << block.blockNumber(); if (block.isValid()) { TextBlockUserData::doCollapse(block, false); d->moveCursorVisible(); @@ -3238,6 +3391,14 @@ void BaseTextEditor::cut() QPlainTextEdit::cut(); } +void BaseTextEditor::paste() +{ + if (d->m_inBlockSelectionMode) { + d->removeBlockSelection(); + } + QPlainTextEdit::paste(); +} + QMimeData *BaseTextEditor::createMimeDataFromSelection() const { if (d->m_inBlockSelectionMode) { diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h index ced22900030e6684800dc119bd290291987d4818..40454a9c7d430dc6b188567843a7e13323f98f88 100644 --- a/src/plugins/texteditor/basetexteditor.h +++ b/src/plugins/texteditor/basetexteditor.h @@ -169,6 +169,8 @@ public: static MatchType checkClosedParenthesis(QTextCursor *cursor, QChar c); static MatchType matchCursorBackward(QTextCursor *cursor); static MatchType matchCursorForward(QTextCursor *cursor); + static bool findPreviousOpenParenthesis(QTextCursor *cursor, bool select = false); + static bool findNextClosingParenthesis(QTextCursor *cursor, bool select = false); private: @@ -298,6 +300,8 @@ public: void setReadOnly(bool b); + void setTextCursor(const QTextCursor &cursor); + public slots: void setDisplayName(const QString &title); virtual void setFontSettings(const TextEditor::FontSettings &); @@ -305,6 +309,7 @@ public slots: virtual void unCommentSelection(); virtual void setStorageSettings(const TextEditor::StorageSettings &); + void paste(); void cut(); void zoomIn(int range = 1); @@ -316,6 +321,14 @@ public slots: void expand(); void selectEncoding(); + void gotoBlockStart(); + void gotoBlockEnd(); + void gotoBlockStartWithSelection(); + void gotoBlockEndWithSelection(); + + void selectBlockUp(); + void selectBlockDown(); + signals: void changed(); @@ -356,7 +369,6 @@ private: Internal::BaseTextEditorPrivate *d; friend class Internal::BaseTextEditorPrivate; - public: QWidget *extraArea() const; virtual int extraAreaWidth(int *markWidthPtr = 0) const; @@ -372,8 +384,16 @@ public: void ensureCursorVisible(); - void setExtraExtraSelections(const QList<QTextEdit::ExtraSelection> &selections); - QList<QTextEdit::ExtraSelection> extraExtraSelections() const; + enum ExtraSelectionKind { + CurrentLineSelection, + ParenthesesMatchingSelection, + CodeWarningsSelection, + CodeSemanticsSelection, + OtherSelection, + NExtraSelectionKinds + }; + void setExtraSelections(ExtraSelectionKind kind, const QList<QTextEdit::ExtraSelection> &selections); + QList<QTextEdit::ExtraSelection> extraSelections(ExtraSelectionKind kind) const; struct BlockRange { BlockRange():first(0), last(-1){} @@ -418,7 +438,6 @@ protected slots: signals: - void markRequested(TextEditor::ITextEditor *editor, int line); void requestBlockUpdate(const QTextBlock &); void requestAutoCompletion(ITextEditable *editor, bool forced); diff --git a/src/plugins/texteditor/basetexteditor_p.h b/src/plugins/texteditor/basetexteditor_p.h index 87d1af0de0f078b7a7d3edbceea8a5405ad0d1e7..9f1e5a7eb67b633e56e67268da701357f64327f0 100644 --- a/src/plugins/texteditor/basetexteditor_p.h +++ b/src/plugins/texteditor/basetexteditor_p.h @@ -204,8 +204,7 @@ public: QObject *m_actionHack; - QList<QTextEdit::ExtraSelection> m_extraSelections; - QList<QTextEdit::ExtraSelection> m_extraExtraSelections; + QList<QTextEdit::ExtraSelection> m_extraSelections[BaseTextEditor::NExtraSelectionKinds]; // block selection mode bool m_inBlockSelectionMode; @@ -216,6 +215,7 @@ public: void removeBlockSelection(const QString &text = QString()); QTextCursor m_findScope; + QTextCursor m_selectBlockAnchor; void moveCursorVisible(); }; diff --git a/src/plugins/texteditor/itexteditor.h b/src/plugins/texteditor/itexteditor.h index 432c3c9c5850b34ea8a38b93498979c84f8151a4..514f311472a8a362b6ec08a09b397dab18a10857 100644 --- a/src/plugins/texteditor/itexteditor.h +++ b/src/plugins/texteditor/itexteditor.h @@ -44,6 +44,7 @@ #include <QtGui/QIcon> QT_BEGIN_NAMESPACE +class QMenu; class QTextBlock; QT_END_NAMESPACE @@ -124,6 +125,7 @@ public: signals: void contentsChanged(); void markRequested(TextEditor::ITextEditor *editor, int line); + void markContextMenuRequested(TextEditor::ITextEditor *editor, int line, QMenu *menu); void tooltipRequested(TextEditor::ITextEditor *editor, const QPoint &globalPos, int position); void contextHelpIdRequested(TextEditor::ITextEditor *editor, int position); }; diff --git a/src/plugins/texteditor/texteditoractionhandler.cpp b/src/plugins/texteditor/texteditoractionhandler.cpp index 94cdca6cfda4110a6c349808a47e8df98ee27a0b..635f96545769d0e36a03dadf3de5a3544d2882b8 100644 --- a/src/plugins/texteditor/texteditoractionhandler.cpp +++ b/src/plugins/texteditor/texteditoractionhandler.cpp @@ -67,6 +67,9 @@ TextEditorActionHandler::TextEditorActionHandler(Core::ICore *core, = m_collapseAction = m_expandAction = m_deleteLineAction = m_selectEncodingAction = m_increaseFontSizeAction = m_decreaseFontSizeAction + = m_gotoBlockStartAction = m_gotoBlockStartWithSelectionAction + = m_gotoBlockEndAction = m_gotoBlockEndWithSelectionAction + = m_selectBlockUpAction = m_selectBlockDownAction = 0; m_contextId << m_core->uniqueIDManager()->uniqueIdentifier(context); @@ -161,13 +164,11 @@ void TextEditorActionHandler::createActions() command = am->registerAction(m_collapseAction, Constants::COLLAPSE, m_contextId); command->setDefaultKeySequence(QKeySequence(tr("Ctrl+<"))); connect(m_collapseAction, SIGNAL(triggered()), this, SLOT(collapse())); - advancedMenu->addAction(command); m_expandAction = new QAction(tr("Expand"), this); command = am->registerAction(m_expandAction, Constants::EXPAND, m_contextId); command->setDefaultKeySequence(QKeySequence(tr("Ctrl+>"))); connect(m_expandAction, SIGNAL(triggered()), this, SLOT(expand())); - advancedMenu->addAction(command); m_unCollapseAllAction = new QAction(tr("(Un)&Collapse All"), this); command = am->registerAction(m_unCollapseAllAction, Constants::UN_COLLAPSE_ALL, m_contextId); @@ -185,6 +186,36 @@ void TextEditorActionHandler::createActions() command->setDefaultKeySequence(QKeySequence(tr("Ctrl+-"))); connect(m_decreaseFontSizeAction, SIGNAL(triggered()), this, SLOT(decreaseFontSize())); advancedMenu->addAction(command); + + m_gotoBlockStartAction = new QAction(tr("Goto Block Start"), this); + command = am->registerAction(m_gotoBlockStartAction, Constants::GOTO_BLOCK_START, m_contextId); + command->setDefaultKeySequence(QKeySequence(tr("Ctrl+["))); + connect(m_gotoBlockStartAction, SIGNAL(triggered()), this, SLOT(gotoBlockStart())); + + m_gotoBlockEndAction = new QAction(tr("Goto Block End"), this); + command = am->registerAction(m_gotoBlockEndAction, Constants::GOTO_BLOCK_END, m_contextId); + command->setDefaultKeySequence(QKeySequence(tr("Ctrl+]"))); + connect(m_gotoBlockEndAction, SIGNAL(triggered()), this, SLOT(gotoBlockEnd())); + + m_gotoBlockStartWithSelectionAction = new QAction(tr("Goto Block Start With Selection"), this); + command = am->registerAction(m_gotoBlockStartWithSelectionAction, Constants::GOTO_BLOCK_START_WITH_SELECTION, m_contextId); + command->setDefaultKeySequence(QKeySequence(tr("Ctrl+{"))); + connect(m_gotoBlockStartWithSelectionAction, SIGNAL(triggered()), this, SLOT(gotoBlockStartWithSelection())); + + m_gotoBlockEndWithSelectionAction = new QAction(tr("Goto Block End With Selection"), this); + command = am->registerAction(m_gotoBlockEndWithSelectionAction, Constants::GOTO_BLOCK_END_WITH_SELECTION, m_contextId); + command->setDefaultKeySequence(QKeySequence(tr("Ctrl+}"))); + connect(m_gotoBlockEndWithSelectionAction, SIGNAL(triggered()), this, SLOT(gotoBlockEndWithSelection())); + + m_selectBlockUpAction= new QAction(tr("Select Block Up"), this); + command = am->registerAction(m_selectBlockUpAction, Constants::SELECT_BLOCK_UP, m_contextId); + command->setDefaultKeySequence(QKeySequence(tr("Ctrl+U"))); + connect(m_selectBlockUpAction, SIGNAL(triggered()), this, SLOT(selectBlockUp())); + + m_selectBlockDownAction= new QAction(tr("Select Block Down"), this); + command = am->registerAction(m_selectBlockDownAction, Constants::SELECT_BLOCK_DOWN, m_contextId); + command->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+U"))); + connect(m_selectBlockDownAction, SIGNAL(triggered()), this, SLOT(selectBlockDown())); } bool TextEditorActionHandler::supportsAction(const QString & /*id */) const @@ -229,35 +260,30 @@ void TextEditorActionHandler::updateActions() void TextEditorActionHandler::updateActions(UpdateMode um) { - if (m_pasteAction) - m_pasteAction->setEnabled(um != NoEditor); - if (m_selectAllAction) - m_selectAllAction->setEnabled(um != NoEditor); - if (m_gotoAction) - m_gotoAction->setEnabled(um != NoEditor); - if (m_selectEncodingAction) - m_selectEncodingAction->setEnabled(um != NoEditor); - if (m_printAction) - m_printAction->setEnabled(um != NoEditor); - if (m_formatAction) - m_formatAction->setEnabled((m_optionalActions & Format) && um != NoEditor); - if (m_unCommentSelectionAction) - m_unCommentSelectionAction->setEnabled((m_optionalActions & UnCommentSelection) && um != NoEditor); - if (m_collapseAction) - m_collapseAction->setEnabled(um != NoEditor); - if (m_expandAction) - m_expandAction->setEnabled(um != NoEditor); - if (m_unCollapseAllAction) - m_unCollapseAllAction->setEnabled((m_optionalActions & UnCollapseAll) && um != NoEditor); - if (m_decreaseFontSizeAction) - m_decreaseFontSizeAction->setEnabled(um != NoEditor); - if (m_increaseFontSizeAction) - m_increaseFontSizeAction->setEnabled(um != NoEditor); - if (m_visualizeWhitespaceAction) { - m_visualizeWhitespaceAction->setEnabled(um != NoEditor); - if (m_currentEditor) - m_visualizeWhitespaceAction->setChecked(m_currentEditor->displaySettings().m_visualizeWhitespace); - } + if (!m_initialized) + return; + m_pasteAction->setEnabled(um != NoEditor); + m_selectAllAction->setEnabled(um != NoEditor); + m_gotoAction->setEnabled(um != NoEditor); + m_selectEncodingAction->setEnabled(um != NoEditor); + m_printAction->setEnabled(um != NoEditor); + m_formatAction->setEnabled((m_optionalActions & Format) && um != NoEditor); + m_unCommentSelectionAction->setEnabled((m_optionalActions & UnCommentSelection) && um != NoEditor); + m_collapseAction->setEnabled(um != NoEditor); + m_expandAction->setEnabled(um != NoEditor); + m_unCollapseAllAction->setEnabled((m_optionalActions & UnCollapseAll) && um != NoEditor); + m_decreaseFontSizeAction->setEnabled(um != NoEditor); + m_increaseFontSizeAction->setEnabled(um != NoEditor); + m_gotoBlockStartAction->setEnabled(um != NoEditor); + m_gotoBlockStartWithSelectionAction->setEnabled(um != NoEditor); + m_gotoBlockEndAction->setEnabled(um != NoEditor); + m_gotoBlockEndWithSelectionAction->setEnabled(um != NoEditor); + m_selectBlockUpAction->setEnabled(um != NoEditor); + m_selectBlockDownAction->setEnabled(um != NoEditor); + + m_visualizeWhitespaceAction->setEnabled(um != NoEditor); + if (m_currentEditor) + m_visualizeWhitespaceAction->setChecked(m_currentEditor->displaySettings().m_visualizeWhitespace); if (m_textWrappingAction) { m_textWrappingAction->setEnabled(um != NoEditor); if (m_currentEditor) @@ -365,54 +391,31 @@ void TextEditorActionHandler::setTextWrapping(bool checked) } } -void TextEditorActionHandler::unCommentSelection() -{ - if (m_currentEditor) - m_currentEditor->unCommentSelection(); -} - -void TextEditorActionHandler::deleteLine() -{ - if (m_currentEditor) - m_currentEditor->deleteLine(); -} - -void TextEditorActionHandler::unCollapseAll() -{ - if (m_currentEditor) - m_currentEditor->unCollapseAll(); -} - -void TextEditorActionHandler::collapse() -{ - if (m_currentEditor) - m_currentEditor->collapse(); -} - -void TextEditorActionHandler::expand() -{ - if (m_currentEditor) - m_currentEditor->expand(); -} - -void TextEditorActionHandler::selectEncoding() -{ - if (m_currentEditor) - m_currentEditor->selectEncoding(); -} - -void TextEditorActionHandler::increaseFontSize() -{ - if (m_currentEditor) - m_currentEditor->zoomIn(); -} - -void TextEditorActionHandler::decreaseFontSize() -{ - if (m_currentEditor) - m_currentEditor->zoomOut(); -} - +#define FUNCTION(funcname) void TextEditorActionHandler::funcname ()\ +{\ + if (m_currentEditor)\ + m_currentEditor->funcname ();\ +} +#define FUNCTION2(funcname, funcname2) void TextEditorActionHandler::funcname ()\ +{\ + if (m_currentEditor)\ + m_currentEditor->funcname2 ();\ +} + +FUNCTION(unCommentSelection) +FUNCTION(deleteLine) +FUNCTION(unCollapseAll) +FUNCTION(collapse) +FUNCTION(expand) +FUNCTION2(increaseFontSize, zoomIn) +FUNCTION2(decreaseFontSize, zoomOut) +FUNCTION(selectEncoding) +FUNCTION(gotoBlockStart) +FUNCTION(gotoBlockEnd) +FUNCTION(gotoBlockStartWithSelection) +FUNCTION(gotoBlockEndWithSelection) +FUNCTION(selectBlockUp) +FUNCTION(selectBlockDown) void TextEditorActionHandler::updateCurrentEditor(Core::IContext *object) { diff --git a/src/plugins/texteditor/texteditoractionhandler.h b/src/plugins/texteditor/texteditoractionhandler.h index 79ac67c21781ab68085e5d3afc75b6765da2a6e3..9a8c7b9f57c89ceb4a6bd1e1971b1c06bce7ed61 100644 --- a/src/plugins/texteditor/texteditoractionhandler.h +++ b/src/plugins/texteditor/texteditoractionhandler.h @@ -109,6 +109,12 @@ private slots: void selectEncoding(); void increaseFontSize(); void decreaseFontSize(); + void gotoBlockStart(); + void gotoBlockEnd(); + void gotoBlockStartWithSelection(); + void gotoBlockEndWithSelection(); + void selectBlockUp(); + void selectBlockDown(); void updateCurrentEditor(Core::IContext *object); private: @@ -131,6 +137,12 @@ private: QAction *m_selectEncodingAction; QAction *m_increaseFontSizeAction; QAction *m_decreaseFontSizeAction; + QAction *m_gotoBlockStartAction; + QAction *m_gotoBlockEndAction; + QAction *m_gotoBlockStartWithSelectionAction; + QAction *m_gotoBlockEndWithSelectionAction; + QAction *m_selectBlockUpAction; + QAction *m_selectBlockDownAction; uint m_optionalActions; QPointer<BaseTextEditor> m_currentEditor; diff --git a/src/plugins/texteditor/texteditorconstants.h b/src/plugins/texteditor/texteditorconstants.h index 8313f61fc3dc870980a1ce1e69a30972f45a7e66..9ac9fdff0e4c368ecb3d43f6ad13da8f86f7660d 100644 --- a/src/plugins/texteditor/texteditorconstants.h +++ b/src/plugins/texteditor/texteditorconstants.h @@ -48,9 +48,17 @@ const char * const UN_COLLAPSE_ALL = "TextEditor.UnCollapseAll"; const char * const AUTO_INDENT_SELECTION = "TextEditor.AutoIndentSelection"; const char * const INCREASE_FONT_SIZE = "TextEditor.IncreaseFontSize"; const char * const DECREASE_FONT_SIZE = "TextEditor.DecreaseFontSize"; +const char * const GOTO_BLOCK_START = "TextEditor.GotoBlockStart"; +const char * const GOTO_BLOCK_START_WITH_SELECTION = "TextEditor.GotoBlockStartWithSelection"; +const char * const GOTO_BLOCK_END = "TextEditor.GotoBlockEnd"; +const char * const GOTO_BLOCK_END_WITH_SELECTION = "TextEditor.GotoBlockEndWithSelection"; +const char * const SELECT_BLOCK_UP = "TextEditor.SelectBlockUp"; +const char * const SELECT_BLOCK_DOWN = "TextEditor.SelectBlockDown"; const char * const DELETE_LINE = "TextEditor.DeleteLine"; const char * const DELETE_WORD = "TextEditor.DeleteWord"; const char * const SELECT_ENCODING = "TextEditor.SelectEncoding"; +const char * const GOTO_OPENING_PARENTHESIS = "TextEditor.GotoOpeningParenthesis"; +const char * const GOTO_CLOSING_PARENTHESIS = "TextEditor.GotoOpeningParenthesis"; const char * const C_TEXTEDITOR_MIMETYPE_TEXT = "text/plain"; const char * const C_TEXTEDITOR_MIMETYPE_XML = "application/xml"; diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index dcfe55d195b82650428ce434fef6ab836aee909b..eb65457c1090bacf713cae9b51b5eaf598b8f5fa 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -225,23 +225,12 @@ void VCSBaseEditor::mouseMoveEvent(QMouseEvent *e) sel.format.setFontUnderline(true); change = changeUnderCursor(cursor); sel.format.setProperty(QTextFormat::UserProperty, change); - bool found = false; - foreach (QTextEdit::ExtraSelection es, extraSelections()) { - if (es.format.stringProperty(QTextFormat::UserProperty) == sel.format.stringProperty(QTextFormat::UserProperty)) { - found = true; - break; - } - } - if (!found) { - setExtraSelections(QList<QTextEdit::ExtraSelection>() << sel); - viewport()->setCursor(Qt::PointingHandCursor); - } - } else { - if (!extraSelections().isEmpty()) { - setExtraSelections(QList<QTextEdit::ExtraSelection>()); - viewport()->setCursor(Qt::IBeamCursor); - } + setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>() << sel); + viewport()->setCursor(Qt::PointingHandCursor); } + } else { + setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>()); + viewport()->setCursor(Qt::IBeamCursor); } TextEditor::BaseTextEditor::mouseMoveEvent(e); }