OSDN Git Service

Merge remote branch 'origin/2.0'
authorcon <qtc-committer@nokia.com>
Fri, 21 May 2010 14:04:27 +0000 (16:04 +0200)
committercon <qtc-committer@nokia.com>
Fri, 21 May 2010 14:04:27 +0000 (16:04 +0200)
Conflicts:
doc/qtcreator.qdoc
src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.h

385 files changed:
.gitignore
README
doc/qt-html-templates.qdocconf
doc/qtcreator.qdoc
doc/qtcreator.qdocconf
share/qtcreator/gdbmacros/dumper.py
share/qtcreator/gdbmacros/gdbmacros.py
share/qtcreator/gdbmacros/pdumper.py
share/qtcreator/generic-highlighter/README [new file with mode: 0644]
share/qtcreator/static.pro
share/qtcreator/templates/wizards/qtcreatorplugin/MyPlugin.pluginspec [new file with mode: 0644]
share/qtcreator/templates/wizards/qtcreatorplugin/myplugin.cpp [new file with mode: 0644]
share/qtcreator/templates/wizards/qtcreatorplugin/myplugin.h [new file with mode: 0644]
share/qtcreator/templates/wizards/qtcreatorplugin/myplugin.pro [new file with mode: 0644]
share/qtcreator/templates/wizards/qtcreatorplugin/myplugin_global.h [new file with mode: 0644]
share/qtcreator/templates/wizards/qtcreatorplugin/qtcreator_logo_24.png [new file with mode: 0644]
share/qtcreator/templates/wizards/qtcreatorplugin/wizard.xml [new file with mode: 0644]
src/app/Info.plist
src/libs/3rdparty/net7ssh/src/ne7ssh.cpp
src/libs/3rdparty/net7ssh/src/ne7ssh.h
src/libs/3rdparty/net7ssh/src/ne7ssh_connection.cpp
src/libs/3rdparty/net7ssh/src/ne7ssh_connection.h
src/libs/cplusplus/CheckUndefinedSymbols.cpp
src/libs/cplusplus/CheckUndefinedSymbols.h
src/libs/cplusplus/CppDocument.cpp
src/libs/cplusplus/CppDocument.h
src/libs/cplusplus/DeprecatedGenTemplateInstance.cpp [moved from src/libs/cplusplus/GenTemplateInstance.cpp with 84% similarity]
src/libs/cplusplus/DeprecatedGenTemplateInstance.h [moved from src/libs/cplusplus/GenTemplateInstance.h with 75% similarity]
src/libs/cplusplus/DeprecatedLookupContext.cpp [new file with mode: 0644]
src/libs/cplusplus/DeprecatedLookupContext.h [new file with mode: 0644]
src/libs/cplusplus/FindUsages.cpp
src/libs/cplusplus/FindUsages.h
src/libs/cplusplus/LookupContext.cpp
src/libs/cplusplus/LookupContext.h
src/libs/cplusplus/LookupItem.cpp [new file with mode: 0644]
src/libs/cplusplus/LookupItem.h [new file with mode: 0644]
src/libs/cplusplus/ResolveExpression.cpp
src/libs/cplusplus/ResolveExpression.h
src/libs/cplusplus/TypeOfExpression.cpp
src/libs/cplusplus/TypeOfExpression.h
src/libs/cplusplus/cplusplus-lib.pri
src/libs/utils/checkablemessagebox.h
src/libs/utils/checkablemessagebox.ui
src/libs/utils/uncommentselection.cpp
src/libs/utils/uncommentselection.h
src/plugins/bineditor/BinEditor.pluginspec
src/plugins/bineditor/bineditor.cpp
src/plugins/bineditor/bineditorplugin.cpp
src/plugins/bineditor/imageviewer.cpp
src/plugins/bineditor/imageviewer.h
src/plugins/bookmarks/Bookmarks.pluginspec
src/plugins/cmakeprojectmanager/CMakeProjectManager.pluginspec
src/plugins/cmakeprojectmanager/cmakeproject.cpp
src/plugins/cmakeprojectmanager/cmakeproject.h
src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp
src/plugins/cmakeprojectmanager/cmakeprojectnodes.h
src/plugins/coreplugin/Core.pluginspec
src/plugins/coreplugin/coreconstants.h
src/plugins/coreplugin/editormanager/editorview.cpp
src/plugins/coreplugin/filemanager.cpp
src/plugins/coreplugin/filemanager.h
src/plugins/coreplugin/ifile.h
src/plugins/coreplugin/iversioncontrol.h
src/plugins/coreplugin/ssh/sshconnection.cpp
src/plugins/coreplugin/ssh/sshconnection.h
src/plugins/coreplugin/vcsmanager.cpp
src/plugins/cpaster/CodePaster.pluginspec
src/plugins/cppeditor/CppEditor.pluginspec
src/plugins/cppeditor/cppeditor.cpp
src/plugins/cppeditor/cppeditor.h
src/plugins/cppeditor/cpphighlighter.cpp
src/plugins/cppeditor/cpphoverhandler.cpp
src/plugins/cppeditor/cppquickfix.cpp
src/plugins/cppeditor/cppquickfix.h
src/plugins/cpptools/CppTools.pluginspec
src/plugins/cpptools/abstracteditorsupport.cpp
src/plugins/cpptools/cppcodecompletion.cpp
src/plugins/cpptools/cppcodecompletion.h
src/plugins/cpptools/cppmodelmanager.cpp
src/plugins/cpptools/cppmodelmanager.h
src/plugins/cvs/CVS.pluginspec
src/plugins/cvs/cvscontrol.cpp
src/plugins/cvs/cvscontrol.h
src/plugins/cvs/cvsplugin.cpp
src/plugins/cvs/cvsplugin.h
src/plugins/debugger/Debugger.pluginspec
src/plugins/debugger/attachtcfdialog.ui [new file with mode: 0644]
src/plugins/debugger/breakcondition.ui
src/plugins/debugger/breakhandler.cpp
src/plugins/debugger/breakhandler.h
src/plugins/debugger/breakpoint.h [new file with mode: 0644]
src/plugins/debugger/breakwindow.cpp
src/plugins/debugger/breakwindow.h
src/plugins/debugger/cdb/breakpoint.cpp
src/plugins/debugger/cdb/breakpoint.h
src/plugins/debugger/cdb/cdbbreakpoint.cpp
src/plugins/debugger/cdb/cdbbreakpoint.h
src/plugins/debugger/cdb/cdbdebugengine.cpp
src/plugins/debugger/cdb/cdbdebugengine.h
src/plugins/debugger/cdb/cdboptions.cpp
src/plugins/debugger/cdb/cdboptions.h
src/plugins/debugger/cdb/cdbstacktracecontext.cpp
src/plugins/debugger/cdb/cdbsymbolpathlisteditor.cpp
src/plugins/debugger/cdb/cdbsymbolpathlisteditor.h
src/plugins/debugger/cdb/coreengine.cpp
src/plugins/debugger/cdb/coreengine.h
src/plugins/debugger/debugger.pro
src/plugins/debugger/debugger.qrc
src/plugins/debugger/debuggerconstants.h
src/plugins/debugger/debuggerdialogs.cpp
src/plugins/debugger/debuggerdialogs.h
src/plugins/debugger/debuggermanager.cpp
src/plugins/debugger/debuggermanager.h
src/plugins/debugger/debuggerplugin.cpp
src/plugins/debugger/debuggerplugin.h
src/plugins/debugger/debuggerrunner.cpp
src/plugins/debugger/gdb/abstractgdbadapter.cpp
src/plugins/debugger/gdb/abstractgdbadapter.h
src/plugins/debugger/gdb/abstractgdbprocess.cpp [new file with mode: 0644]
src/plugins/debugger/gdb/abstractgdbprocess.h [new file with mode: 0644]
src/plugins/debugger/gdb/abstractplaingdbadapter.cpp [moved from src/plugins/debugger/gdb/plaingdbadapter.cpp with 54% similarity]
src/plugins/debugger/gdb/abstractplaingdbadapter.h [new file with mode: 0644]
src/plugins/debugger/gdb/attachgdbadapter.h
src/plugins/debugger/gdb/classicgdbengine.cpp
src/plugins/debugger/gdb/coregdbadapter.h
src/plugins/debugger/gdb/gdb.pri
src/plugins/debugger/gdb/gdbengine.cpp
src/plugins/debugger/gdb/gdbengine.h
src/plugins/debugger/gdb/localgdbprocess.cpp [new file with mode: 0644]
src/plugins/debugger/gdb/localgdbprocess.h [new file with mode: 0644]
src/plugins/debugger/gdb/localplaingdbadapter.cpp [new file with mode: 0644]
src/plugins/debugger/gdb/localplaingdbadapter.h [moved from src/plugins/debugger/gdb/plaingdbadapter.h with 77% similarity]
src/plugins/debugger/gdb/pythongdbengine.cpp
src/plugins/debugger/gdb/remotegdbprocess.cpp [new file with mode: 0644]
src/plugins/debugger/gdb/remotegdbprocess.h [new file with mode: 0644]
src/plugins/debugger/gdb/remotegdbserveradapter.cpp [moved from src/plugins/debugger/gdb/remotegdbadapter.cpp with 89% similarity]
src/plugins/debugger/gdb/remotegdbserveradapter.h [moved from src/plugins/debugger/gdb/remotegdbadapter.h with 89% similarity]
src/plugins/debugger/gdb/remoteplaingdbadapter.cpp [new file with mode: 0644]
src/plugins/debugger/gdb/remoteplaingdbadapter.h [new file with mode: 0644]
src/plugins/debugger/gdb/termgdbadapter.cpp
src/plugins/debugger/gdb/termgdbadapter.h
src/plugins/debugger/gdb/trkgdbadapter.cpp
src/plugins/debugger/gdb/trkgdbadapter.h
src/plugins/debugger/idebuggerengine.h
src/plugins/debugger/images/watchpoint.png [new file with mode: 0644]
src/plugins/debugger/moduleshandler.cpp
src/plugins/debugger/moduleshandler.h
src/plugins/debugger/moduleswindow.cpp
src/plugins/debugger/pdb/pdbengine.cpp
src/plugins/debugger/pdb/pdbengine.h
src/plugins/debugger/script/scriptengine.cpp
src/plugins/debugger/script/scriptengine.h
src/plugins/debugger/stackframe.cpp [new file with mode: 0644]
src/plugins/debugger/stackhandler.cpp
src/plugins/debugger/stackhandler.h
src/plugins/debugger/startexternaldialog.ui
src/plugins/debugger/tcf/json.cpp [new file with mode: 0644]
src/plugins/debugger/tcf/json.h [new file with mode: 0644]
src/plugins/debugger/tcf/tcf.pri [new file with mode: 0644]
src/plugins/debugger/tcf/tcfengine.cpp [new file with mode: 0644]
src/plugins/debugger/tcf/tcfengine.h [new file with mode: 0644]
src/plugins/debugger/threadshandler.cpp [new file with mode: 0644]
src/plugins/debugger/threadshandler.h [new file with mode: 0644]
src/plugins/debugger/watchhandler.cpp
src/plugins/debugger/watchhandler.h
src/plugins/debugger/watchutils.cpp
src/plugins/debugger/watchwindow.cpp
src/plugins/debugger/watchwindow.h
src/plugins/designer/Designer.pluginspec
src/plugins/designer/formwindoweditor.cpp
src/plugins/designer/formwindowfile.cpp
src/plugins/designer/formwindowfile.h
src/plugins/designer/qtcreatorintegration.cpp
src/plugins/fakevim/FakeVim.pluginspec
src/plugins/fakevim/fakevimactions.cpp
src/plugins/fakevim/fakevimactions.h
src/plugins/fakevim/fakevimhandler.cpp
src/plugins/fakevim/fakevimhandler.h
src/plugins/fakevim/fakevimoptions.ui
src/plugins/fakevim/fakevimplugin.cpp
src/plugins/find/Find.pluginspec
src/plugins/find/currentdocumentfind.cpp
src/plugins/genericprojectmanager/GenericProjectManager.pluginspec
src/plugins/genericprojectmanager/genericproject.cpp
src/plugins/genericprojectmanager/genericproject.h
src/plugins/genericprojectmanager/genericprojectnodes.cpp
src/plugins/genericprojectmanager/genericprojectnodes.h
src/plugins/git/ScmGit.pluginspec
src/plugins/git/gitclient.cpp
src/plugins/git/gitclient.h
src/plugins/git/gitversioncontrol.cpp
src/plugins/git/gitversioncontrol.h
src/plugins/helloworld/HelloWorld.pluginspec
src/plugins/help/Help.pluginspec
src/plugins/locator/Locator.pluginspec
src/plugins/mercurial/Mercurial.pluginspec
src/plugins/mercurial/mercurialclient.cpp
src/plugins/mercurial/mercurialclient.h
src/plugins/mercurial/mercurialcontrol.cpp
src/plugins/mercurial/mercurialcontrol.h
src/plugins/perforce/Perforce.pluginspec
src/plugins/perforce/perforceplugin.cpp
src/plugins/perforce/perforceplugin.h
src/plugins/perforce/perforceversioncontrol.cpp
src/plugins/perforce/perforceversioncontrol.h
src/plugins/projectexplorer/ProjectExplorer.pluginspec
src/plugins/projectexplorer/applicationlauncher_win.cpp
src/plugins/projectexplorer/applicationlauncher_x11.cpp
src/plugins/projectexplorer/applicationrunconfiguration.cpp
src/plugins/projectexplorer/applicationrunconfiguration.h
src/plugins/projectexplorer/buildconfigurationmodel.cpp [new file with mode: 0644]
src/plugins/projectexplorer/buildconfigurationmodel.h [new file with mode: 0644]
src/plugins/projectexplorer/buildsettingspropertiespage.cpp
src/plugins/projectexplorer/buildsettingspropertiespage.h
src/plugins/projectexplorer/customwizard/customwizardpage.cpp
src/plugins/projectexplorer/customwizard/customwizardpage.h
src/plugins/projectexplorer/environment.cpp
src/plugins/projectexplorer/miniprojecttargetselector.cpp
src/plugins/projectexplorer/miniprojecttargetselector.h
src/plugins/projectexplorer/outputwindow.cpp
src/plugins/projectexplorer/outputwindow.h
src/plugins/projectexplorer/pluginfilefactory.cpp
src/plugins/projectexplorer/projectexplorer.cpp
src/plugins/projectexplorer/projectexplorer.h
src/plugins/projectexplorer/projectexplorer.pro
src/plugins/projectexplorer/projectfilewizardextension.cpp
src/plugins/projectexplorer/projectmodels.cpp
src/plugins/projectexplorer/projectmodels.h
src/plugins/projectexplorer/projectnodes.cpp
src/plugins/projectexplorer/projectnodes.h
src/plugins/projectexplorer/runconfiguration.cpp
src/plugins/projectexplorer/runconfiguration.h
src/plugins/projectexplorer/runconfigurationmodel.cpp [new file with mode: 0644]
src/plugins/projectexplorer/runconfigurationmodel.h [new file with mode: 0644]
src/plugins/projectexplorer/runsettingspropertiespage.cpp
src/plugins/projectexplorer/runsettingspropertiespage.h
src/plugins/projectexplorer/session.cpp
src/plugins/projectexplorer/session.h
src/plugins/projectexplorer/userfileaccessor.cpp
src/plugins/qmldesigner/QmlDesigner.pluginspec
src/plugins/qmldesigner/designercore/include/bindingproperty.h
src/plugins/qmldesigner/designercore/include/enumeratormetainfo.h
src/plugins/qmldesigner/designercore/include/qmlobjectnode.h
src/plugins/qmldesigner/designercore/include/qmlstate.h
src/plugins/qmldesigner/designercore/metainfo/enumeratormetainfo.cpp
src/plugins/qmldesigner/designercore/metainfo/gui.metainfo
src/plugins/qmldesigner/designercore/metainfo/metainfo.cpp
src/plugins/qmldesigner/designercore/model/abstractproperty.cpp
src/plugins/qmldesigner/designercore/model/bindingproperty.cpp
src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp
src/plugins/qmldesigner/designercore/model/qmlstate.cpp
src/plugins/qmldesigner/designercore/model/variantparser.cpp
src/plugins/qmlinspector/QmlInspector.pluginspec
src/plugins/qmlinspector/components/inspectortreeitems.cpp
src/plugins/qmlinspector/components/inspectortreeitems.h
src/plugins/qmlinspector/components/objectpropertiesview.cpp
src/plugins/qmlinspector/components/objectpropertiesview.h
src/plugins/qmljseditor/QmlJSEditor.pluginspec
src/plugins/qmljseditor/qmljshighlighter.cpp
src/plugins/qmljseditor/qmljshighlighter.h
src/plugins/qmlprojectmanager/QmlProjectManager.pluginspec
src/plugins/qmlprojectmanager/qmlprojectfile.cpp
src/plugins/qmlprojectmanager/qmlprojectfile.h
src/plugins/qmlprojectmanager/qmlprojectnodes.cpp
src/plugins/qmlprojectmanager/qmlprojectnodes.h
src/plugins/qmlprojectmanager/qmlprojectruncontrol.cpp
src/plugins/qmlprojectmanager/qmlprojectruncontrol.h
src/plugins/qt4projectmanager/Qt4ProjectManager.pluginspec
src/plugins/qt4projectmanager/qmakestep.cpp
src/plugins/qt4projectmanager/qt-maemo/maemopackagecontents.cpp
src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationstep.cpp
src/plugins/qt4projectmanager/qt-maemo/maemopackagecreationstep.h
src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.cpp
src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.h
src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp
src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.h
src/plugins/qt4projectmanager/qt-maemo/maemosettingswidget.cpp
src/plugins/qt4projectmanager/qt-maemo/maemosshthread.cpp
src/plugins/qt4projectmanager/qt-maemo/maemosshthread.h
src/plugins/qt4projectmanager/qt-s60/s60createpackagestep.cpp
src/plugins/qt4projectmanager/qt-s60/s60createpackagestep.h
src/plugins/qt4projectmanager/qt-s60/s60createpackagestep.ui
src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp
src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h
src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.cpp
src/plugins/qt4projectmanager/qt-s60/s60emulatorrunconfiguration.h
src/plugins/qt4projectmanager/qt-s60/s60manager.cpp
src/plugins/qt4projectmanager/qt4buildconfiguration.cpp
src/plugins/qt4projectmanager/qt4buildconfiguration.h
src/plugins/qt4projectmanager/qt4nodes.cpp
src/plugins/qt4projectmanager/qt4nodes.h
src/plugins/qt4projectmanager/qt4project.cpp
src/plugins/qt4projectmanager/qt4project.h
src/plugins/qt4projectmanager/qt4projectmanager.cpp
src/plugins/qt4projectmanager/qt4projectmanager.h
src/plugins/qt4projectmanager/qt4projectmanagerconstants.h
src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp
src/plugins/qt4projectmanager/qt4projectmanagerplugin.h
src/plugins/regexp/RegExp.pluginspec
src/plugins/resourceeditor/ResourceEditor.pluginspec
src/plugins/resourceeditor/resourceeditorw.cpp
src/plugins/resourceeditor/resourceeditorw.h
src/plugins/snippets/Snippets.pluginspec
src/plugins/subversion/Subversion.pluginspec
src/plugins/subversion/subversioncontrol.cpp
src/plugins/subversion/subversioncontrol.h
src/plugins/subversion/subversionplugin.cpp
src/plugins/subversion/subversionplugin.h
src/plugins/texteditor/TextEditor.pluginspec
src/plugins/texteditor/basetextdocument.cpp
src/plugins/texteditor/basetextdocument.h
src/plugins/texteditor/basetextdocumentlayout.cpp
src/plugins/texteditor/basetextdocumentlayout.h
src/plugins/texteditor/basetexteditor.cpp
src/plugins/texteditor/basetexteditor.h
src/plugins/texteditor/basetexteditor_p.h
src/plugins/texteditor/fontsettingspage.cpp
src/plugins/texteditor/generichighlighter/context.cpp [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/context.h [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/dynamicrule.cpp [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/dynamicrule.h [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/highlightdefinition.cpp [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/highlightdefinition.h [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/highlightdefinitionhandler.cpp [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/highlightdefinitionhandler.h [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/highlighter.cpp [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/highlighter.h [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/highlighterexception.h [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/includerulesinstruction.cpp [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/includerulesinstruction.h [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/itemdata.cpp [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/itemdata.h [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/keywordlist.cpp [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/keywordlist.h [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/manager.cpp [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/manager.h [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/progressdata.cpp [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/progressdata.h [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/reuse.h [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/rule.cpp [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/rule.h [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/specificrules.cpp [new file with mode: 0644]
src/plugins/texteditor/generichighlighter/specificrules.h [new file with mode: 0644]
src/plugins/texteditor/indenter.cpp [new file with mode: 0644]
src/plugins/texteditor/indenter.h [new file with mode: 0644]
src/plugins/texteditor/normalindenter.cpp [new file with mode: 0644]
src/plugins/texteditor/normalindenter.h [new file with mode: 0644]
src/plugins/texteditor/plaintexteditor.cpp
src/plugins/texteditor/plaintexteditor.h
src/plugins/texteditor/plaintexteditorfactory.cpp
src/plugins/texteditor/plaintexteditorfactory.h
src/plugins/texteditor/texteditor.pro
src/plugins/texteditor/texteditoractionhandler.cpp
src/plugins/texteditor/texteditoractionhandler.h
src/plugins/texteditor/texteditorconstants.h
src/plugins/texteditor/texteditorplugin.cpp
src/plugins/texteditor/texteditorplugin.h
src/plugins/vcsbase/VCSBase.pluginspec
src/plugins/vcsbase/submiteditorfile.cpp
src/plugins/vcsbase/submiteditorfile.h
src/plugins/vcsbase/vcsbaseeditor.cpp
src/plugins/welcome/Welcome.pluginspec
src/shared/cplusplus/CPlusPlusForwardDeclarations.h
src/shared/cplusplus/CheckDeclaration.cpp
src/shared/cplusplus/CheckName.cpp
src/shared/cplusplus/Control.cpp
src/shared/cplusplus/Control.h
src/shared/cplusplus/Parser.cpp
src/shared/cplusplus/Scope.cpp
src/shared/cplusplus/Scope.h
src/shared/cplusplus/Symbol.cpp
src/shared/cplusplus/Symbol.h
src/shared/cplusplus/SymbolVisitor.h
src/shared/cplusplus/Symbols.cpp
src/shared/cplusplus/Symbols.h
tests/auto/auto.pro
tests/auto/cplusplus/lookup/tst_lookup.cpp
tests/auto/cplusplus/semantic/tst_semantic.cpp
tests/auto/debugger/dumpers.pro
tests/auto/debugger/tst_dumpers.cpp
tests/auto/generichighlighter/generichighlighter.pro [new file with mode: 0644]
tests/auto/generichighlighter/specificrules/specificrules.pro [new file with mode: 0644]
tests/auto/generichighlighter/specificrules/tst_specificrules.cpp [new file with mode: 0644]
tests/manual/cplusplus/main.cpp
tests/manual/gdbdebugger/simple/app.cpp

index 2e53e05..5c1ce5b 100644 (file)
@@ -81,3 +81,4 @@ tests/auto/qml/qmldesigner/coretests/tst_qmldesigner_core
 tests/auto/qml/qmldesigner/propertyeditortests/tst_propertyeditor
 tests/auto/profilewriter/tst_profilewriter
 src/tools/cplusplus/generate-ast
+src/tools/qml/qmldump/qmldump
diff --git a/README b/README
index 276c530..b10ff31 100644 (file)
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-Qt Creator 1.3.84
+Qt Creator 2.0.80
 ===============
 Qt Creator is a crossplatform C++ IDE for development with the Qt framework.
 
index 9d385d8..2544702 100644 (file)
@@ -16,7 +16,7 @@ HTML.postheader         = " <div class=\"header\" id=\"qtdocheader\">\n" \
                          "    </div>\n" \
                          "    <div id=\"shortCut\">\n" \
                          "      <ul>\n" \
-                         "        <li class=\"shortCut-topleft-inactive\"><span><a href=\"index.html\">Qt Creator 1.3.84 </a></span></li>\n" \
+                         "        <li class=\"shortCut-topleft-inactive\"><span><a href=\"index.html\">Qt Creator 2.0.80 </a></span></li>\n" \
                          "        <li class=\"shortCut-topleft-active\"><a href=\"http://qt.nokia.com/doc/\">ALL Versions" \
                          "        </a></li>\n" \
                          "      </ul>\n" \
index e96ec23..694d55f 100644 (file)
@@ -12,7 +12,7 @@
 
     \title Qt Creator Manual
 
-    \section1 Version 2.0 (Beta)
+    \section1 Version 2.0.80
 
     Qt Creator provides integrated tools for both application designers
     and developers to create applications for multiple desktop and mobile device
     \section1 Using Update Code Model
 
     To refresh the internal information in Qt Creator pertaining to your code,
-    select \gui{Tools} > \gui{C++} > \gui{Update Code Model}.
+    select \gui{Tools} > \gui{C++} > \gui{Update code model}.
 
     \note In Qt Creator indexing updates the code automatically. Use
-    \gui{Update Code Model} only as an emergency command.
+    \gui{Update code model} only as an emergency command.
 
 */
 
 
     In the \gui{FakeVim} mode, you can run the main editor in a manner similar
     to the Vim editor. To run the editor in the \gui{FakeVim} mode, select
-    \gui{Edit} > \gui{Advanced} > \gui{Use Vim-style Editing} or press
+    \gui{Edit} > \gui{Advanced} > \gui{Use vim-style editing} or press
     \key{Alt+V,Alt+V}.
 
     In the \gui{FakeVim} mode, most keystrokes in the main editor will be
     {Complete Guide to Symbian Signed}.
 
     When you have your own certificate and private key, you can specify them in
-    the \gui{Create SIS Package} step in your build configuration.
+    the \gui{Create sis Package} step in your build configuration.
 
     \image qtcreator-qt4-symbian-signing.png
 
            \gui{Add clean step} and select the type of step you want to add.
 
            By default, custom steps are disabled. Activate custom steps by
-           checking the \gui{Enable custom process step} check-box.
-        \o To remove a clean step, click \gui{Remove Item}.
+           checking the \gui{Enable Custom Process Step} check-box.
+        \o To remove a clean step, click \gui{Remove clean step} and select the
+           step you want to remove.
         \o To change the order of steps, click
            \inlineimage qtcreator-movestep.png
            .
                 a rebase operation while pulling.
 
         \row
-            \i  \gui{Clean Repository.../Clean Project...}
+            \i  \gui{Clean repository.../Clean project...}
             \i  Collect all files that are not under version control
                 with the exception of patches and project files
                 and show them as a checkable list in a dialog
         \row
             \i  \gui{Stashes...}
             \i  Displays a dialog showing the stashes created by
-                \gui{Stash Snapshot...} with options to restore,
+                \gui{Stash snapshots...} with options to restore,
                 display or delete them.
         \row
             \i  \gui {Stage File for Commit}
     \section2 Terminal Mode
 
     To launch the debugger in the terminal mode, select \gui {Projects > Run Settings}
-    and select the \gui {Run in terminal} check box. Then click the
+    and select the \gui {Run in Terminal} check box. Then click the
     \gui {Start Debugging} button for the active project.
 
     \section2 Attach Mode
     To enable Qt's basic objects data display feature:
     \list
        \o  Select \gui Tools > \gui {Options...} > \gui Debugger >
-           \gui{Debugging Helper} and check the \gui{Use Debugging Helper}
+           \gui{Debugging Helper} and check the \gui{Use debugging helper}
            checkbox.
        \o  The \gui{Locals and Watchers} view is reorganized to provide a
            high-level view of the objects.
     specified in the \c CMake project file.
 
     Known issues for the current version can be found
-    \l{Known Issues of version 1.3.84}{here}.
+    \l{Known Issues of version 2.0.80}{here}.
 
 
     \section1 Adding External Libraries to a CMake Project
             \o In the \gui {Configuration name} field, enter a name for
             the connection.
 
-            \o In the \gui {Device type} field, select \gui {Maemo emulator}.
+            \o In the \gui {Device type} field, select \gui {Local simulator}.
 
             \o In the \gui {Authentication type} field, select \gui Password
             for the initial connection.
     \list 1
         \o Select \gui Tools > \gui Options... > \gui Debugger >
            \gui{Debugging Helper}.
-        \o Uncheck the \gui{Use Debugging Helper} checkbox.
+        \o Uncheck the \gui{Use debugging helper} checkbox.
     \endlist
 
 */
     There are some known issues with Qt Creator.
     The development team is aware of them, there is no need to report them as bugs.
 
-    \section1 Known Issues of Version 1.3.84
+    \section1 Known Issues of Version 2.0.80
 
     \list
         \o On Windows, debugging a MinGW-built console application (with \gui{Run in terminal}
index 7f438ce..b43113b 100644 (file)
@@ -19,12 +19,12 @@ sources.fileextensions  = "qtcreator.qdoc addressbook-sdk.qdoc"
 
 qhp.projects            = QtCreator
 qhp.QtCreator.file             = qtcreator.qhp
-qhp.QtCreator.namespace        = com.nokia.qtcreator.1384
+qhp.QtCreator.namespace        = com.nokia.qtcreator.2080
 qhp.QtCreator.virtualFolder    = doc
 qhp.QtCreator.indexTitle       = Qt Creator
-qhp.QtCreator.filterAttributes = qtcreator 1.3.84
-qhp.QtCreator.customFilters.QtCreator.name = Qt Creator 1.3.84
-qhp.QtCreator.customFilters.QtCreator.filterAttributes = qtcreator 1.3.84
+qhp.QtCreator.filterAttributes = qtcreator 2.0.80
+qhp.QtCreator.customFilters.QtCreator.name = Qt Creator 2.0.80
+qhp.QtCreator.customFilters.QtCreator.filterAttributes = qtcreator 2.0.80
 qhp.QtCreator.indexRoot        =
 qhp.QtCreator.extraFiles       = \
                           style/style.css \
index e31b154..0f2295c 100644 (file)
@@ -385,6 +385,8 @@ def listOfLocals(varList):
     hasBlock = 'block' in __builtin__.dir(frame)
 
     items = []
+    #warn("HAS BLOCK: %s" % hasBlock);
+    #warn("IS GOOD GDB: %s" % isGoodGdb());
     if hasBlock and isGoodGdb():
         #warn("IS GOOD: %s " % varList)
         try:
@@ -780,6 +782,7 @@ class FrameCommand(gdb.Command):
         formats = {}
         watchers = ""
         expandedINames = ""
+        resultVarName = ""
         for arg in args.split(' '):
             pos = arg.find(":") + 1
             if arg.startswith("options:"):
@@ -787,6 +790,8 @@ class FrameCommand(gdb.Command):
             elif arg.startswith("vars:"):
                 if len(arg[pos:]) > 0:
                     varList = arg[pos:].split(",")
+            elif arg.startswith("resultvarname:"):
+                resultVarName = arg[pos:]
             elif arg.startswith("expanded:"):
                 expandedINames = set(arg[pos:].split(","))
             elif arg.startswith("typeformats:"):
@@ -838,7 +843,7 @@ class FrameCommand(gdb.Command):
         d.typeformats = typeformats
         d.formats = formats
         d.useFancy = useFancy
-        d.passExceptions = "passexceptions" in options
+        d.passExceptions = "pe" in options
         d.autoDerefPointers = "autoderef" in options
         d.ns = qtNamespace()
         d.expandedINames = expandedINames
@@ -847,7 +852,18 @@ class FrameCommand(gdb.Command):
         #
         # Locals
         #
-        for item in listOfLocals(varList):
+        locals = listOfLocals(varList);
+
+        # Take care of the return value of the last function call.
+        if len(resultVarName) > 0:
+            try:
+                value = parseAndEvaluate(resultVarName)
+                locals.append(Item(value, "return", resultVarName, "return"))
+            except:
+                # Don't bother. It's only supplementary information anyway.
+                pass
+
+        for item in locals:
           with OutputSafer(d, "", ""):
             d.anonNumber = -1
             #warn("ITEM NAME %s: " % item.name)
@@ -1313,8 +1329,10 @@ class Dumper:
                 self.putNumChild(1)
                 if self.isExpanded(item):
                     with Children(self):
-                        self.putItem(
-                              Item(item.value.dereference(), item.iname, "*", "*"))
+                        with SubItem(self):
+                            self.putItemHelper(Item(item.value.dereference(),
+                                item.iname, "*", "*"))
+                            self.putAddress(item.value)
                 self.putPointerValue(value.address)
 
         elif str(type).startswith("<anon"):
index 9ccc1c5..785ce35 100644 (file)
@@ -366,6 +366,15 @@ def qdump__QHashNode(d, item):
                 d.putItemHelper(Item(value, item.iname, "value"))
 
 
+def qdump__QHostAddress(d, item):
+    data = item.value["d"]["d"].dereference()
+    d.putStringValue(data["ipString"])
+    d.putNumChild(1)
+    if d.isExpanded(item):
+        with Children(d):
+           d.putFields(Item(data, item.iname))
+
+
 def qdump__QList(d, item):
     d_ptr = item.value["d"]
     begin = d_ptr["begin"]
@@ -397,9 +406,9 @@ def qdump__QList(d, item):
         # in the frontend.
         # So as first approximation only do the 'isLarge' check:
         isInternal = innerSize <= d_ptr.type.sizeof and d.isMovableType(innerType)
-        #warn("INTERNAL: %d" % int(isInternal))
-
-        p = gdb.Value(array).cast(innerType.pointer()) + begin
+        dummyType = gdb.lookup_type("void").pointer().pointer()
+        innerTypePointer = innerType.pointer()
+        p = gdb.Value(array).cast(dummyType) + begin
         if innerTypeIsPointer:
             inner = innerType.target()
         else:
@@ -408,10 +417,11 @@ def qdump__QList(d, item):
         with Children(d, [size, 2000], inner):
             for i in d.childRange():
                 if isInternal:
-                    d.putItem(Item(p.dereference(), item.iname, i))
+                    pp = p.cast(innerTypePointer).dereference();
+                    d.putItem(Item(pp, item.iname, i))
                 else:
-                    pp = p.cast(innerType.pointer().pointer()).dereference()
-                    d.putItem(Item(pp.dereference(), item.iname, i))
+                    pp = p.cast(innerTypePointer.pointer()).dereference()
+                    d.putItem(Item(pp, item.iname, i))
                 p += 1
 
 
@@ -1404,6 +1414,14 @@ def qdump__QStack(d, item):
 def qdump__QString(d, item):
     d.putStringValue(item.value)
     d.putNumChild(0)
+    d.putField("typeformats", "Normal,Displayed");
+    format = d.itemFormat(item)
+    if format == 0:
+        d.putDisplay(StopDisplay)
+    elif format == 1:
+        d.putField("editformat", 2)
+        str = encodeString(item.value)
+        d.putField("editvalue", str)
 
 
 def qdump__QStringList(d, item):
@@ -1452,9 +1470,9 @@ def qdump__QUrl(d, item):
 
 
 def qdumpHelper__QVariant(d, value):
-    #warn("VARIANT TYPE: %s : " % variantType)
     data = value["d"]["data"]
     variantType = int(value["d"]["type"])
+    #warn("VARIANT TYPE: %s : " % variantType)
     val = None
     inner = ""
     innert = ""
@@ -1596,15 +1614,18 @@ def qdumpHelper__QVariant(d, value):
 
 def qdump__QVariant(d, item):
     val, inner, innert = qdumpHelper__QVariant(d, item.value)
+    #warn("VARIANT DATA: '%s' '%s' '%s': " % (val, inner, innert))
 
-    if len(inner):
-        # Build-in types.
-        #d.putValue("(%s)" % innert)
-        d.putType("%sQVariant (%s)" % (d.ns, innert))
-        d.putNumChild(1)
-        if d.isExpanded(item):
-            with Children(d):
-                d.putItem(Item(val, item.iname, "data", "data"))
+    if len(inner): 
+        innerType = gdb.lookup_type(inner)
+        # FIXME: Why "shared"?
+        if innerType.sizeof > item.value["d"]["data"].type.sizeof:
+            v = item.value["d"]["data"]["shared"]["ptr"] \
+                .cast(innerType.pointer()).dereference()
+        else:
+            v = item.value["d"]["data"].cast(innerType)
+        d.putItemHelper(Item(v, item.iname))
+        d.putType("%sQVariant (%s)" % (d.ns, innert), d.currentTypePriority + 1)
     else:
         # User types.
         d_member = item.value["d"]
@@ -1951,6 +1972,37 @@ def qdump__TLitC(d, item):
 #######################################################################
 
 if False:
+
+    # FIXME: Make that work
+    def qdump__Color(d, item):
+        v = item.value
+        d.putValue("(%s, %s, %s; %s)" % (v["r"], v["g"], v["b"], v["a"]))
+        if d.isExpanded(item):
+            with Children(d):
+                d.putItem(Item(v["r"], item.iname, "0", "r"))
+                d.putItem(Item(v["g"], item.iname, "1", "g"))
+                d.putItem(Item(v["b"], item.iname, "2", "b"))
+                d.putItem(Item(v["a"], item.iname, "3", "a"))
+
+    def qdump__Color_(d, item):
+        v = item.value
+        d.putValue("(%s, %s, %s; %s)" % (v["r"], v["g"], v["b"], v["a"]))
+        if d.isExpanded(item):
+            with Children(d):
+                with SubItem(d):
+                    d.putField("iname", item.iname + ".0")
+                    d.putItemHelper(Item(v["r"], item.iname, "0", "r"))
+                with SubItem(d):
+                    d.putField("iname", item.iname + ".1")
+                    d.putItemHelper(Item(v["g"], item.iname, "1", "g"))
+                with SubItem(d):
+                    d.putField("iname", item.iname + ".2")
+                    d.putItemHelper(Item(v["b"], item.iname, "2", "b"))
+                with SubItem(d):
+                    d.putField("iname", item.iname + ".3")
+                    d.putItemHelper(Item(v["a"], item.iname, "3", "a"))
+
+
     def qdump__Function(d, item):
         min = item.value["min"]
         max = item.value["max"]
index 7d9a465..96addcc 100644 (file)
@@ -12,11 +12,16 @@ class qdebug:
             individualformats = None,
             watchers = None):
         self.options = options
-        self.expanded = expanded
+        self.expandedINames = expanded
         self.typeformats = typeformats
         self.individualformats = individualformats
         self.watchers = watchers
-        self.doit()
+        if self.options == "listmodules":
+            self.handleListModules()
+        elif self.options == "listsymbols":
+            self.handleListSymbols(expanded)
+        else:
+            self.handleListVars()
 
     def put(self, value):
         sys.stdout.write(value)
@@ -34,6 +39,8 @@ class qdebug:
         t = str(type)
         if t.startswith("<type '") and t.endswith("'>"):
             t = t[7:-2]
+        if t.startswith("<class '") and t.endswith("'>"):
+            t = t[8:-2]
         return t
 
     def putType(self, type, priority = 0):
@@ -51,14 +58,12 @@ class qdebug:
     def putName(self, name):
         self.put('name="%s",' % name)
 
-    def isExpanded(self, item):
-        #warn("IS EXPANDED: %s in %s" % (item.iname, self.expandedINames))
-        if item.iname is None:
-            raise "Illegal iname 'None'"
-        if item.iname.startswith("None"):
-            raise "Illegal iname '%s'" % item.iname
-        #warn("   --> %s" % (item.iname in self.expandedINames))
-        return item.iname in self.expandedINames
+    def isExpanded(self, iname):
+        #self.warn("IS EXPANDED: %s in %s" % (iname, self.expandedINames))
+        if iname.startswith("None"):
+            raise "Illegal iname '%s'" % iname
+        #self.warn("   --> %s" % (iname in self.expandedINames))
+        return iname in self.expandedINames
 
     def isExpandedIName(self, iname):
         return iname in self.expandedINames
@@ -88,11 +93,19 @@ class qdebug:
         tt = self.cleanType(t)
         if tt == "module" or tt == "function":
             return
+        if str(value).startswith("<class '"):
+            return
+        # FIXME: Should we?
+        if str(value).startswith("<enum-item "):
+            return
         self.put("{")
         self.putField("iname", iname)
         self.putName(name)
         self.putType(tt)
-        if tt == "list" or tt == "tuple":
+        if tt == "NoneType":
+            self.putValue("None")
+            self.putNumChild(0)
+        elif tt == "list" or tt == "tuple":
             self.putItemCount(len(value))
             #self.putValue(value)
             self.put("children=[")
@@ -128,23 +141,53 @@ class qdebug:
                 self.put("{")
                 self.putType(" ")
                 self.putValue("%s: %s" % (k, v))
-                self.put("children=[")
-                self.dumpValue(k, "key", "%s.%d.k" % (iname, i))
-                self.dumpValue(v, "value", "%s.%d.v" % (iname, i))
-                self.put("]},")
+                if self.isExpanded(iname):
+                    self.put("children=[")
+                    self.dumpValue(k, "key", "%s.%d.k" % (iname, i))
+                    self.dumpValue(v, "value", "%s.%d.v" % (iname, i))
+                    self.put("]},")
                 i += 1
             self.put("]")
-        elif tt == "module" or tt == "function":
+        elif tt == "class":
+            pass
+        elif tt == "module":
+            pass
+        elif tt == "function":
             pass
+        elif str(value).startswith("<enum-item "):
+            # FIXME: Having enums always shown like this is not nice.
+            self.putValue(str(value)[11:-1])
+            self.putNumChild(0)
         else:
-            self.putValue(value)
+            v = str(value)
+            p = v.find(" object at ")
+            if p > 1:
+                v = "@" + v[p + 11:-1]
+            self.putValue(v)
+            if self.isExpanded(iname):
+                self.put("children=[")
+                for child in dir(value):
+                    if child == "__dict__":
+                        continue
+                    if child == "__doc__":
+                        continue
+                    if child == "__module__":
+                        continue
+                    attr = getattr(value, child)
+                    if callable(attr):
+                        continue
+                    try:
+                        self.dumpValue(attr, child, "%s.%s" % (iname, child))
+                    except:
+                        pass
+                self.put("],")
         self.put("},")
 
 
     def warn(self, msg):
         self.putField("warning", msg)
 
-    def doit(self):
+    def handleListVars(self):
         # Trigger error to get a backtrace.
         frame = None
         #self.warn("frame: %s" % frame)
@@ -174,3 +217,24 @@ class qdebug:
             n = n + 1
 
         sys.stdout.flush()
+
+    def handleListModules(self):
+        self.put("modules=[");
+        for name in sys.modules:
+            self.put("{")
+            self.putName(name)
+            self.putValue(sys.modules[name])
+            self.put("},")
+        self.put("]")
+        sys.stdout.flush()
+
+    def handleListSymbols(self, module):
+        #self.put("symbols=%s" % dir(sys.modules[module]))
+        self.put("symbols=[");
+        for name in sys.modules:
+            self.put("{")
+            self.putName(name)
+            #self.putValue(sys.modules[name])
+            self.put("},")
+        self.put("]")
+        sys.stdout.flush()
diff --git a/share/qtcreator/generic-highlighter/README b/share/qtcreator/generic-highlighter/README
new file mode 100644 (file)
index 0000000..8aabe11
--- /dev/null
@@ -0,0 +1,3 @@
+Place syntax definitions files inside this directory. 
+Files can be downloaded at http://kate-editor.org/downloads/syntax_highlighting?kateversion=3.2
+Instructions on how to write your own definitions can be found at http://kate-editor.org/article/writing_a_kate_highlighting_xml_file
index 4210cbe..c3595b5 100644 (file)
@@ -30,7 +30,8 @@ DATA_DIRS = \
     styles \
     gdbmacros \
     qmldesigner \
-    qml-type-descriptions
+    qml-type-descriptions \
+    generic-highlighter
 
 !isEmpty(copydata) {
 
diff --git a/share/qtcreator/templates/wizards/qtcreatorplugin/MyPlugin.pluginspec b/share/qtcreator/templates/wizards/qtcreatorplugin/MyPlugin.pluginspec
new file mode 100644 (file)
index 0000000..8946d48
--- /dev/null
@@ -0,0 +1,10 @@
+<plugin name="%PluginName%" version="0.0.1" compatVersion="0.0.1">
+    <vendor>%VendorName%</vendor>
+    <copyright>%Copyright%</copyright>
+    <license>%License%</license>
+    <description>%Description%</description>
+    <url>%URL%</url>
+    <dependencyList>
+        <dependency name="Core" version="2.0.80"/>
+    </dependencyList>
+</plugin>
diff --git a/share/qtcreator/templates/wizards/qtcreatorplugin/myplugin.cpp b/share/qtcreator/templates/wizards/qtcreatorplugin/myplugin.cpp
new file mode 100644 (file)
index 0000000..e68c6d9
--- /dev/null
@@ -0,0 +1,82 @@
+#include "%PluginName:l%.%CppHeaderSuffix%"
+
+#include <QtPlugin>
+
+#include <coreplugin/icore.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/actionmanager/command.h>
+#include <coreplugin/actionmanager/actioncontainer.h>
+#include <coreplugin/coreconstants.h>
+
+#include <QtPlugin>
+#include <QAction>
+#include <QMessageBox>
+#include <QMainWindow>
+#include <QMenu>
+
+namespace {
+    const char * const ACTION_ID = "%PluginName%.Action";
+    const char * const MENU_ID = "%PluginName%.Menu";
+}
+
+using namespace %PluginName%::Internal;
+
+%PluginName%Impl::%PluginName%Impl()
+{
+    // Create your members
+}
+
+%PluginName%Impl::~%PluginName%Impl()
+{
+    // Unregister objects from the plugin manager's object pool
+    // Delete members
+}
+
+bool %PluginName%Impl::initialize(const QStringList &arguments, QString *errorString)
+{
+    // Register objects in the plugin manager's object pool
+    // Load settings
+    // Add actions to menus
+    // connect to other plugins' signals
+    // "In the initialize method, a plugin can be sure that the plugins it
+    //  depends on have initialized their members."
+
+    Q_UNUSED(arguments)
+    Q_UNUSED(errorString)
+    Core::ActionManager *am = Core::ICore::instance()->actionManager();
+
+    QAction *action = new QAction(tr("%PluginName% action"), this);
+    Core::Command *cmd = am->registerAction(action, QLatin1String(ACTION_ID),
+                         QList<int>() << Core::Constants::C_GLOBAL_ID);
+    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Meta+A")));
+    connect(action, SIGNAL(triggered()), this, SLOT(triggerAction()));
+
+    Core::ActionContainer *menu = am->createMenu(MENU_ID);
+    menu->menu()->setTitle(tr("%PluginName%"));
+    menu->addAction(cmd);
+    am->actionContainer(Core::Constants::M_TOOLS)->addMenu(menu);
+
+    return true;
+}
+
+void %PluginName%Impl::extensionsInitialized()
+{
+    // Retrieve objects from the plugin manager's object pool
+    // "In the extensionsInitialized method, a plugin can be sure that all
+    //  plugins that depend on it are completely initialized."
+}
+
+void %PluginName%Impl::aboutToShutdown()
+{
+    // Save settings
+    // Disconnect from signals that are not needed during shutdown
+}
+
+void %PluginName%Impl::triggerAction()
+{
+    QMessageBox::information(Core::ICore::instance()->mainWindow(),
+                             tr("Action triggered"),
+                             tr("This is an action from %PluginName%."));
+}
+
+Q_EXPORT_PLUGIN2(%PluginName%, %PluginName%Impl)
diff --git a/share/qtcreator/templates/wizards/qtcreatorplugin/myplugin.h b/share/qtcreator/templates/wizards/qtcreatorplugin/myplugin.h
new file mode 100644 (file)
index 0000000..ac28bdf
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef %PluginName:u%_%CppHeaderSuffix:u%
+#define %PluginName:u%_%CppHeaderSuffix:u%
+
+#include "%PluginName:l%_global.%CppHeaderSuffix%"
+
+#include <extensionsystem/iplugin.h>
+
+namespace %PluginName% {
+namespace Internal {
+
+class %PluginName%Impl : public ExtensionSystem::IPlugin
+{
+    Q_OBJECT
+
+public:
+    %PluginName%Impl();
+    ~%PluginName%Impl();
+
+    bool initialize(const QStringList &arguments, QString *errorString);
+    void extensionsInitialized();
+    void aboutToShutdown();
+
+private slots:
+    void triggerAction();
+};
+
+} // namespace Internal
+} // namespace %PluginName%
+
+#endif // %PluginName:u%_%CppHeaderSuffix:u%
diff --git a/share/qtcreator/templates/wizards/qtcreatorplugin/myplugin.pro b/share/qtcreator/templates/wizards/qtcreatorplugin/myplugin.pro
new file mode 100644 (file)
index 0000000..65e1cef
--- /dev/null
@@ -0,0 +1,31 @@
+TARGET = %PluginName%
+TEMPLATE = lib
+
+DEFINES += %PluginName:u%_LIBRARY
+
+# %PluginName% files
+
+SOURCES += %PluginName:l%.cpp
+
+HEADERS += %PluginName:l%.h\
+        %PluginName:l%_global.h
+
+OTHER_FILES = %PluginName%.pluginspec
+
+
+# Qt Creator linking
+
+## set the QTC_SOURCE environment variable to override the setting here
+QTCREATOR_SOURCES = $$(QTC_SOURCE)
+isEmpty(QTCREATOR_SOURCES):QTCREATOR_SOURCES=%QtCreatorSources%
+
+## set the QTC_BUILD environment variable to override the setting here
+IDE_BUILD_TREE = $$(QTC_BUILD)
+isEmpty(IDE_BUILD_TREE):IDE_BUILD_TREE=%QtCreatorBuild%
+
+PROVIDER = %VendorName%
+
+include($$QTCREATOR_SOURCES/src/qtcreatorplugin.pri)
+include($$QTCREATOR_SOURCES/src/plugins/coreplugin/coreplugin.pri)
+
+LIBS += -L$$IDE_PLUGIN_PATH/Nokia
diff --git a/share/qtcreator/templates/wizards/qtcreatorplugin/myplugin_global.h b/share/qtcreator/templates/wizards/qtcreatorplugin/myplugin_global.h
new file mode 100644 (file)
index 0000000..c18aa87
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef %PluginName:u%_GLOBAL_%CppHeaderSuffix:u%
+#define %PluginName:u%_GLOBAL_%CppHeaderSuffix:u%
+
+#include <QtCore/qglobal.h>
+
+#if defined(%PluginName:u%_LIBRARY)
+#  define %PluginName:u%SHARED_EXPORT Q_DECL_EXPORT
+#else
+#  define %PluginName:u%SHARED_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // %PluginName:u%_GLOBAL_H
diff --git a/share/qtcreator/templates/wizards/qtcreatorplugin/qtcreator_logo_24.png b/share/qtcreator/templates/wizards/qtcreatorplugin/qtcreator_logo_24.png
new file mode 100644 (file)
index 0000000..1f651b2
Binary files /dev/null and b/share/qtcreator/templates/wizards/qtcreatorplugin/qtcreator_logo_24.png differ
diff --git a/share/qtcreator/templates/wizards/qtcreatorplugin/wizard.xml b/share/qtcreator/templates/wizards/qtcreatorplugin/wizard.xml
new file mode 100644 (file)
index 0000000..10275ff
--- /dev/null
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+Custom project wizard configuration example file. Note that by convention, 
+the project file goes last.
+The "class" and "firstpage" attributes specify that it is a Qt 4 wizard and 
+leave room for the Qt 4 target page.
+-->
+<wizard version="1" kind="project"
+        class="qt4project" firstpage="10"
+        id="R.QtCreatorPlugin" category="I.Projects">
+    <icon>qtcreator_logo_24.png</icon>
+    <description>Creates a custom Qt Creator plugin.</description>
+    <displayname>Qt Creator plugin</displayname>;
+    <displaycategory>Other Project</displaycategory>
+    <files>
+        <file source="myplugin.pro" target="%PluginName:l%.pro" openproject="true"/>
+        <file source="MyPlugin.pluginspec" target="%PluginName%.pluginspec" openeditor="true"/>
+        <file source="myplugin.h" target="%PluginName:l%.%CppHeaderSuffix%" openeditor="true"/>
+        <file source="myplugin.cpp" target="%PluginName:l%.%CppSourceSuffix%" openeditor="true"/>
+        <file source="myplugin_global.h" target="%PluginName:l%_global.%CppHeaderSuffix%" openeditor="true"/>
+    </files>
+    <!-- Create a 2nd wizard page with parameters -->
+    <fieldpagetitle>Plugin Information</fieldpagetitle>
+    <fieldpagetitle xml:lang="de">Plugininformationen</fieldpagetitle>
+    <fields>
+        <field mandatory="true" name="PluginName">
+            <fieldcontrol class="QLineEdit" validator="^[a-zA-Z0-9_]+$"
+                          defaulttext="MyPlugin" />
+            <fielddescription>Plugin name:</fielddescription>
+            <fielddescription xml:lang="de">Name des Plugins:</fielddescription>
+        </field>
+        <field mandatory="true" name="VendorName">
+            <fieldcontrol class="QLineEdit" validator="^[a-zA-Z0-9_]+$"
+                          defaulttext="MyCompany" />
+            <fielddescription>Vendor name:</fielddescription>
+            <fielddescription xml:lang="de">Name des Anbieters:</fielddescription>
+        </field>
+        <field name="Copyright">
+            <fieldcontrol class="QLineEdit"
+                          defaulttext="(C) MyCompany" />
+            <fielddescription>Copyright:</fielddescription>
+            <fielddescription xml:lang="de">Copyright:</fielddescription>
+        </field>
+        <field name="License">
+            <fieldcontrol class="QTextEdit"
+                          defaulttext="Put your license text here" />
+            <fielddescription>License:</fielddescription>
+            <fielddescription xml:lang="de">Lizenz:</fielddescription>
+        </field>
+        <field name="Description">
+            <fieldcontrol class="QTextEdit"
+                          defaulttext="Put a short description of your plugin here"/>
+            <fielddescription>Description:</fielddescription>
+            <fielddescription xml:lang="de">Beschreibung:</fielddescription>
+        </field>
+        <field name="URL">
+            <fieldcontrol class="QLineEdit"
+                          defaulttext="http://www.mycompany.com" />
+            <fielddescription>Url:</fielddescription>
+            <fielddescription xml:lang="de">Url:</fielddescription>
+        </field>
+        <field mandatory="true" name="QtCreatorSources">
+            <fieldcontrol class="Utils::PathChooser"
+                          defaulttext="" />
+            <fielddescription>Qt Creator sources:</fielddescription>
+            <fielddescription xml:lang="de">Qt Creator Quellen:</fielddescription>
+        </field>
+        <field mandatory="true" name="QtCreatorBuild">
+            <fieldcontrol class="Utils::PathChooser"
+                          defaulttext="" />
+            <fielddescription>Qt Creator build:</fielddescription>
+            <fielddescription xml:lang="de">Qt Creator build:</fielddescription>
+        </field>
+    </fields>
+</wizard>
index 9f93dbe..36af61b 100644 (file)
@@ -219,8 +219,8 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
        <key>CFBundleIdentifier</key>
        <string>com.nokia.qtcreator</string>
        <key>CFBundleVersion</key>
-       <string>1.3.84</string>
+       <string>2.0.80</string>
        <key>CFBundleShortVersionString</key>
-       <string>1.3.84</string>
+       <string>2.0.80</string>
 </dict>
 </plist>
index 08fbe52..fee5690 100644 (file)
@@ -293,13 +293,15 @@ void *ne7ssh::selectThread (void *initData)
   return 0;
 }
 
-int ne7ssh::connectWithPassword (const char *host, const int port, const char* username, const char* password, bool shell, const int timeout)
+int ne7ssh::connectWithPassword (const char *host, const int port,
+    const char* username, const char* password, bool shell, const int timeout,
+    void (*callbackFunc)(void *), void *callbackArg)
 {
   int channel;
   uint32 currentRecord, z;
   uint32 channelID;
 
-  ne7ssh_connection* con = new ne7ssh_connection ();
+  ne7ssh_connection* con = new ne7ssh_connection (callbackFunc, callbackArg);
 
   if (!lock()) return -1;
   if (!conCount) connections = (ne7ssh_connection**) malloc (sizeof (ne7ssh_connection*));
@@ -344,13 +346,15 @@ int ne7ssh::connectWithPassword (const char *host, const int port, const char* u
   return channel;
 }
 
-int ne7ssh::connectWithKey (const char* host, const int port, const char* username, const char* privKeyFileName, bool shell, const int timeout)
+int ne7ssh::connectWithKey (const char* host, const int port,
+    const char* username, const char* privKeyFileName, bool shell,
+    const int timeout, void (*callbackFunc)(void *), void *callbackArg)
 {
   int channel;
   uint32 currentRecord, z;
   uint32 channelID;
 
-  ne7ssh_connection* con = new ne7ssh_connection ();
+  ne7ssh_connection* con = new ne7ssh_connection (callbackFunc, callbackArg);
   if (!lock()) return -1;
   if (!conCount) connections = (ne7ssh_connection**) malloc (sizeof (ne7ssh_connection*) * (conCount + 1));
   else connections = (ne7ssh_connection**) realloc (connections, sizeof (ne7ssh_connection*) * (conCount + 1));
index 853d8b0..57cc281 100644 (file)
@@ -175,7 +175,9 @@ class SSH_EXPORT ne7ssh
      * @param timeout Timeout for the connection procedure, in seconds.
      * @return Returns newly assigned channel ID, or -1 if connection failed.
      */
-    int connectWithPassword (const char* host, const int port, const char* username, const char* password, bool shell = true, const int timeout = 0);
+    int connectWithPassword (const char* host, const int port, const char* username,
+        const char* password, bool shell = true, const int timeout = 0,
+        void (*callbackFunc)(void *) = 0, void *callbackArg = 0);
 
     /**
      * Connect to remote host using SSH2 protocol, with publickey authentication.
@@ -189,7 +191,9 @@ class SSH_EXPORT ne7ssh
      * @param timeout Timeout for the connection procedure, in seconds.
      * @return Returns newly assigned channel ID, or -1 if connection failed.
      */
-    int connectWithKey (const char* host, const int port, const char* username, const char* privKeyFileName, bool shell = true, const int timeout = 0);
+    int connectWithKey (const char* host, const int port, const char* username,
+        const char* privKeyFileName, bool shell = true, const int timeout = 0,
+        void (*callbackFunc)(void *) = 0, void *callbackArg = 0);
 
     /**
      * Retrieves a pointer to all current connections.
index 569eaa4..7361dba 100644 (file)
 
 using namespace Botan;
 
-ne7ssh_connection::ne7ssh_connection() : sock (-1), thisChannel(0), sftp(0), connected(false), cmdRunning(false), cmdClosed(false)
+ne7ssh_connection::ne7ssh_connection(void (*callbackFunc)(void *),
+    void *callbackArg)
+    : sock (-1), thisChannel(0), sftp(0), connected(false), cmdRunning(false),
+      cmdClosed(false), callbackFunc(callbackFunc), callbackArg(callbackArg)
 {
   session = new ne7ssh_session();
   crypto = new ne7ssh_crypt(session);
@@ -285,6 +288,8 @@ bool ne7ssh_connection::sendLocalVersion ()
 void ne7ssh_connection::handleData ()
 {
   channel->receive();
+  if (callbackFunc && getReceived().size() > 0)
+      callbackFunc(callbackArg);
 }
 
 void ne7ssh_connection::sendData (const char* data)
index a201c19..182b482 100644 (file)
@@ -46,6 +46,8 @@ class ne7ssh_connection
     bool cmdRunning;
     bool cmdClosed;
 
+    void (*callbackFunc)(void *);
+    void *callbackArg;
 
     /**
      * Checks if remote side is returning a correctly formated SSH version string, and makes sure that version 2 of SSH protocol is supported by the remote side.
@@ -88,7 +90,7 @@ class ne7ssh_connection
     /**
      * ne7ssh_connection class constructor.
      */
-    ne7ssh_connection();
+    ne7ssh_connection(void (*callbackFunc)(void *) = 0, void *callbackArg = 0);
 
     /**
      * ne7ssh_connection class destructor.
index 3e43507..c972e89 100644 (file)
@@ -196,6 +196,8 @@ void CheckUndefinedSymbols::buildTypeMap(NamespaceBinding *binding, QSet<Namespa
                     addType(e->name());
                 } else if (ForwardClassDeclaration *fwd = member->asForwardClassDeclaration()) {
                     addType(fwd->name());
+                } else if (NamespaceAlias *alias = member->asNamespaceAlias()) {
+                    addType(alias->name());
                 } else if (Declaration *decl = member->asDeclaration()) {
                     if (decl->isTypedef())
                         addType(decl->name());
@@ -255,6 +257,14 @@ bool CheckUndefinedSymbols::visit(TypeofSpecifierAST *)
     return false;
 }
 
+bool CheckUndefinedSymbols::visit(NamespaceAliasDefinitionAST *ast)
+{
+    if (const Identifier *id = identifier(ast->namespace_name_token))
+        _types.insert(QByteArray(id->chars(), id->size()));
+
+    return true;
+}
+
 bool CheckUndefinedSymbols::visit(NamedTypeSpecifierAST *ast)
 {
     if (ast->name) {
index 06b41c8..00b8d4d 100644 (file)
@@ -93,6 +93,7 @@ protected:
     virtual bool visit(QualifiedNameAST *ast);
     virtual bool visit(CastExpressionAST *ast);
     virtual bool visit(SizeofExpressionAST *ast);
+    virtual bool visit(NamespaceAliasDefinitionAST *ast);
 
     virtual bool visit(ObjCClassDeclarationAST *ast);
     virtual bool visit(ObjCProtocolRefsAST *ast);
index 5192f53..cd7c0fe 100644 (file)
@@ -28,8 +28,9 @@
 **************************************************************************/
 
 #include "CppDocument.h"
-#include "CppBindings.h"
 #include "FastPreprocessor.h"
+#include "LookupContext.h"
+#include "Overview.h"
 
 #include <Control.h>
 #include <TranslationUnit.h>
 #include <Semantic.h>
 #include <Literals.h>
 #include <Symbols.h>
+#include <Names.h>
 #include <AST.h>
 #include <Scope.h>
+#include <SymbolVisitor.h>
 
 #include <QtCore/QByteArray>
 #include <QtCore/QBitArray>
@@ -54,6 +57,97 @@ using namespace CPlusPlus;
 
 namespace {
 
+class FindScopeAt: protected SymbolVisitor
+{
+    TranslationUnit *_unit;
+    unsigned _line;
+    unsigned _column;
+    Scope *_scope;
+
+public:
+    FindScopeAt(TranslationUnit *unit, unsigned line, unsigned column)
+        : _unit(unit), _line(line), _column(column), _scope(0) {}
+
+    Scope *operator()(Symbol *symbol)
+    {
+        accept(symbol);
+        return _scope;
+    }
+
+protected:
+    bool process(ScopedSymbol *symbol)
+    {
+        if (! _scope) {
+            Scope *scope = symbol->members();
+
+            for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+                accept(scope->symbolAt(i));
+
+                if (_scope)
+                    return false;
+            }
+
+            unsigned startLine, startColumn;
+            _unit->getPosition(symbol->startOffset(), &startLine, &startColumn);
+
+            if (_line > startLine || (_line == startLine && _column >= startColumn)) {
+                unsigned endLine, endColumn;
+                _unit->getPosition(symbol->endOffset(), &endLine, &endColumn);
+
+                if (_line < endLine || (_line == endLine && _column < endColumn))
+                    _scope = scope;
+            }
+        }
+
+        return false;
+    }
+
+    using SymbolVisitor::visit;
+
+    virtual bool preVisit(Symbol *)
+    { return ! _scope; }
+
+    virtual bool visit(UsingNamespaceDirective *) { return false; }
+    virtual bool visit(UsingDeclaration *) { return false; }
+    virtual bool visit(NamespaceAlias *) { return false; }
+    virtual bool visit(Declaration *) { return false; }
+    virtual bool visit(Argument *) { return false; }
+    virtual bool visit(TypenameArgument *) { return false; }
+    virtual bool visit(BaseClass *) { return false; }
+    virtual bool visit(ForwardClassDeclaration *) { return false; }
+
+    virtual bool visit(Enum *symbol)
+    { return process(symbol); }
+
+    virtual bool visit(Function *symbol)
+    { return process(symbol); }
+
+    virtual bool visit(Namespace *symbol)
+    { return process(symbol); }
+
+    virtual bool visit(Class *symbol)
+    { return process(symbol); }
+
+    virtual bool visit(Block *symbol)
+    { return process(symbol); }
+
+    // Objective-C
+    virtual bool visit(ObjCBaseClass *) { return false; }
+    virtual bool visit(ObjCBaseProtocol *) { return false; }
+    virtual bool visit(ObjCForwardClassDeclaration *) { return false; }
+    virtual bool visit(ObjCForwardProtocolDeclaration *) { return false; }
+    virtual bool visit(ObjCPropertyDeclaration *) { return false; }
+
+    virtual bool visit(ObjCClass *symbol)
+    { return process(symbol); }
+
+    virtual bool visit(ObjCProtocol *symbol)
+    { return process(symbol); }
+
+    virtual bool visit(ObjCMethod *symbol)
+    { return process(symbol); }
+};
+
 class DocumentDiagnosticClient : public DiagnosticClient
 {
     enum { MAX_MESSAGE_COUNT = 10 };
@@ -123,7 +217,7 @@ Document::Document(const QString &fileName)
                                                                       localFileName.size());
     _translationUnit = new TranslationUnit(_control, fileId);
     _translationUnit->setQtMocRunEnabled(true);
-    _translationUnit->setCxxOxEnabled(false);
+    _translationUnit->setCxxOxEnabled(true);
     _translationUnit->setObjCEnabled(true);
     (void) _control->switchTranslationUnit(_translationUnit);
 }
@@ -310,12 +404,20 @@ void Document::setGlobalNamespace(Namespace *globalNamespace)
     _globalNamespace = globalNamespace;
 }
 
-Symbol *Document::findSymbolAt(unsigned line, unsigned column) const
+Scope *Document::scopeAt(unsigned line, unsigned column)
 {
-    return findSymbolAt(line, column, globalSymbols());
+    FindScopeAt findScopeAt(_translationUnit, line, column);
+    if (Scope *scope = findScopeAt(_globalNamespace))
+        return scope;
+    return globalSymbols();
 }
 
-Symbol *Document::findSymbolAt(unsigned line, unsigned column, Scope *scope) const
+Symbol *Document::lastVisibleSymbolAt(unsigned line, unsigned column) const
+{
+    return lastVisibleSymbolAt(line, column, globalSymbols());
+}
+
+Symbol *Document::lastVisibleSymbolAt(unsigned line, unsigned column, Scope *scope) const
 {
     Symbol *previousSymbol = 0;
 
@@ -329,7 +431,7 @@ Symbol *Document::findSymbolAt(unsigned line, unsigned column, Scope *scope) con
 
     if (previousSymbol) {
         if (ScopedSymbol *scoped = previousSymbol->asScopedSymbol()) {
-            if (Symbol *member = findSymbolAt(line, column, scoped->members()))
+            if (Symbol *member = lastVisibleSymbolAt(line, column, scoped->members()))
                 return member;
         }
     }
@@ -545,11 +647,6 @@ Document::Ptr Snapshot::documentFromSource(const QByteArray &preprocessedCode,
     return newDoc;
 }
 
-QSharedPointer<NamespaceBinding> Snapshot::globalNamespaceBinding(Document::Ptr doc) const
-{
-    return CPlusPlus::bind(doc, *this);
-}
-
 Document::Ptr Snapshot::document(const QString &fileName) const
 {
     return _documents.value(fileName);
@@ -576,3 +673,123 @@ void Snapshot::simplified_helper(Document::Ptr doc, Snapshot *snapshot) const
         }
     }
 }
+
+namespace {
+class FindMatchingDefinition: public SymbolVisitor
+{
+    Symbol *_declaration;
+    QList<Function *> _result;
+
+public:
+    FindMatchingDefinition(Symbol *declaration)
+        : _declaration(declaration) {}
+
+    QList<Function *> result() const { return _result; }
+
+    using SymbolVisitor::visit;
+
+    virtual bool visit(Function *fun)
+    {
+        if (_declaration->identifier()->isEqualTo(fun->identifier()))
+            _result.append(fun);
+
+        return false;
+    }
+
+    virtual bool visit(Block *)
+    {
+        return false;
+    }
+};
+} // end of anonymous namespace
+
+Symbol *Snapshot::findMatchingDefinition(Symbol *symbol) const
+{
+    if (! symbol->identifier())
+        return 0;
+
+    Document::Ptr thisDocument = document(QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()));
+    if (! thisDocument) {
+        qWarning() << "undefined document:" << symbol->fileName();
+        return 0;
+    }
+
+    LookupContext thisContext(thisDocument, *this);
+    const QList<Symbol *> declarationCandidates = thisContext.lookup(symbol->name(), symbol->scope());
+    if (declarationCandidates.isEmpty()) {
+        qWarning() << "unresolved declaration:" << symbol->fileName() << symbol->line() << symbol->column();
+        return 0;
+    }
+
+    Symbol *declaration = declarationCandidates.first();
+    Function *declarationTy = declaration->type()->asFunctionType();
+    if (! declarationTy) {
+        qWarning() << "not a function:" << declaration->fileName() << declaration->line() << declaration->column();
+        return 0;
+    }
+
+    foreach (Document::Ptr doc, *this) {
+        if (! doc->control()->findIdentifier(declaration->identifier()->chars(),
+                                             declaration->identifier()->size()))
+            continue;
+
+        FindMatchingDefinition candidates(declaration);
+        candidates.accept(doc->globalNamespace());
+
+        const QList<Function *> result = candidates.result();
+        if (! result.isEmpty()) {
+            LookupContext context(doc, *this);
+
+            QList<Function *> viableFunctions;
+
+            ClassOrNamespace *enclosingType = context.lookupType(declaration);
+            if (! enclosingType)
+                continue; // nothing to do
+
+            foreach (Function *fun, result) {
+                const QList<Symbol *> declarations = context.lookup(fun->name(), fun->scope());
+                if (declarations.isEmpty())
+                    continue;
+
+                else if (enclosingType == context.lookupType(declarations.first()))
+                    viableFunctions.append(fun);
+            }
+
+            if (viableFunctions.isEmpty())
+                continue;
+
+            else if (viableFunctions.length() == 1)
+                return viableFunctions.first();
+
+            Function *best = 0;
+
+            foreach (Function *fun, viableFunctions) {
+                if (fun->identity()->isEqualTo(declaration->identity()))
+                    continue;
+
+                else if (fun->argumentCount() == declarationTy->argumentCount()) {
+                    if (! best)
+                        best = fun;
+
+                    unsigned argc = 0;
+                    for (; argc < declarationTy->argumentCount(); ++argc) {
+                        Symbol *arg = fun->argumentAt(argc);
+                        Symbol *otherArg = declarationTy->argumentAt(argc);
+                        if (! arg->type().isEqualTo(otherArg->type()))
+                            break;
+                    }
+
+                    if (argc == declarationTy->argumentCount())
+                        best = fun;
+                }
+            }
+
+            if (! best)
+                best = viableFunctions.first();
+
+            return best;
+        }
+    }
+
+    return 0;
+}
index f215914..81fcc91 100644 (file)
@@ -42,7 +42,6 @@ namespace CPlusPlus {
 
 class Macro;
 class MacroArgumentReference;
-class NamespaceBinding;
 
 class CPLUSPLUS_EXPORT Document
 {
@@ -93,7 +92,8 @@ public:
     QList<Macro> definedMacros() const
     { return _definedMacros; }
 
-    Symbol *findSymbolAt(unsigned line, unsigned column) const;
+    Symbol *lastVisibleSymbolAt(unsigned line, unsigned column) const;
+    Scope *scopeAt(unsigned line, unsigned column);
 
     QByteArray source() const;
     void setSource(const QByteArray &source);
@@ -310,7 +310,7 @@ public:
     const UndefinedMacroUse *findUndefinedMacroUseAt(unsigned offset) const;
 
 private:
-    Symbol *findSymbolAt(unsigned line, unsigned column, Scope *scope) const;
+    Symbol *lastVisibleSymbolAt(unsigned line, unsigned column, Scope *scope) const;
 
 private:
     QString _fileName;
@@ -365,7 +365,7 @@ public:
     Document::Ptr documentFromSource(const QByteArray &preprocessedCode,
                                      const QString &fileName) const;
 
-    QSharedPointer<NamespaceBinding> globalNamespaceBinding(Document::Ptr doc) const;
+    Symbol *findMatchingDefinition(Symbol *symbol) const;
 
 private:
     void simplified_helper(Document::Ptr doc, Snapshot *snapshot) const;
@@ -27,7 +27,7 @@
 **
 **************************************************************************/
 
-#include "GenTemplateInstance.h"
+#include "DeprecatedGenTemplateInstance.h"
 #include "Overview.h"
 
 #include <Control.h>
@@ -47,10 +47,10 @@ namespace {
 class ApplySubstitution
 {
 public:
-    ApplySubstitution(const LookupContext &context, Symbol *symbol, const GenTemplateInstance::Substitution &substitution);
+    ApplySubstitution(Control *control, Symbol *symbol, const DeprecatedGenTemplateInstance::Substitution &substitution);
     ~ApplySubstitution();
 
-    Control *control() const { return context.control(); }
+    inline Control *control() const { return _control; }
 
     FullySpecifiedType apply(const Name *name);
     FullySpecifiedType apply(const FullySpecifiedType &type);
@@ -309,16 +309,16 @@ private:
     };
 
 public: // attributes
-    LookupContext context;
+    Control *_control;
     Symbol *symbol;
-    GenTemplateInstance::Substitution substitution;
+    DeprecatedGenTemplateInstance::Substitution substitution;
     ApplyToType applyToType;
     ApplyToName applyToName;
 };
 
-ApplySubstitution::ApplySubstitution(const LookupContext &context, Symbol *symbol,
-                                     const GenTemplateInstance::Substitution &substitution)
-    : context(context), symbol(symbol),
+ApplySubstitution::ApplySubstitution(Control *control, Symbol *symbol,
+                                     const DeprecatedGenTemplateInstance::Substitution &substitution)
+    : _control(control), symbol(symbol),
       substitution(substitution),
       applyToType(this), applyToName(this)
 { }
@@ -363,17 +363,43 @@ FullySpecifiedType ApplySubstitution::applySubstitution(int index) const
 
 } // end of anonymous namespace
 
-GenTemplateInstance::GenTemplateInstance(const LookupContext &context, const Substitution &substitution)
+DeprecatedGenTemplateInstance::DeprecatedGenTemplateInstance(Control *control, const Substitution &substitution)
     : _symbol(0),
-      _context(context),
+      _control(control),
       _substitution(substitution)
 { }
 
-FullySpecifiedType GenTemplateInstance::operator()(Symbol *symbol)
+FullySpecifiedType DeprecatedGenTemplateInstance::gen(Symbol *symbol)
 {
-    ApplySubstitution o(_context, symbol, _substitution);
+    ApplySubstitution o(_control, symbol, _substitution);
     return o.apply(symbol->type());
 }
 
-Control *GenTemplateInstance::control() const
-{ return _context.control(); }
+FullySpecifiedType DeprecatedGenTemplateInstance::instantiate(const Name *className, Symbol *candidate, Control *control)
+{
+    if (className) {
+        if (const TemplateNameId *templId = className->asTemplateNameId()) {
+            if (Class *klass = candidate->enclosingSymbol()->asClass()) {
+                DeprecatedGenTemplateInstance::Substitution subst;
+
+                for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) {
+                    FullySpecifiedType templArgTy = templId->templateArgumentAt(i);
+
+                    if (i < klass->templateParameterCount()) {
+                        const Name *templArgName = klass->templateParameterAt(i)->name();
+
+                        if (templArgName && templArgName->identifier()) {
+                            const Identifier *templArgId = templArgName->identifier();
+                            subst.append(qMakePair(templArgId, templArgTy));
+                        }
+                    }
+                }
+
+                DeprecatedGenTemplateInstance inst(control, subst);
+                return inst.gen(candidate);
+            }
+        }
+    }
+
+    return candidate->type();
+}
 **
 **************************************************************************/
 
-#ifndef GENTEMPLATEINSTANCE_H
-#define GENTEMPLATEINSTANCE_H
+#ifndef CPLUSPLUS_DEPRECATEDGENTEMPLATEINSTANCE_H
+#define CPLUSPLUS_DEPRECATEDGENTEMPLATEINSTANCE_H
 
 #include <TypeVisitor.h>
 #include <NameVisitor.h>
 #include <FullySpecifiedType.h>
 
-#include "LookupContext.h"
+#include "DeprecatedLookupContext.h"
 
 #include <QtCore/QList>
 #include <QtCore/QPair>
 
 namespace CPlusPlus {
 
-class CPLUSPLUS_EXPORT GenTemplateInstance
+class CPLUSPLUS_EXPORT DeprecatedGenTemplateInstance
 {
 public:
     typedef QList< QPair<const Identifier *, FullySpecifiedType> > Substitution;
 
 public:
-    GenTemplateInstance(const LookupContext &context, const Substitution &substitution);
+    static FullySpecifiedType instantiate(const Name *className, Symbol *candidate, Control *control);
 
-    FullySpecifiedType operator()(Symbol *symbol);
-
-    Control *control() const;
+private:
+    DeprecatedGenTemplateInstance(Control *control, const Substitution &substitution);
+    FullySpecifiedType gen(Symbol *symbol);
 
 private:
     Symbol *_symbol;
-    LookupContext _context;
+    Control *_control;
     const Substitution _substitution;
 };
 
 } // end of namespace CPlusPlus
 
-#endif // GENTEMPLATEINSTANCE_H
+#endif // CPLUSPLUS_DEPRECATEDGENTEMPLATEINSTANCE_H
diff --git a/src/libs/cplusplus/DeprecatedLookupContext.cpp b/src/libs/cplusplus/DeprecatedLookupContext.cpp
new file mode 100644 (file)
index 0000000..75c71c3
--- /dev/null
@@ -0,0 +1,764 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "DeprecatedLookupContext.h"
+#include "ResolveExpression.h"
+#include "Overview.h"
+#include "CppBindings.h"
+
+#include <CoreTypes.h>
+#include <Symbols.h>
+#include <Literals.h>
+#include <Names.h>
+#include <Scope.h>
+#include <Control.h>
+
+#include <QtDebug>
+
+using namespace CPlusPlus;
+
+/////////////////////////////////////////////////////////////////////
+// LookupContext
+/////////////////////////////////////////////////////////////////////
+DeprecatedLookupContext::DeprecatedLookupContext(Control *control)
+    : _control(control),
+      _symbol(0)
+{ }
+
+DeprecatedLookupContext::DeprecatedLookupContext(Symbol *symbol,
+                             Document::Ptr expressionDocument,
+                             Document::Ptr thisDocument,
+                             const Snapshot &snapshot)
+    : _symbol(symbol),
+      _expressionDocument(expressionDocument),
+      _thisDocument(thisDocument),
+      _snapshot(snapshot)
+{
+    _control = _expressionDocument->control();
+    _visibleScopes = buildVisibleScopes();
+}
+
+bool DeprecatedLookupContext::isValid() const
+{ return _control != 0; }
+
+Control *DeprecatedLookupContext::control() const
+{ return _control; }
+
+Symbol *DeprecatedLookupContext::symbol() const
+{ return _symbol; }
+
+Document::Ptr DeprecatedLookupContext::expressionDocument() const
+{ return _expressionDocument; }
+
+Document::Ptr DeprecatedLookupContext::thisDocument() const
+{ return _thisDocument; }
+
+Document::Ptr DeprecatedLookupContext::document(const QString &fileName) const
+{ return _snapshot.document(fileName); }
+
+Snapshot DeprecatedLookupContext::snapshot() const
+{ return _snapshot; }
+
+bool DeprecatedLookupContext::maybeValidSymbol(Symbol *symbol,
+                                     ResolveMode mode,
+                                     const QList<Symbol *> &candidates)
+{
+    if (((mode & ResolveNamespace)    && symbol->isNamespace())    ||
+        ((mode & ResolveClass)        && symbol->isClass())        ||
+        ((mode & ResolveObjCClass)    && symbol->isObjCClass())    ||
+        ((mode & ResolveObjCProtocol) && symbol->isObjCProtocol()) ||
+         (mode & ResolveSymbol)) {
+        return ! candidates.contains(symbol);
+    }
+
+    return false;
+}
+
+QList<Scope *> DeprecatedLookupContext::resolveNestedNameSpecifier(const QualifiedNameId *q,
+                                                         const QList<Scope *> &visibleScopes) const
+{
+    QList<Symbol *> candidates;
+    QList<Scope *> scopes = visibleScopes;
+
+    for (unsigned i = 0; i < q->nameCount() - 1; ++i) {
+        const Name *name = q->nameAt(i);
+
+        candidates = resolveClassOrNamespace(name, scopes);
+
+        if (candidates.isEmpty())
+            break;
+
+        scopes.clear();
+
+        foreach (Symbol *candidate, candidates) {
+            ScopedSymbol *scoped = candidate->asScopedSymbol();
+            Scope *members = scoped->members();
+
+            if (! scopes.contains(members))
+                scopes.append(members);
+        }
+    }
+
+    return scopes;
+}
+
+QList<Symbol *> DeprecatedLookupContext::resolveQualifiedNameId(const QualifiedNameId *q,
+                                                      const QList<Scope *> &visibleScopes,
+                                                      ResolveMode mode) const
+{
+    QList<Symbol *> candidates;
+
+    if (true || mode & ResolveClass) {
+        for (int i = 0; i < visibleScopes.size(); ++i) {
+            Scope *scope = visibleScopes.at(i);
+
+            for (Symbol *symbol = scope->lookat(q); symbol; symbol = symbol->next()) {
+                if (! symbol->name())
+                    continue;
+                else if (! symbol->isClass())
+                    continue;
+
+                const QualifiedNameId *qq = symbol->name()->asQualifiedNameId();
+
+                if (! qq)
+                    continue;
+                else if (! maybeValidSymbol(symbol, mode, candidates))
+                    continue;
+
+                if (! q->unqualifiedNameId()->isEqualTo(qq->unqualifiedNameId()))
+                    continue;
+
+                else if (qq->nameCount() == q->nameCount()) {
+                    unsigned j = 0;
+
+                    for (; j < q->nameCount(); ++j) {
+                        const Name *classOrNamespaceName1 = q->nameAt(j);
+                        const Name *classOrNamespaceName2 = qq->nameAt(j);
+
+                        if (! classOrNamespaceName1->isEqualTo(classOrNamespaceName2))
+                            break;
+                    }
+
+                    if (j == q->nameCount())
+                        candidates.append(symbol);
+                }
+            }
+        }
+    }
+
+    QList<Scope *> scopes;
+
+    if (q->nameCount() == 1)
+        scopes = visibleScopes;     // ### handle global scope lookup
+    else
+        scopes = resolveNestedNameSpecifier(q, visibleScopes);
+
+    QList<Scope *> expanded;
+    foreach (Scope *scope, scopes) {
+        expanded.append(scope);
+
+        for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+            Symbol *member = scope->symbolAt(i);
+
+            if (ScopedSymbol *scopedSymbol = member->asScopedSymbol())
+                expandEnumOrAnonymousSymbol(scopedSymbol, &expanded);
+        }
+    }
+
+    candidates += resolve(q->unqualifiedNameId(), expanded, mode);
+
+    return candidates;
+}
+
+QList<Symbol *> DeprecatedLookupContext::resolveOperatorNameId(const OperatorNameId *opId,
+                                                     const QList<Scope *> &visibleScopes,
+                                                     ResolveMode) const
+{
+    QList<Symbol *> candidates;
+
+    for (int scopeIndex = 0; scopeIndex < visibleScopes.size(); ++scopeIndex) {
+        Scope *scope = visibleScopes.at(scopeIndex);
+
+        for (Symbol *symbol = scope->lookat(opId->kind()); symbol; symbol = symbol->next()) {
+            if (! opId->isEqualTo(symbol->name()))
+                continue;
+
+            if (! candidates.contains(symbol))
+                candidates.append(symbol);
+        }
+    }
+
+    return candidates;
+}
+
+QList<Symbol *> DeprecatedLookupContext::resolve(const Name *name, const QList<Scope *> &visibleScopes,
+                                       ResolveMode mode) const
+{
+    QList<Symbol *> candidates;
+
+    if (!name)
+        return candidates; // nothing to do, the symbol is anonymous.
+
+    else if (const QualifiedNameId *q = name->asQualifiedNameId())
+        return resolveQualifiedNameId(q, visibleScopes, mode);
+
+    else if (const OperatorNameId *opId = name->asOperatorNameId())
+        return resolveOperatorNameId(opId, visibleScopes, mode);
+
+    else if (const Identifier *id = name->identifier()) {
+        for (int scopeIndex = 0; scopeIndex < visibleScopes.size(); ++scopeIndex) {
+            Scope *scope = visibleScopes.at(scopeIndex);
+
+            for (Symbol *symbol = scope->lookat(id); symbol; symbol = symbol->next()) {
+                if (! symbol->name())
+                    continue; // nothing to do, the symbol is anonymous.
+
+                else if (! maybeValidSymbol(symbol, mode, candidates))
+                    continue; // skip it, we're not looking for this kind of symbols
+
+                else if (const Identifier *symbolId = symbol->identifier()) {
+                    if (! symbolId->isEqualTo(id))
+                        continue; // skip it, the symbol's id is not compatible with this lookup.
+                }
+
+                if (const QualifiedNameId *q = symbol->name()->asQualifiedNameId()) {
+
+                    if (name->isDestructorNameId() != q->unqualifiedNameId()->isDestructorNameId())
+                        continue;
+
+                    else if (q->nameCount() > 1) {
+                        const Name *classOrNamespaceName = control()->qualifiedNameId(q->names(),
+                                                                                      q->nameCount() - 1);
+
+                        if (const Identifier *classOrNamespaceNameId = identifier(classOrNamespaceName)) {
+                            if (classOrNamespaceNameId->isEqualTo(id))
+                                continue;
+                        }
+
+                        const QList<Symbol *> resolvedClassOrNamespace =
+                                resolveClassOrNamespace(classOrNamespaceName, visibleScopes);
+
+                        bool good = false;
+                        foreach (Symbol *classOrNamespace, resolvedClassOrNamespace) {
+                            ScopedSymbol *scoped = classOrNamespace->asScopedSymbol();
+                            if (visibleScopes.contains(scoped->members())) {
+                                good = true;
+                                break;
+                            }
+                        }
+
+                        if (! good)
+                            continue;
+                    }
+                } else if (symbol->name()->isDestructorNameId() != name->isDestructorNameId()) {
+                    // ### FIXME: this is wrong!
+                    continue;
+                }
+
+                if (! candidates.contains(symbol))
+                    candidates.append(symbol);
+            }
+        }
+    }
+
+    return candidates;
+}
+
+const Identifier *DeprecatedLookupContext::identifier(const Name *name) const
+{
+    if (name)
+        return name->identifier();
+
+    return 0;
+}
+
+void DeprecatedLookupContext::buildVisibleScopes_helper(Document::Ptr doc, QList<Scope *> *scopes,
+                                              QSet<QString> *processed)
+{
+    if (doc && ! processed->contains(doc->fileName())) {
+        processed->insert(doc->fileName());
+
+        if (doc->globalSymbolCount())
+            scopes->append(doc->globalSymbols());
+
+        foreach (const Document::Include &incl, doc->includes()) {
+            buildVisibleScopes_helper(_snapshot.document(incl.fileName()),
+                                      scopes, processed);
+        }
+    }
+}
+
+QList<Scope *> DeprecatedLookupContext::buildVisibleScopes()
+{
+    QList<Scope *> scopes;
+
+    if (_symbol) {
+        Scope *scope = _symbol->scope();
+
+        if (Function *fun = _symbol->asFunction())
+            scope = fun->members(); // handle ctor initializers.
+
+        for (; scope; scope = scope->enclosingScope()) {
+            if (scope == _thisDocument->globalSymbols())
+                break;
+
+            scopes.append(scope);
+        }
+    }
+
+    QSet<QString> processed;
+    buildVisibleScopes_helper(_thisDocument, &scopes, &processed);
+
+    while (true) {
+        QList<Scope *> expandedScopes;
+        expand(scopes, &expandedScopes);
+
+        if (expandedScopes.size() == scopes.size())
+            return expandedScopes;
+
+        scopes = expandedScopes;
+    }
+
+    return scopes;
+}
+
+QList<Scope *> DeprecatedLookupContext::visibleScopes(const LookupItem &result) const
+{ return visibleScopes(result.declaration()); }
+
+QList<Scope *> DeprecatedLookupContext::visibleScopes(Symbol *symbol) const
+{
+    QList<Scope *> scopes;
+    if (symbol) {
+        for (Scope *scope = symbol->scope(); scope; scope = scope->enclosingScope())
+            scopes.append(scope);
+    }
+    scopes += visibleScopes();
+    scopes = expand(scopes);
+    return scopes;
+}
+
+void DeprecatedLookupContext::expandEnumOrAnonymousSymbol(ScopedSymbol *scopedSymbol,
+                                                QList<Scope *> *expandedScopes) const
+{
+    if (! scopedSymbol || expandedScopes->contains(scopedSymbol->members()))
+        return;
+
+    Scope *members = scopedSymbol->members();
+
+    if (scopedSymbol->isEnum())
+        expandedScopes->append(members);
+    else if (! scopedSymbol->name() && (scopedSymbol->isClass() || scopedSymbol->isNamespace())) {
+        // anonymous class or namespace
+
+        expandedScopes->append(members);
+
+        for (unsigned i = 0; i < members->symbolCount(); ++i) {
+            Symbol *member = members->symbolAt(i);
+
+            if (ScopedSymbol *nested = member->asScopedSymbol()) {
+                expandEnumOrAnonymousSymbol(nested, expandedScopes);
+            }
+        }
+    }
+}
+
+QList<Scope *> DeprecatedLookupContext::expand(const QList<Scope *> &scopes) const
+{
+    QList<Scope *> expanded;
+    expand(scopes, &expanded);
+    return expanded;
+}
+
+void DeprecatedLookupContext::expand(const QList<Scope *> &scopes, QList<Scope *> *expandedScopes) const
+{
+    for (int i = 0; i < scopes.size(); ++i) {
+        expand(scopes.at(i), scopes, expandedScopes);
+    }
+}
+
+void DeprecatedLookupContext::expandNamespace(Namespace *ns,
+                                    const QList<Scope *> &visibleScopes,
+                                    QList<Scope *> *expandedScopes) const
+{
+    //qDebug() << "*** expand namespace:" << ns->fileName() << ns->line() << ns->column();
+
+    if (Scope *encl = ns->enclosingNamespaceScope())
+        expand(encl, visibleScopes, expandedScopes);
+
+    if (const Name *nsName = ns->name()) {
+        const QList<Symbol *> namespaceList = resolveNamespace(nsName, visibleScopes);
+        foreach (Symbol *otherNs, namespaceList) {
+            if (otherNs == ns)
+                continue;
+            expand(otherNs->asNamespace()->members(), visibleScopes, expandedScopes);
+        }
+    }
+
+    for (unsigned i = 0; i < ns->memberCount(); ++i) { // ### make me fast
+        Symbol *symbol = ns->memberAt(i);
+        if (Namespace *otherNs = symbol->asNamespace()) {
+            if (! otherNs->name()) {
+                expand(otherNs->members(), visibleScopes, expandedScopes);
+            }
+        } else if (UsingNamespaceDirective *u = symbol->asUsingNamespaceDirective()) {
+            const QList<Symbol *> candidates = resolveNamespace(u->name(), visibleScopes);
+            for (int j = 0; j < candidates.size(); ++j) {
+                expand(candidates.at(j)->asNamespace()->members(),
+                       visibleScopes, expandedScopes);
+            }
+        } else if (Enum *e = symbol->asEnum()) {
+            expand(e->members(), visibleScopes, expandedScopes);
+        }
+    }
+}
+
+void DeprecatedLookupContext::expandClass(Class *klass,
+                                const QList<Scope *> &visibleScopes,
+                                QList<Scope *> *expandedScopes) const
+{
+    for (TemplateParameters *params = klass->templateParameters(); params; params = params->previous())
+        expand(params->scope(), visibleScopes, expandedScopes);
+
+    for (unsigned i = 0; i < klass->memberCount(); ++i) {
+        Symbol *symbol = klass->memberAt(i);
+        if (Class *nestedClass = symbol->asClass()) {
+            if (! nestedClass->name()) {
+                expand(nestedClass->members(), visibleScopes, expandedScopes);
+            }
+        } else if (Enum *e = symbol->asEnum()) {
+            expand(e->members(), visibleScopes, expandedScopes);
+        }
+    }
+
+    if (klass->baseClassCount()) {
+        QList<Scope *> classVisibleScopes = visibleScopes;
+        for (Scope *scope = klass->scope(); scope; scope = scope->enclosingScope()) {
+            if (scope->isNamespaceScope()) {
+                Namespace *enclosingNamespace = scope->owner()->asNamespace();
+                if (enclosingNamespace->name()) {
+                    const QList<Symbol *> nsList = resolveNamespace(enclosingNamespace->name(),
+                                                                    visibleScopes);
+                    foreach (Symbol *ns, nsList) {
+                        expand(ns->asNamespace()->members(), classVisibleScopes,
+                               &classVisibleScopes);
+                    }
+                }
+            }
+        }
+
+        for (unsigned i = 0; i < klass->baseClassCount(); ++i) {
+            BaseClass *baseClass = klass->baseClassAt(i);
+            const Name *baseClassName = baseClass->name();
+            const QList<Symbol *> baseClassCandidates = resolveClass(baseClassName,
+                                                                     classVisibleScopes);
+
+            for (int j = 0; j < baseClassCandidates.size(); ++j) {
+                if (Class *baseClassSymbol = baseClassCandidates.at(j)->asClass())
+                    expand(baseClassSymbol->members(), visibleScopes, expandedScopes);
+            }
+        }
+    }
+}
+
+void DeprecatedLookupContext::expandBlock(Block *blockSymbol,
+                                const QList<Scope *> &visibleScopes,
+                                QList<Scope *> *expandedScopes) const
+{
+    for (unsigned i = 0; i < blockSymbol->memberCount(); ++i) {
+        Symbol *symbol = blockSymbol->memberAt(i);
+        if (UsingNamespaceDirective *u = symbol->asUsingNamespaceDirective()) {
+            const QList<Symbol *> candidates = resolveNamespace(u->name(),
+                                                                visibleScopes);
+            for (int j = 0; j < candidates.size(); ++j) {
+                expand(candidates.at(j)->asNamespace()->members(),
+                       visibleScopes, expandedScopes);
+            }
+        }
+
+    }
+}
+
+void DeprecatedLookupContext::expandFunction(Function *function,
+                                   const QList<Scope *> &visibleScopes,
+                                   QList<Scope *> *expandedScopes) const
+{
+    for (TemplateParameters *params = function->templateParameters(); params; params = params->previous())
+        expand(params->scope(), visibleScopes, expandedScopes);
+
+    if (! expandedScopes->contains(function->arguments()))
+        expandedScopes->append(function->arguments());
+
+    if (const QualifiedNameId *q = function->name()->asQualifiedNameId()) {
+        const Name *nestedNameSpec = 0;
+        if (q->nameCount() == 1)
+            nestedNameSpec = q->nameAt(0);
+        else
+            nestedNameSpec = control()->qualifiedNameId(q->names(), q->nameCount() - 1,
+                                                        q->isGlobal());
+        const QList<Symbol *> candidates = resolveClassOrNamespace(nestedNameSpec, visibleScopes);
+        for (int j = 0; j < candidates.size(); ++j) {
+            if (ScopedSymbol *scopedSymbol = candidates.at(j)->asScopedSymbol())
+                expand(scopedSymbol->members(), visibleScopes, expandedScopes);
+        }
+    }
+}
+
+void DeprecatedLookupContext::expandObjCMethod(ObjCMethod *method,
+                                     const QList<Scope *> &,
+                                     QList<Scope *> *expandedScopes) const
+{
+    if (! expandedScopes->contains(method->arguments()))
+        expandedScopes->append(method->arguments());
+}
+
+void DeprecatedLookupContext::expandObjCClass(ObjCClass *klass,
+                                    const QList<Scope *> &visibleScopes,
+                                    QList<Scope *> *expandedScopes) const
+{
+    {// expand other @interfaces, @implementations and categories for this class:
+        const QList<Symbol *> classList = resolveObjCClass(klass->name(), visibleScopes);
+        foreach (Symbol *otherClass, classList) {
+            if (otherClass == klass)
+                continue;
+            expand(otherClass->asObjCClass()->members(), visibleScopes, expandedScopes);
+        }
+    }
+
+    // expand definitions in the currect class:
+    for (unsigned i = 0; i < klass->memberCount(); ++i) {
+        Symbol *symbol = klass->memberAt(i);
+        if (Class *nestedClass = symbol->asClass()) {
+            if (! nestedClass->name()) {
+                expand(nestedClass->members(), visibleScopes, expandedScopes);
+            }
+        } else if (Enum *e = symbol->asEnum()) {
+            expand(e->members(), visibleScopes, expandedScopes);
+        }
+    }
+
+    // expand the base class:
+    if (ObjCBaseClass *baseClass = klass->baseClass()) {
+        const Name *baseClassName = baseClass->name();
+        const QList<Symbol *> baseClassCandidates = resolveObjCClass(baseClassName,
+                                                                     visibleScopes);
+
+        for (int j = 0; j < baseClassCandidates.size(); ++j) {
+            if (ObjCClass *baseClassSymbol = baseClassCandidates.at(j)->asObjCClass())
+                expand(baseClassSymbol->members(), visibleScopes, expandedScopes);
+        }
+    }
+
+    // expand the protocols:
+    for (unsigned i = 0; i < klass->protocolCount(); ++i) {
+        const Name *protocolName = klass->protocolAt(i)->name();
+        const QList<Symbol *> protocolCandidates = resolveObjCProtocol(protocolName, visibleScopes);
+        for (int j = 0; j < protocolCandidates.size(); ++j) {
+            if (ObjCProtocol *protocolSymbol = protocolCandidates.at(j)->asObjCProtocol())
+                expandObjCProtocol(protocolSymbol, visibleScopes, expandedScopes);
+        }
+    }
+}
+
+void DeprecatedLookupContext::expandObjCProtocol(ObjCProtocol *protocol, const QList<Scope *> &visibleScopes, QList<Scope *> *expandedScopes) const
+{
+    // First expand the protocol itself
+    expand(protocol->members(), visibleScopes, expandedScopes);
+
+    // Then do the same for any incorporated protocol
+    for (unsigned i = 0; i < protocol->protocolCount(); ++i) {
+        ObjCBaseProtocol *baseProtocol = protocol->protocolAt(i);
+        const QList<Symbol *> protocolList = resolveObjCProtocol(baseProtocol->name(), visibleScopes);
+        foreach (Symbol *symbol, protocolList)
+            if (ObjCProtocol *protocolSymbol = symbol->asObjCProtocol())
+                expandObjCProtocol(protocolSymbol, visibleScopes, expandedScopes);
+    }
+}
+
+void DeprecatedLookupContext::expand(Scope *scope,
+                           const QList<Scope *> &visibleScopes,
+                           QList<Scope *> *expandedScopes) const
+{
+    if (expandedScopes->contains(scope))
+        return;
+
+    expandedScopes->append(scope);
+
+    if (Namespace *ns = scope->owner()->asNamespace()) {
+        expandNamespace(ns, visibleScopes, expandedScopes);
+    } else if (Class *klass = scope->owner()->asClass()) {
+        expandClass(klass, visibleScopes, expandedScopes);
+    } else if (Block *block = scope->owner()->asBlock()) {
+        expandBlock(block, visibleScopes, expandedScopes);
+    } else if (Function *fun = scope->owner()->asFunction()) {
+        expandFunction(fun, visibleScopes, expandedScopes);
+    } else if (ObjCMethod *meth = scope->owner()->asObjCMethod()) {
+        expandObjCMethod(meth, visibleScopes, expandedScopes);
+    } else if (ObjCClass *objcKlass = scope->owner()->asObjCClass()) {
+        expandObjCClass(objcKlass, visibleScopes, expandedScopes);
+    }
+}
+
+static void visibleClassBindings_helper(ClassBinding *classBinding,
+                                        QList<ClassBinding *> *allClassBindings,
+                                        QSet<ClassBinding *> *processed)
+{
+    if (! classBinding)
+        return;
+
+    else if (processed->contains(classBinding))
+        return;
+
+    processed->insert(classBinding);
+
+    foreach (ClassBinding *baseClassBinding, classBinding->baseClassBindings)
+        visibleClassBindings_helper(baseClassBinding, allClassBindings, processed);
+
+    allClassBindings->append(classBinding);
+}
+
+static QList<ClassBinding *> visibleClassBindings(Symbol *symbol, NamespaceBinding *globalNamespace)
+{
+    QList<ClassBinding *> classBindings;
+
+    if (! symbol)
+        return classBindings;
+
+    else if (Class *klass = symbol->asClass()) {
+        QSet<ClassBinding *> processed;
+
+        visibleClassBindings_helper(NamespaceBinding::find(klass, globalNamespace),
+                                    &classBindings, &processed);
+    }
+
+    return classBindings;
+}
+
+Symbol *DeprecatedLookupContext::canonicalSymbol(Symbol *symbol,
+                                       NamespaceBinding *globalNamespace)
+{
+    Symbol *canonicalSymbol = DeprecatedLookupContext::canonicalSymbol(symbol);
+    if (! canonicalSymbol)
+        return 0;
+
+    if (const Identifier *symbolId = canonicalSymbol->identifier()) {
+        if (symbolId && canonicalSymbol->type()->isFunctionType()) {
+            Class *enclosingClass = canonicalSymbol->scope()->owner()->asClass();
+            const QList<ClassBinding *> classBindings = visibleClassBindings(enclosingClass, globalNamespace);
+
+            foreach (ClassBinding *baseClassBinding, classBindings) {
+                if (! baseClassBinding)
+                    continue;
+
+                foreach (Class *baseClass, baseClassBinding->symbols) {
+                    if (! baseClass)
+                        continue;
+
+                    for (Symbol *c = baseClass->members()->lookat(symbolId); c; c = c->next()) {
+                        if (! symbolId->isEqualTo(c->identifier()))
+                            continue;
+                        else if (Function *f = c->type()->asFunctionType()) {
+                            if (f->isVirtual())
+                                return DeprecatedLookupContext::canonicalSymbol(f);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return canonicalSymbol;
+}
+
+Symbol *DeprecatedLookupContext::canonicalSymbol(const QList<Symbol *> &candidates,
+                                       NamespaceBinding *globalNamespaceBinding)
+{
+    if (candidates.isEmpty())
+        return 0;
+
+    return canonicalSymbol(candidates.first(), globalNamespaceBinding);
+}
+
+Symbol *DeprecatedLookupContext::canonicalSymbol(const QList<LookupItem> &results,
+                                       NamespaceBinding *globalNamespaceBinding)
+{
+    QList<Symbol *> candidates;
+
+    foreach (const LookupItem &result, results)
+        candidates.append(result.declaration()); // ### not exactly.
+
+    return canonicalSymbol(candidates, globalNamespaceBinding);
+}
+
+
+Symbol *DeprecatedLookupContext::canonicalSymbol(Symbol *symbol)
+{
+    Symbol *canonical = symbol;
+    Class *canonicalClass = 0;
+    ObjCClass *canonicalObjCClass = 0;
+    ObjCProtocol *canonicalObjCProto = 0;
+
+    for (; symbol; symbol = symbol->next()) {
+        if (symbol->identifier() == canonical->identifier()) {
+            canonical = symbol;
+
+            if (Class *klass = symbol->asClass())
+                canonicalClass = klass;
+            else if (ObjCClass *clazz = symbol->asObjCClass())
+                canonicalObjCClass = clazz;
+            else if (ObjCProtocol *proto = symbol->asObjCProtocol())
+                canonicalObjCProto = proto;
+        }
+    }
+
+    if (canonicalClass) {
+        Q_ASSERT(canonical != 0);
+
+        if (canonical->isForwardClassDeclaration())
+            return canonicalClass; // prefer class declarations when available.
+    } else if (canonicalObjCClass) {
+        Q_ASSERT(canonical != 0);
+
+        if (canonical->isObjCForwardClassDeclaration())
+            return canonicalObjCClass;
+    } else if (canonicalObjCProto) {
+        Q_ASSERT(canonical != 0);
+
+        if (canonical->isObjCForwardProtocolDeclaration())
+            return canonicalObjCProto;
+    }
+
+    if (canonical && canonical->scope()->isClassScope()) {
+        Class *enclosingClass = canonical->scope()->owner()->asClass();
+
+        if (enclosingClass->identifier() == canonical->identifier())
+            return enclosingClass;
+    }
+
+    return canonical;
+}
diff --git a/src/libs/cplusplus/DeprecatedLookupContext.h b/src/libs/cplusplus/DeprecatedLookupContext.h
new file mode 100644 (file)
index 0000000..19d63e3
--- /dev/null
@@ -0,0 +1,205 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef CPLUSPLUS_DEPRECATEDLOOKUPCONTEXT_H
+#define CPLUSPLUS_DEPRECATEDLOOKUPCONTEXT_H
+
+#include "CppDocument.h"
+#include "LookupItem.h"
+#include <FullySpecifiedType.h>
+
+namespace CPlusPlus {
+
+class NamespaceBinding;
+
+class CPLUSPLUS_EXPORT DeprecatedLookupContext
+{
+public:
+    DeprecatedLookupContext(Control *control = 0);
+
+    DeprecatedLookupContext(Symbol *symbol,
+                  Document::Ptr expressionDocument,
+                  Document::Ptr thisDocument,
+                  const Snapshot &snapshot);
+
+    bool isValid() const;
+
+    Control *control() const;
+    Symbol *symbol() const;
+    Document::Ptr expressionDocument() const;
+    Document::Ptr thisDocument() const;
+    Document::Ptr document(const QString &fileName) const;
+    Snapshot snapshot() const;
+
+    static Symbol *canonicalSymbol(const QList<Symbol *> &candidates,
+                                   NamespaceBinding *globalNamespaceBinding);
+
+    static Symbol *canonicalSymbol(Symbol *symbol,
+                                   NamespaceBinding *globalNamespaceBinding);
+
+    static Symbol *canonicalSymbol(const QList<LookupItem> &candidates,
+                                   NamespaceBinding *globalNamespaceBinding);
+
+    QList<Symbol *> resolve(const Name *name) const
+    { return resolve(name, visibleScopes()); }
+
+    QList<Symbol *> resolveNamespace(const Name *name) const
+    { return resolveNamespace(name, visibleScopes()); }
+
+    QList<Symbol *> resolveClass(const Name *name) const
+    { return resolveClass(name, visibleScopes()); }
+
+    QList<Symbol *> resolveClassOrNamespace(const Name *name) const
+    { return resolveClassOrNamespace(name, visibleScopes()); }
+
+    QList<Symbol *> resolveObjCClass(const Name *name) const
+    { return resolveObjCClass(name, visibleScopes()); }
+
+    QList<Symbol *> resolveObjCProtocol(const Name *name) const
+    { return resolveObjCProtocol(name, visibleScopes()); }
+
+    enum ResolveMode {
+        ResolveSymbol           = 0x01,
+        ResolveClass            = 0x02,
+        ResolveNamespace        = 0x04,
+        ResolveClassOrNamespace = ResolveClass  | ResolveNamespace,
+        ResolveObjCClass        = 0x08,
+        ResolveObjCProtocol     = 0x10,
+        ResolveAll              = ResolveSymbol | ResolveClassOrNamespace | ResolveObjCClass | ResolveObjCProtocol
+    };
+
+    QList<Symbol *> resolve(const Name *name, const QList<Scope *> &visibleScopes,
+                            ResolveMode mode = ResolveAll) const;
+
+    QList<Symbol *> resolveNamespace(const Name *name, const QList<Scope *> &visibleScopes) const
+    { return resolve(name, visibleScopes, ResolveNamespace); }
+
+    QList<Symbol *> resolveClass(const Name *name, const QList<Scope *> &visibleScopes) const
+    { return resolve(name, visibleScopes, ResolveClass); }
+
+    QList<Symbol *> resolveClassOrNamespace(const Name *name, const QList<Scope *> &visibleScopes) const
+    { return resolve(name, visibleScopes, ResolveClassOrNamespace); }
+
+    QList<Symbol *> resolveObjCClass(const Name *name, const QList<Scope *> &visibleScopes) const
+    { return resolve(name, visibleScopes, ResolveObjCClass); }
+
+    QList<Symbol *> resolveObjCProtocol(const Name *name, const QList<Scope *> &visibleScopes) const
+    { return resolve(name, visibleScopes, ResolveObjCProtocol); }
+
+    QList<Scope *> visibleScopes() const
+    { return _visibleScopes; }
+
+    QList<Scope *> visibleScopes(Symbol *symbol) const;
+    QList<Scope *> visibleScopes(const LookupItem &result) const;
+
+    QList<Scope *> expand(const QList<Scope *> &scopes) const;
+
+    void expand(const QList<Scope *> &scopes, QList<Scope *> *expandedScopes) const;
+
+    void expand(Scope *scope, const QList<Scope *> &visibleScopes,
+                QList<Scope *> *expandedScopes) const;
+
+    void expandNamespace(Namespace *namespaceSymbol,
+                         const QList<Scope *> &visibleScopes,
+                         QList<Scope *> *expandedScopes) const;
+
+    void expandClass(Class *classSymbol,
+                     const QList<Scope *> &visibleScopes,
+                     QList<Scope *> *expandedScopes) const;
+
+    void expandBlock(Block *blockSymbol,
+                     const QList<Scope *> &visibleScopes,
+                     QList<Scope *> *expandedScopes) const;
+
+    void expandFunction(Function *functionSymbol,
+                        const QList<Scope *> &visibleScopes,
+                        QList<Scope *> *expandedScopes) const;
+
+    void expandObjCMethod(ObjCMethod *method,
+                          const QList<Scope *> &visibleScopes,
+                          QList<Scope *> *expandedScopes) const;
+
+    void expandObjCClass(ObjCClass *klass,
+                         const QList<Scope *> &visibleScopes,
+                         QList<Scope *> *expandedScopes) const;
+
+    void expandObjCProtocol(ObjCProtocol *protocol,
+                            const QList<Scope *> &visibleScopes,
+                            QList<Scope *> *expandedScopes) const;
+
+    void expandEnumOrAnonymousSymbol(ScopedSymbol *scopedSymbol,
+                                     QList<Scope *> *expandedScopes) const;
+
+private:
+    static Symbol *canonicalSymbol(Symbol *symbol);
+
+    QList<Symbol *> resolveQualifiedNameId(const QualifiedNameId *q,
+                                           const QList<Scope *> &visibleScopes,
+                                           ResolveMode mode) const;
+
+    QList<Symbol *> resolveOperatorNameId(const OperatorNameId *opId,
+                                          const QList<Scope *> &visibleScopes,
+                                          ResolveMode mode) const;
+
+    QList<Scope *> resolveNestedNameSpecifier(const QualifiedNameId *q,
+                                               const QList<Scope *> &visibleScopes) const;
+
+    const Identifier *identifier(const Name *name) const;
+
+    QList<Scope *> buildVisibleScopes();
+
+    void buildVisibleScopes_helper(Document::Ptr doc, QList<Scope *> *scopes,
+                                   QSet<QString> *processed);
+
+    static bool maybeValidSymbol(Symbol *symbol,
+                                 ResolveMode mode,
+                                 const QList<Symbol *> &candidates);
+
+private:
+    Control *_control;
+
+    // The current symbol.
+    Symbol *_symbol;
+
+    // The current expression.
+    Document::Ptr _expressionDocument;
+
+    // The current document.
+    Document::Ptr _thisDocument;
+
+    // All documents.
+    Snapshot _snapshot;
+
+    // Visible scopes.
+    QList<Scope *> _visibleScopes;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // CPLUSPLUS_DEPRECATEDLOOKUPCONTEXT_H
index 7425fb5..6c52a02 100644 (file)
@@ -28,7 +28,7 @@
 **************************************************************************/
 
 #include "FindUsages.h"
-#include "TypeOfExpression.h"
+#include "DeprecatedLookupContext.h"
 
 #include <Control.h>
 #include <Literals.h>
@@ -46,12 +46,14 @@ FindUsages::FindUsages(Document::Ptr doc, const Snapshot &snapshot)
     : ASTVisitor(doc->translationUnit()),
       _doc(doc),
       _snapshot(snapshot),
+      _context(doc, snapshot),
       _source(_doc->source()),
       _sem(doc->translationUnit()),
       _inSimpleDeclaration(0),
       _inQProperty(false)
 {
     _snapshot.insert(_doc);
+    typeofExpression.init(_doc, _snapshot, _context.bindings());
 }
 
 void FindUsages::setGlobalNamespaceBinding(NamespaceBindingPtr globalNamespaceBinding)
@@ -105,6 +107,14 @@ QString FindUsages::matchingLine(const Token &tk) const
     return matchingLine;
 }
 
+Scope *FindUsages::scopeAt(unsigned tokenIndex) const
+{
+    TranslationUnit *unit = _doc->translationUnit();
+    unsigned line, column;
+    unit->getTokenPosition(tokenIndex, &line, &column);
+    return _doc->scopeAt(line, column);
+}
+
 void FindUsages::reportResult(unsigned tokenIndex, const QList<Symbol *> &candidates)
 {
     if (_processed.contains(tokenIndex))
@@ -141,7 +151,7 @@ void FindUsages::reportResult(unsigned tokenIndex)
 
 bool FindUsages::checkCandidates(const QList<Symbol *> &candidates) const
 {
-    if (Symbol *canonicalSymbol = LookupContext::canonicalSymbol(candidates, _globalNamespaceBinding.data())) {
+    if (Symbol *canonicalSymbol = DeprecatedLookupContext::canonicalSymbol(candidates, _globalNamespaceBinding.data())) {
 
 #if 0
         Symbol *c = candidates.first();
@@ -201,27 +211,6 @@ bool FindUsages::checkSymbol(Symbol *symbol) const
     return false;
 }
 
-LookupContext FindUsages::currentContext(AST *ast)
-{
-    unsigned line, column;
-    getTokenStartPosition(ast->firstToken(), &line, &column);
-    Symbol *lastVisibleSymbol = _doc->findSymbolAt(line, column);
-
-    if (_inQProperty && lastVisibleSymbol->isClass()) {
-        Scope *memberScope = lastVisibleSymbol->asClass()->members();
-
-        if (unsigned count = memberScope->symbolCount())
-            lastVisibleSymbol = memberScope->symbolAt(count - 1);
-    }
-
-    if (lastVisibleSymbol && lastVisibleSymbol == _previousContext.symbol())
-        return _previousContext;
-
-    LookupContext ctx(lastVisibleSymbol, _exprDoc, _doc, _snapshot);
-    _previousContext = ctx;
-    return _previousContext;
-}
-
 void FindUsages::ensureNameIsValid(NameAST *ast)
 {
     if (ast && ! ast->name)
@@ -235,8 +224,7 @@ bool FindUsages::visit(MemInitializerAST *ast)
 
         SimpleNameAST *simple = ast->name->asSimpleName();
         if (identifier(simple->identifier_token) == _id) {
-            LookupContext context = currentContext(ast);
-            const QList<Symbol *> candidates = context.resolve(simple->name);
+            const QList<Symbol *> candidates = _context.lookup(simple->name, scopeAt(simple->identifier_token));
             reportResult(simple->identifier_token, candidates);
         }
     }
@@ -281,20 +269,17 @@ void FindUsages::checkExpression(unsigned startToken, unsigned endToken)
     const QString expression = _source.mid(begin, end - begin);
     // qDebug() << "*** check expression:" << expression;
 
-    TypeOfExpression typeofExpression;
-    typeofExpression.setSnapshot(_snapshot);
-
     unsigned line, column;
     getTokenStartPosition(startToken, &line, &column);
-    Symbol *lastVisibleSymbol = _doc->findSymbolAt(line, column);
+    Scope *scope = _doc->scopeAt(line, column);
 
-    const QList<LookupItem> results = typeofExpression(expression, _doc, lastVisibleSymbol,
-                                                   TypeOfExpression::Preprocess);
+    const QList<LookupItem> results = typeofExpression(expression, scope,
+                                                       TypeOfExpression::Preprocess);
 
     QList<Symbol *> candidates;
 
     foreach (const LookupItem &r, results) {
-        Symbol *lastVisibleSymbol = r.lastVisibleSymbol();
+        Symbol *lastVisibleSymbol = r.declaration();
         candidates.append(lastVisibleSymbol);
     }
 
@@ -365,8 +350,7 @@ bool FindUsages::visit(EnumeratorAST *ast)
 {
     const Identifier *id = identifier(ast->identifier_token);
     if (id == _id) {
-        LookupContext context = currentContext(ast);
-        const QList<Symbol *> candidates = context.resolve(control()->nameId(id));
+        const QList<Symbol *> candidates = _context.lookup(control()->nameId(id), scopeAt(ast->identifier_token));
         reportResult(ast->identifier_token, candidates);
     }
 
@@ -379,8 +363,7 @@ bool FindUsages::visit(SimpleNameAST *ast)
 {
     const Identifier *id = identifier(ast->identifier_token);
     if (id == _id) {
-        LookupContext context = currentContext(ast);
-        const QList<Symbol *> candidates = context.resolve(ast->name);
+        const QList<Symbol *> candidates = _context.lookup(ast->name, scopeAt(ast->identifier_token));
         reportResult(ast->identifier_token, candidates);
     }
 
@@ -391,8 +374,7 @@ bool FindUsages::visit(DestructorNameAST *ast)
 {
     const Identifier *id = identifier(ast->identifier_token);
     if (id == _id) {
-        LookupContext context = currentContext(ast);
-        const QList<Symbol *> candidates = context.resolve(ast->name);
+        const QList<Symbol *> candidates = _context.lookup(ast->name, scopeAt(ast->identifier_token));
         reportResult(ast->identifier_token, candidates);
     }
 
@@ -402,8 +384,7 @@ bool FindUsages::visit(DestructorNameAST *ast)
 bool FindUsages::visit(TemplateIdAST *ast)
 {
     if (_id == identifier(ast->identifier_token)) {
-        LookupContext context = currentContext(ast);
-        const QList<Symbol *> candidates = context.resolve(ast->name);
+        const QList<Symbol *> candidates = _context.lookup(ast->name, scopeAt(ast->identifier_token));
         reportResult(ast->identifier_token, candidates);
     }
 
@@ -478,8 +459,7 @@ bool FindUsages::visit(ObjCSelectorAST *ast)
     if (ast->name) {
         const Identifier *id = ast->name->identifier();
         if (id == _id) {
-            LookupContext context = currentContext(ast);
-            const QList<Symbol *> candidates = context.resolve(ast->name);
+            const QList<Symbol *> candidates = _context.lookup(ast->name, scopeAt(ast->firstToken()));
             reportResult(ast->firstToken(), candidates);
         }
     }
index 176553b..97729fd 100644 (file)
@@ -34,6 +34,7 @@
 #include "CppDocument.h"
 #include "CppBindings.h"
 #include "Semantic.h"
+#include "TypeOfExpression.h"
 #include <ASTVisitor.h>
 #include <QtCore/QSet>
 
@@ -73,6 +74,7 @@ protected:
     using ASTVisitor::endVisit;
 
     QString matchingLine(const Token &tk) const;
+    Scope *scopeAt(unsigned tokenIndex) const;
 
     void reportResult(unsigned tokenIndex, const QList<Symbol *> &candidates);
     void reportResult(unsigned tokenIndex);
@@ -82,8 +84,6 @@ protected:
     bool checkScope(Symbol *symbol, Symbol *otherSymbol) const;
     void checkExpression(unsigned startToken, unsigned endToken);
 
-    LookupContext currentContext(AST *ast);
-
     void ensureNameIsValid(NameAST *ast);
 
     virtual bool visit(MemInitializerAST *ast);
@@ -108,6 +108,7 @@ private:
     Symbol *_declSymbol;
     Document::Ptr _doc;
     Snapshot _snapshot;
+    LookupContext _context;
     QByteArray _source;
     Document::Ptr _exprDoc;
     Semantic _sem;
@@ -116,10 +117,10 @@ private:
     QList<QualifiedNameAST *> _qualifiedNameStack;
     QList<int> _references;
     QList<Usage> _usages;
-    LookupContext _previousContext;
     int _inSimpleDeclaration;
     bool _inQProperty;
     QSet<unsigned> _processed;
+    TypeOfExpression typeofExpression;
 };
 
 } // end of namespace CPlusPlus
index 93b1c07..ec1a086 100644 (file)
@@ -31,6 +31,7 @@
 #include "ResolveExpression.h"
 #include "Overview.h"
 #include "CppBindings.h"
+#include "DeprecatedGenTemplateInstance.h"
 
 #include <CoreTypes.h>
 #include <Symbols.h>
 
 #include <QtDebug>
 
-uint CPlusPlus::qHash(const CPlusPlus::LookupItem &key)
-{
-    const uint h1 = QT_PREPEND_NAMESPACE(qHash)(key.type().type());
-    const uint h2 = QT_PREPEND_NAMESPACE(qHash)(key.lastVisibleSymbol());
-    return ((h1 << 16) | (h1 >> 16)) ^ h2;
+namespace {
+    const bool debug = ! qgetenv("CPLUSPLUS_LOOKUPCONTEXT_DEBUG").isEmpty();
 }
 
 using namespace CPlusPlus;
 
+static void fullyQualifiedName_helper(Symbol *symbol, QList<const Name *> *names)
+{
+    if (! symbol)
+        return;
+
+    fullyQualifiedName_helper(symbol->enclosingSymbol(), names);
+
+    if (symbol->name()) {
+        if (symbol->isClass() || symbol->isNamespace()) {
+            if (const QualifiedNameId *q = symbol->name()->asQualifiedNameId()) {
+                for (unsigned i = 0; i < q->nameCount(); ++i)
+                    names->append(q->nameAt(i));
+
+            } else if (symbol->name()->isNameId() || symbol->name()->isTemplateNameId()) {
+                names->append(symbol->name());
+            }
+        } else if (symbol->isObjCClass() || symbol->isObjCBaseClass() || symbol->isObjCProtocol()
+                || symbol->isObjCForwardClassDeclaration() || symbol->isObjCForwardProtocolDeclaration()) {
+            if (symbol->name())
+                names->append(symbol->name());
+        } else if (symbol->isFunction()) {
+            if (const QualifiedNameId *q = symbol->name()->asQualifiedNameId()) {
+                for (unsigned i = 0; i < q->nameCount() - 1; ++i)
+                    names->append(q->nameAt(i));
+            }
+        }
+    }
+}
+
+bool ClassOrNamespace::CompareName::operator()(const Name *name, const Name *other) const
+{
+    Q_ASSERT(name != 0);
+    Q_ASSERT(other != 0);
+
+    const Identifier *id = name->identifier();
+    const Identifier *otherId = other->identifier();
+    return strcmp(id->chars(), otherId->chars()) < 0;
+}
+
 /////////////////////////////////////////////////////////////////////
 // LookupContext
 /////////////////////////////////////////////////////////////////////
-LookupContext::LookupContext(Control *control)
-    : _control(control),
-      _symbol(0)
+LookupContext::LookupContext()
 { }
 
-LookupContext::LookupContext(Symbol *symbol,
-                             Document::Ptr expressionDocument,
+LookupContext::LookupContext(Document::Ptr thisDocument,
+                             const Snapshot &snapshot)
+    : _expressionDocument(Document::create("<LookupContext>")),
+      _thisDocument(thisDocument),
+      _snapshot(snapshot)
+{
+}
+
+LookupContext::LookupContext(Document::Ptr expressionDocument,
                              Document::Ptr thisDocument,
                              const Snapshot &snapshot)
-    : _symbol(symbol),
-      _expressionDocument(expressionDocument),
+    : _expressionDocument(expressionDocument),
       _thisDocument(thisDocument),
       _snapshot(snapshot)
 {
-    _control = _expressionDocument->control();
-    _visibleScopes = buildVisibleScopes();
 }
 
-bool LookupContext::isValid() const
-{ return _control != 0; }
+LookupContext::LookupContext(const LookupContext &other)
+    : _expressionDocument(other._expressionDocument),
+      _thisDocument(other._thisDocument),
+      _snapshot(other._snapshot),
+      _bindings(other._bindings)
+{ }
 
-Control *LookupContext::control() const
-{ return _control; }
+LookupContext &LookupContext::operator = (const LookupContext &other)
+{
+    _expressionDocument = other._expressionDocument;
+    _thisDocument = other._thisDocument;
+    _snapshot = other._snapshot;
+    _bindings = other._bindings;
+    return *this;
+}
+
+QList<const Name *> LookupContext::fullyQualifiedName(Symbol *symbol)
+{
+    QList<const Name *> names;
+    fullyQualifiedName_helper(symbol, &names);
+    return names;
+}
+
+QSharedPointer<CreateBindings> LookupContext::bindings() const
+{
+    if (! _bindings)
+        _bindings = QSharedPointer<CreateBindings>(new CreateBindings(_thisDocument, _snapshot));
+
+    return _bindings;
+}
 
-Symbol *LookupContext::symbol() const
-{ return _symbol; }
+void LookupContext::setBindings(QSharedPointer<CreateBindings> bindings)
+{
+    _bindings = bindings;
+}
+
+Control *LookupContext::control() const
+{ return bindings()->control(); }
 
 Document::Ptr LookupContext::expressionDocument() const
 { return _expressionDocument; }
@@ -92,680 +161,694 @@ Document::Ptr LookupContext::document(const QString &fileName) const
 Snapshot LookupContext::snapshot() const
 { return _snapshot; }
 
-bool LookupContext::maybeValidSymbol(Symbol *symbol,
-                                     ResolveMode mode,
-                                     const QList<Symbol *> &candidates)
+ClassOrNamespace *LookupContext::globalNamespace() const
 {
-    if (((mode & ResolveNamespace)    && symbol->isNamespace())    ||
-        ((mode & ResolveClass)        && symbol->isClass())        ||
-        ((mode & ResolveObjCClass)    && symbol->isObjCClass())    ||
-        ((mode & ResolveObjCProtocol) && symbol->isObjCProtocol()) ||
-         (mode & ResolveSymbol)) {
-        return ! candidates.contains(symbol);
-    }
-
-    return false;
+    return bindings()->globalNamespace();
 }
 
-QList<Scope *> LookupContext::resolveNestedNameSpecifier(const QualifiedNameId *q,
-                                                         const QList<Scope *> &visibleScopes) const
+ClassOrNamespace *LookupContext::lookupType(const Name *name, Scope *scope) const
 {
-    QList<Symbol *> candidates;
-    QList<Scope *> scopes = visibleScopes;
-
-    for (unsigned i = 0; i < q->nameCount() - 1; ++i) {
-        const Name *name = q->nameAt(i);
+    if (ClassOrNamespace *b = bindings()->lookupType(scope->owner()))
+        return b->lookupType(name);
 
-        candidates = resolveClassOrNamespace(name, scopes);
-
-        if (candidates.isEmpty())
-            break;
-
-        scopes.clear();
-
-        foreach (Symbol *candidate, candidates) {
-            ScopedSymbol *scoped = candidate->asScopedSymbol();
-            Scope *members = scoped->members();
-
-            if (! scopes.contains(members))
-                scopes.append(members);
-        }
-    }
+    return 0;
+}
 
-    return scopes;
+ClassOrNamespace *LookupContext::lookupType(Symbol *symbol) const
+{
+    return bindings()->lookupType(symbol);
 }
 
-QList<Symbol *> LookupContext::resolveQualifiedNameId(const QualifiedNameId *q,
-                                                      const QList<Scope *> &visibleScopes,
-                                                      ResolveMode mode) const
+QList<Symbol *> LookupContext::lookup(const Name *name, Scope *scope) const
 {
     QList<Symbol *> candidates;
 
-    if (true || mode & ResolveClass) {
-        for (int i = 0; i < visibleScopes.size(); ++i) {
-            Scope *scope = visibleScopes.at(i);
+    if (! name)
+        return candidates;
 
-            for (Symbol *symbol = scope->lookat(q); symbol; symbol = symbol->next()) {
-                if (! symbol->name())
-                    continue;
-                else if (! symbol->isClass())
-                    continue;
+    const Identifier *id = name->identifier();
 
-                const QualifiedNameId *qq = symbol->name()->asQualifiedNameId();
+    for (; scope; scope = scope->enclosingScope()) {
+        if (id && scope->isBlockScope()) {
+            bindings()->lookupInScope(name, scope, &candidates, /*templateId = */ 0);
 
-                if (! qq)
-                    continue;
-                else if (! maybeValidSymbol(symbol, mode, candidates))
-                    continue;
-
-                if (! q->unqualifiedNameId()->isEqualTo(qq->unqualifiedNameId()))
-                    continue;
+            if (! candidates.isEmpty())
+                break; // it's a local.
 
-                else if (qq->nameCount() == q->nameCount()) {
-                    unsigned j = 0;
+            for (unsigned index = 0; index < scope->symbolCount(); ++index) {
+                Symbol *member = scope->symbolAt(index);
 
-                    for (; j < q->nameCount(); ++j) {
-                        const Name *classOrNamespaceName1 = q->nameAt(j);
-                        const Name *classOrNamespaceName2 = qq->nameAt(j);
+                if (UsingNamespaceDirective *u = member->asUsingNamespaceDirective()) {
+                    if (Namespace *enclosingNamespace = u->enclosingNamespaceScope()->owner()->asNamespace()) {
+                        if (ClassOrNamespace *b = bindings()->lookupType(enclosingNamespace)) {
+                            if (ClassOrNamespace *uu = b->lookupType(u->name())) {
+                                candidates = uu->lookup(name);
 
-                        if (! classOrNamespaceName1->isEqualTo(classOrNamespaceName2))
-                            break;
+                                if (! candidates.isEmpty())
+                                    return candidates;
+                            }
+                        }
                     }
-
-                    if (j == q->nameCount())
-                        candidates.append(symbol);
                 }
             }
-        }
-    }
 
-    QList<Scope *> scopes;
+        } else if (scope->isFunctionScope()) {
+            Function *fun = scope->owner()->asFunction();
+            bindings()->lookupInScope(name, fun->arguments(), &candidates, /*templateId = */ 0);
+            if (! candidates.isEmpty())
+                break; // it's a formal argument.
 
-    if (q->nameCount() == 1)
-        scopes = visibleScopes;     // ### handle global scope lookup
-    else
-        scopes = resolveNestedNameSpecifier(q, visibleScopes);
+            if (fun->name() && fun->name()->isQualifiedNameId()) {
+                if (ClassOrNamespace *binding = bindings()->lookupType(fun))
+                    return binding->lookup(name);
+            }
 
-    QList<Scope *> expanded;
-    foreach (Scope *scope, scopes) {
-        expanded.append(scope);
+        } else if (scope->isObjCMethodScope()) {
+            ObjCMethod *method = scope->owner()->asObjCMethod();
+            bindings()->lookupInScope(name, method->arguments(), &candidates, /*templateId = */ 0);
+            if (! candidates.isEmpty())
+                break; // it's a formal argument.
 
-        for (unsigned i = 0; i < scope->symbolCount(); ++i) {
-            Symbol *member = scope->symbolAt(i);
+        } else if (scope->isClassScope() || scope->isNamespaceScope()
+                    || scope->isObjCClassScope() || scope->isObjCProtocolScope()) {
+            if (ClassOrNamespace *binding = bindings()->lookupType(scope->owner()))
+                return binding->lookup(name);
 
-            if (ScopedSymbol *scopedSymbol = member->asScopedSymbol())
-                expandEnumOrAnonymousSymbol(scopedSymbol, &expanded);
+            break;
         }
     }
 
-    candidates += resolve(q->unqualifiedNameId(), expanded, mode);
-
     return candidates;
 }
 
-QList<Symbol *> LookupContext::resolveOperatorNameId(const OperatorNameId *opId,
-                                                     const QList<Scope *> &visibleScopes,
-                                                     ResolveMode) const
+ClassOrNamespace::ClassOrNamespace(CreateBindings *factory, ClassOrNamespace *parent)
+    : _factory(factory), _parent(parent), _templateId(0)
 {
-    QList<Symbol *> candidates;
+}
 
-    for (int scopeIndex = 0; scopeIndex < visibleScopes.size(); ++scopeIndex) {
-        Scope *scope = visibleScopes.at(scopeIndex);
+const TemplateNameId *ClassOrNamespace::templateId() const
+{
+    return _templateId;
+}
 
-        for (Symbol *symbol = scope->lookat(opId->kind()); symbol; symbol = symbol->next()) {
-            if (! opId->isEqualTo(symbol->name()))
-                continue;
+ClassOrNamespace *ClassOrNamespace::parent() const
+{
+    return _parent;
+}
 
-            if (! candidates.contains(symbol))
-                candidates.append(symbol);
-        }
-    }
+QList<ClassOrNamespace *> ClassOrNamespace::usings() const
+{
+    const_cast<ClassOrNamespace *>(this)->flush();
+    return _usings;
+}
 
-    return candidates;
+QList<Enum *> ClassOrNamespace::enums() const
+{
+    const_cast<ClassOrNamespace *>(this)->flush();
+    return _enums;
 }
 
-QList<Symbol *> LookupContext::resolve(const Name *name, const QList<Scope *> &visibleScopes,
-                                       ResolveMode mode) const
+QList<Symbol *> ClassOrNamespace::symbols() const
 {
-    QList<Symbol *> candidates;
+    if (_templateId && ! _usings.isEmpty())
+        return _usings.first()->symbols(); // ask to the base implementation
 
-    if (!name)
-        return candidates; // nothing to do, the symbol is anonymous.
+    const_cast<ClassOrNamespace *>(this)->flush();
+    return _symbols;
+}
 
-    else if (const QualifiedNameId *q = name->asQualifiedNameId())
-        return resolveQualifiedNameId(q, visibleScopes, mode);
+ClassOrNamespace *ClassOrNamespace::globalNamespace() const
+{
+    ClassOrNamespace *e = const_cast<ClassOrNamespace *>(this);
 
-    else if (const OperatorNameId *opId = name->asOperatorNameId())
-        return resolveOperatorNameId(opId, visibleScopes, mode);
+    do {
+        if (! e->_parent)
+            break;
 
-    else if (const Identifier *id = name->identifier()) {
-        for (int scopeIndex = 0; scopeIndex < visibleScopes.size(); ++scopeIndex) {
-            Scope *scope = visibleScopes.at(scopeIndex);
+        e = e->_parent;
+    } while (e);
 
-            for (Symbol *symbol = scope->lookat(id); symbol; symbol = symbol->next()) {
-                if (! symbol->name())
-                    continue; // nothing to do, the symbol is anonymous.
+    return e;
+}
 
-                else if (! maybeValidSymbol(symbol, mode, candidates))
-                    continue; // skip it, we're not looking for this kind of symbols
+QList<Symbol *> ClassOrNamespace::find(const Name *name)
+{
+    return lookup_helper(name, false);
+}
 
-                else if (const Identifier *symbolId = symbol->identifier()) {
-                    if (! symbolId->isEqualTo(id))
-                        continue; // skip it, the symbol's id is not compatible with this lookup.
-                }
+QList<Symbol *> ClassOrNamespace::lookup(const Name *name)
+{
+    return lookup_helper(name, true);
+}
 
-                if (const QualifiedNameId *q = symbol->name()->asQualifiedNameId()) {
+QList<Symbol *> ClassOrNamespace::lookup_helper(const Name *name, bool searchInEnclosingScope)
+{
+    QList<Symbol *> result;
 
-                    if (name->isDestructorNameId() != q->unqualifiedNameId()->isDestructorNameId())
-                        continue;
+    if (name) {
+        if (const QualifiedNameId *q = name->asQualifiedNameId()) {
+            ClassOrNamespace *binding = this;
 
-                    else if (q->nameCount() > 1) {
-                        const Name *classOrNamespaceName = control()->qualifiedNameId(q->names(),
-                                                                                      q->nameCount() - 1);
+            if (q->isGlobal())
+                binding = globalNamespace();
 
-                        if (const Identifier *classOrNamespaceNameId = identifier(classOrNamespaceName)) {
-                            if (classOrNamespaceNameId->isEqualTo(id))
-                                continue;
-                        }
+            if (q->nameCount() == 1)
+                return binding->find(q->unqualifiedNameId());
 
-                        const QList<Symbol *> resolvedClassOrNamespace =
-                                resolveClassOrNamespace(classOrNamespaceName, visibleScopes);
+            binding = binding->lookupType(q->nameAt(0));
 
-                        bool good = false;
-                        foreach (Symbol *classOrNamespace, resolvedClassOrNamespace) {
-                            ScopedSymbol *scoped = classOrNamespace->asScopedSymbol();
-                            if (visibleScopes.contains(scoped->members())) {
-                                good = true;
-                                break;
-                            }
-                        }
+            for (unsigned index = 1; binding && index < q->nameCount() - 1; ++index)
+                binding = binding->findType(q->nameAt(index));
 
-                        if (! good)
-                            continue;
-                    }
-                } else if (symbol->name()->isDestructorNameId() != name->isDestructorNameId()) {
-                    // ### FIXME: this is wrong!
-                    continue;
-                }
+            if (binding)
+                result = binding->find(q->unqualifiedNameId());
 
-                if (! candidates.contains(symbol))
-                    candidates.append(symbol);
-            }
+            return result;
         }
+
+        QSet<ClassOrNamespace *> processed;
+        ClassOrNamespace *binding = this;
+        do {
+            lookup_helper(name, binding, &result, &processed, /*templateId = */ 0);
+            binding = binding->_parent;
+        } while (searchInEnclosingScope && binding);
     }
 
-    return candidates;
+    return result;
 }
 
-const Identifier *LookupContext::identifier(const Name *name) const
+void ClassOrNamespace::lookup_helper(const Name *name, ClassOrNamespace *binding,
+                                     QList<Symbol *> *result,
+                                     QSet<ClassOrNamespace *> *processed,
+                                     const TemplateNameId *templateId)
 {
-    if (name)
-        return name->identifier();
+    if (binding && ! processed->contains(binding)) {
+        processed->insert(binding);
 
-    return 0;
+        foreach (Symbol *s, binding->symbols()) {
+            if (ScopedSymbol *scoped = s->asScopedSymbol())
+                _factory->lookupInScope(name, scoped->members(), result, templateId);
+        }
+
+        foreach (Enum *e, binding->enums())
+            _factory->lookupInScope(name, e->members(), result, templateId);
+
+        foreach (ClassOrNamespace *u, binding->usings())
+            lookup_helper(name, u, result, processed, binding->_templateId);
+    }
 }
 
-void LookupContext::buildVisibleScopes_helper(Document::Ptr doc, QList<Scope *> *scopes,
-                                              QSet<QString> *processed)
+void CreateBindings::lookupInScope(const Name *name, Scope *scope,
+                                   QList<Symbol *> *result,
+                                   const TemplateNameId *templateId)
 {
-    if (doc && ! processed->contains(doc->fileName())) {
-        processed->insert(doc->fileName());
+    Q_UNUSED(templateId);
 
-        if (doc->globalSymbolCount())
-            scopes->append(doc->globalSymbols());
+    if (! name) {
+        return;
 
-        foreach (const Document::Include &incl, doc->includes()) {
-            buildVisibleScopes_helper(_snapshot.document(incl.fileName()),
-                                      scopes, processed);
+    } else if (const OperatorNameId *op = name->asOperatorNameId()) {
+        for (Symbol *s = scope->lookat(op->kind()); s; s = s->next()) {
+            if (! s->name())
+                continue;
+            else if (! s->name()->isEqualTo(op))
+                continue;
+
+            result->append(s);
         }
+
+    } else if (const Identifier *id = name->identifier()) {
+        for (Symbol *s = scope->lookat(id); s; s = s->next()) {
+            if (! id->isEqualTo(s->identifier()))
+                continue;
+            else if (s->name()->isQualifiedNameId())
+                continue; // skip qualified ids.
+
+#if 0
+            if (templateId && (s->isDeclaration() || s->isFunction())) {
+
+                FullySpecifiedType ty = GenTemplateInstance::instantiate(templateId, s, _control);
+
+                if (debug) {
+                    Overview oo;
+                    oo.setShowFunctionSignatures(true);
+                    oo.setShowReturnTypes(true);
+                    qDebug() << "instantiate:" << oo(s->type(), s->name()) << "using:" << oo(templateId) << oo(ty);
+                }
+
+                if (Declaration *decl = s->asDeclaration()) {
+                    Declaration *d = _control->newDeclaration(0, 0);
+                    d->copy(decl);
+                    d->setType(ty);
+                    result->append(d);
+                    continue;
+                } else if (Function *fun = s->asFunction()) {
+                    Function *d = ty->asFunctionType();
+                    d->copy(fun);
+                    result->append(d);
+                    continue;
+                }
+            }
+#endif
+
+            result->append(s);
+        }
+
     }
 }
 
-QList<Scope *> LookupContext::buildVisibleScopes()
+ClassOrNamespace *ClassOrNamespace::lookupType(const Name *name)
 {
-    QList<Scope *> scopes;
+    if (! name)
+        return 0;
 
-    if (_symbol) {
-        Scope *scope = _symbol->scope();
+    QSet<ClassOrNamespace *> processed;
+    return lookupType_helper(name, &processed, /*searchInEnclosingScope =*/ true);
+}
 
-        if (Function *fun = _symbol->asFunction())
-            scope = fun->members(); // handle ctor initializers.
+ClassOrNamespace *ClassOrNamespace::findType(const Name *name)
+{
+    QSet<ClassOrNamespace *> processed;
+    return lookupType_helper(name, &processed, /*searchInEnclosingScope =*/ false);
+}
 
-        for (; scope; scope = scope->enclosingScope()) {
-            if (scope == _thisDocument->globalSymbols())
-                break;
+ClassOrNamespace *ClassOrNamespace::lookupType_helper(const Name *name,
+                                                      QSet<ClassOrNamespace *> *processed,
+                                                      bool searchInEnclosingScope)
+{
+    if (const QualifiedNameId *q = name->asQualifiedNameId()) {
+        ClassOrNamespace *e = this;
 
-            scopes.append(scope);
-        }
-    }
+        if (q->isGlobal())
+            e = globalNamespace();
 
-    QSet<QString> processed;
-    buildVisibleScopes_helper(_thisDocument, &scopes, &processed);
+        e = e->lookupType(q->nameAt(0));
 
-    while (true) {
-        QList<Scope *> expandedScopes;
-        expand(scopes, &expandedScopes);
+        for (unsigned index = 1; e && index < q->nameCount(); ++index)
+            e = e->findType(q->nameAt(index));
 
-        if (expandedScopes.size() == scopes.size())
-            return expandedScopes;
+        return e;
 
-        scopes = expandedScopes;
-    }
+    } else if (! processed->contains(this)) {
+        processed->insert(this);
 
-    return scopes;
-}
+        if (name->isNameId() || name->isTemplateNameId()) {
+            flush();
 
-QList<Scope *> LookupContext::visibleScopes(const LookupItem &result) const
-{ return visibleScopes(result.lastVisibleSymbol()); }
+            if (ClassOrNamespace *e = nestedType(name))
+                return e;
 
-QList<Scope *> LookupContext::visibleScopes(Symbol *symbol) const
-{
-    QList<Scope *> scopes;
-    if (symbol) {
-        for (Scope *scope = symbol->scope(); scope; scope = scope->enclosingScope())
-            scopes.append(scope);
+            foreach (ClassOrNamespace *u, usings()) {
+                if (ClassOrNamespace *r = u->lookupType_helper(name, processed, /*searchInEnclosingScope =*/ false))
+                    return r;
+            }
+        }
+
+        if (_parent && searchInEnclosingScope)
+            return _parent->lookupType_helper(name, processed, searchInEnclosingScope);
     }
-    scopes += visibleScopes();
-    scopes = expand(scopes);
-    return scopes;
+
+    return 0;
 }
 
-void LookupContext::expandEnumOrAnonymousSymbol(ScopedSymbol *scopedSymbol,
-                                                QList<Scope *> *expandedScopes) const
+ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name) const
 {
-    if (! scopedSymbol || expandedScopes->contains(scopedSymbol->members()))
-        return;
+    Q_ASSERT(name != 0);
+    Q_ASSERT(name->isNameId() || name->isTemplateNameId());
 
-    Scope *members = scopedSymbol->members();
+    const_cast<ClassOrNamespace *>(this)->flush();
 
-    if (scopedSymbol->isEnum())
-        expandedScopes->append(members);
-    else if (! scopedSymbol->name() && (scopedSymbol->isClass() || scopedSymbol->isNamespace())) {
-        // anonymous class or namespace
+    Table::const_iterator it = _classOrNamespaces.find(name);
 
-        expandedScopes->append(members);
+    if (it == _classOrNamespaces.end())
+        return 0;
 
-        for (unsigned i = 0; i < members->symbolCount(); ++i) {
-            Symbol *member = members->symbolAt(i);
+    ClassOrNamespace *c = it->second;
 
-            if (ScopedSymbol *nested = member->asScopedSymbol()) {
-                expandEnumOrAnonymousSymbol(nested, expandedScopes);
-            }
+    if (const TemplateNameId *templId = name->asTemplateNameId()) {
+        foreach (ClassOrNamespace *i, c->_instantiations) {
+            if (templId->isEqualTo(i->_templateId))
+                return i;
         }
+
+        ClassOrNamespace *i = _factory->allocClassOrNamespace(c);
+        i->_templateId = templId;
+        i->_usings.append(c);
+        c->_instantiations.append(i);
+        return i;
     }
+
+    return c;
 }
 
-QList<Scope *> LookupContext::expand(const QList<Scope *> &scopes) const
+void ClassOrNamespace::flush()
 {
-    QList<Scope *> expanded;
-    expand(scopes, &expanded);
-    return expanded;
+    if (! _todo.isEmpty()) {
+        const QList<Symbol *> todo = _todo;
+        _todo.clear();
+
+        foreach (Symbol *member, todo)
+            _factory->process(member, this);
+    }
 }
 
-void LookupContext::expand(const QList<Scope *> &scopes, QList<Scope *> *expandedScopes) const
+void ClassOrNamespace::addSymbol(Symbol *symbol)
 {
-    for (int i = 0; i < scopes.size(); ++i) {
-        expand(scopes.at(i), scopes, expandedScopes);
-    }
+    _symbols.append(symbol);
 }
 
-void LookupContext::expandNamespace(Namespace *ns,
-                                    const QList<Scope *> &visibleScopes,
-                                    QList<Scope *> *expandedScopes) const
+void ClassOrNamespace::addTodo(Symbol *symbol)
 {
-    //qDebug() << "*** expand namespace:" << ns->fileName() << ns->line() << ns->column();
+    _todo.append(symbol);
+}
 
-    if (Scope *encl = ns->enclosingNamespaceScope())
-        expand(encl, visibleScopes, expandedScopes);
+void ClassOrNamespace::addEnum(Enum *e)
+{
+    _enums.append(e);
+}
 
-    if (const Name *nsName = ns->name()) {
-        const QList<Symbol *> namespaceList = resolveNamespace(nsName, visibleScopes);
-        foreach (Symbol *otherNs, namespaceList) {
-            if (otherNs == ns)
-                continue;
-            expand(otherNs->asNamespace()->members(), visibleScopes, expandedScopes);
-        }
-    }
+void ClassOrNamespace::addUsing(ClassOrNamespace *u)
+{
+    _usings.append(u);
+}
 
-    for (unsigned i = 0; i < ns->memberCount(); ++i) { // ### make me fast
-        Symbol *symbol = ns->memberAt(i);
-        if (Namespace *otherNs = symbol->asNamespace()) {
-            if (! otherNs->name()) {
-                expand(otherNs->members(), visibleScopes, expandedScopes);
-            }
-        } else if (UsingNamespaceDirective *u = symbol->asUsingNamespaceDirective()) {
-            const QList<Symbol *> candidates = resolveNamespace(u->name(), visibleScopes);
-            for (int j = 0; j < candidates.size(); ++j) {
-                expand(candidates.at(j)->asNamespace()->members(),
-                       visibleScopes, expandedScopes);
-            }
-        } else if (Enum *e = symbol->asEnum()) {
-            expand(e->members(), visibleScopes, expandedScopes);
-        }
-    }
+void ClassOrNamespace::addNestedType(const Name *alias, ClassOrNamespace *e)
+{
+    _classOrNamespaces[alias] = e;
 }
 
-void LookupContext::expandClass(Class *klass,
-                                const QList<Scope *> &visibleScopes,
-                                QList<Scope *> *expandedScopes) const
+ClassOrNamespace *ClassOrNamespace::findOrCreateType(const Name *name)
 {
-    for (TemplateParameters *params = klass->templateParameters(); params; params = params->previous())
-        expand(params->scope(), visibleScopes, expandedScopes);
+    if (! name)
+        return this;
 
-    for (unsigned i = 0; i < klass->memberCount(); ++i) {
-        Symbol *symbol = klass->memberAt(i);
-        if (Class *nestedClass = symbol->asClass()) {
-            if (! nestedClass->name()) {
-                expand(nestedClass->members(), visibleScopes, expandedScopes);
-            }
-        } else if (Enum *e = symbol->asEnum()) {
-            expand(e->members(), visibleScopes, expandedScopes);
-        }
-    }
+    if (const QualifiedNameId *q = name->asQualifiedNameId()) {
+        ClassOrNamespace *e = this;
 
-    if (klass->baseClassCount()) {
-        QList<Scope *> classVisibleScopes = visibleScopes;
-        for (Scope *scope = klass->scope(); scope; scope = scope->enclosingScope()) {
-            if (scope->isNamespaceScope()) {
-                Namespace *enclosingNamespace = scope->owner()->asNamespace();
-                if (enclosingNamespace->name()) {
-                    const QList<Symbol *> nsList = resolveNamespace(enclosingNamespace->name(),
-                                                                    visibleScopes);
-                    foreach (Symbol *ns, nsList) {
-                        expand(ns->asNamespace()->members(), classVisibleScopes,
-                               &classVisibleScopes);
-                    }
-                }
-            }
-        }
+        for (unsigned i = 0; e && i < q->nameCount(); ++i)
+            e = e->findOrCreateType(q->nameAt(i));
 
-        for (unsigned i = 0; i < klass->baseClassCount(); ++i) {
-            BaseClass *baseClass = klass->baseClassAt(i);
-            const Name *baseClassName = baseClass->name();
-            const QList<Symbol *> baseClassCandidates = resolveClass(baseClassName,
-                                                                     classVisibleScopes);
+        return e;
 
-            for (int j = 0; j < baseClassCandidates.size(); ++j) {
-                if (Class *baseClassSymbol = baseClassCandidates.at(j)->asClass())
-                    expand(baseClassSymbol->members(), visibleScopes, expandedScopes);
-            }
+    } else if (name->isNameId() || name->isTemplateNameId()) {
+        ClassOrNamespace *e = nestedType(name);
+
+        if (! e) {
+            e = _factory->allocClassOrNamespace(this);
+            _classOrNamespaces[name] = e;
         }
+
+        return e;
     }
+
+    return 0;
 }
 
-void LookupContext::expandBlock(Block *blockSymbol,
-                                const QList<Scope *> &visibleScopes,
-                                QList<Scope *> *expandedScopes) const
+CreateBindings::CreateBindings(Document::Ptr thisDocument, const Snapshot &snapshot)
+    : _snapshot(snapshot)
 {
-    for (unsigned i = 0; i < blockSymbol->memberCount(); ++i) {
-        Symbol *symbol = blockSymbol->memberAt(i);
-        if (UsingNamespaceDirective *u = symbol->asUsingNamespaceDirective()) {
-            const QList<Symbol *> candidates = resolveNamespace(u->name(),
-                                                                visibleScopes);
-            for (int j = 0; j < candidates.size(); ++j) {
-                expand(candidates.at(j)->asNamespace()->members(),
-                       visibleScopes, expandedScopes);
-            }
-        }
+    _control = new Control();
+    _globalNamespace = allocClassOrNamespace(/*parent = */ 0);
+    _currentClassOrNamespace = _globalNamespace;
 
-    }
+    process(thisDocument);
 }
 
-void LookupContext::expandFunction(Function *function,
-                                   const QList<Scope *> &visibleScopes,
-                                   QList<Scope *> *expandedScopes) const
+CreateBindings::~CreateBindings()
 {
-    for (TemplateParameters *params = function->templateParameters(); params; params = params->previous())
-        expand(params->scope(), visibleScopes, expandedScopes);
-
-    if (! expandedScopes->contains(function->arguments()))
-        expandedScopes->append(function->arguments());
+    qDeleteAll(_entities);
+    delete _control;
+}
 
-    if (const QualifiedNameId *q = function->name()->asQualifiedNameId()) {
-        const Name *nestedNameSpec = 0;
-        if (q->nameCount() == 1)
-            nestedNameSpec = q->nameAt(0);
-        else
-            nestedNameSpec = control()->qualifiedNameId(q->names(), q->nameCount() - 1,
-                                                        q->isGlobal());
-        const QList<Symbol *> candidates = resolveClassOrNamespace(nestedNameSpec, visibleScopes);
-        for (int j = 0; j < candidates.size(); ++j) {
-            if (ScopedSymbol *scopedSymbol = candidates.at(j)->asScopedSymbol())
-                expand(scopedSymbol->members(), visibleScopes, expandedScopes);
-        }
-    }
+ClassOrNamespace *CreateBindings::switchCurrentClassOrNamespace(ClassOrNamespace *classOrNamespace)
+{
+    ClassOrNamespace *previous = _currentClassOrNamespace;
+    _currentClassOrNamespace = classOrNamespace;
+    return previous;
 }
 
-void LookupContext::expandObjCMethod(ObjCMethod *method,
-                                     const QList<Scope *> &,
-                                     QList<Scope *> *expandedScopes) const
+ClassOrNamespace *CreateBindings::globalNamespace() const
 {
-    if (! expandedScopes->contains(method->arguments()))
-        expandedScopes->append(method->arguments());
+    return _globalNamespace;
 }
 
-void LookupContext::expandObjCClass(ObjCClass *klass,
-                                    const QList<Scope *> &visibleScopes,
-                                    QList<Scope *> *expandedScopes) const
+ClassOrNamespace *CreateBindings::lookupType(Symbol *symbol)
 {
-    {// expand other @interfaces, @implementations and categories for this class:
-        const QList<Symbol *> classList = resolveObjCClass(klass->name(), visibleScopes);
-        foreach (Symbol *otherClass, classList) {
-            if (otherClass == klass)
-                continue;
-            expand(otherClass->asObjCClass()->members(), visibleScopes, expandedScopes);
-        }
-    }
+    const QList<const Name *> names = LookupContext::fullyQualifiedName(symbol);
 
-    // expand definitions in the currect class:
-    for (unsigned i = 0; i < klass->memberCount(); ++i) {
-        Symbol *symbol = klass->memberAt(i);
-        if (Class *nestedClass = symbol->asClass()) {
-            if (! nestedClass->name()) {
-                expand(nestedClass->members(), visibleScopes, expandedScopes);
-            }
-        } else if (Enum *e = symbol->asEnum()) {
-            expand(e->members(), visibleScopes, expandedScopes);
-        }
-    }
+    if (names.isEmpty())
+        return _globalNamespace;
 
-    // expand the base class:
-    if (ObjCBaseClass *baseClass = klass->baseClass()) {
-        const Name *baseClassName = baseClass->name();
-        const QList<Symbol *> baseClassCandidates = resolveObjCClass(baseClassName,
-                                                                     visibleScopes);
+    ClassOrNamespace *b = _globalNamespace->lookupType(names.at(0));
 
-        for (int j = 0; j < baseClassCandidates.size(); ++j) {
-            if (ObjCClass *baseClassSymbol = baseClassCandidates.at(j)->asObjCClass())
-                expand(baseClassSymbol->members(), visibleScopes, expandedScopes);
-        }
-    }
+    for (int i = 1; b && i < names.size(); ++i)
+        b = b->findType(names.at(i));
 
-    // expand the protocols:
-    for (unsigned i = 0; i < klass->protocolCount(); ++i) {
-        const Name *protocolName = klass->protocolAt(i)->name();
-        const QList<Symbol *> protocolCandidates = resolveObjCProtocol(protocolName, visibleScopes);
-        for (int j = 0; j < protocolCandidates.size(); ++j) {
-            if (ObjCProtocol *protocolSymbol = protocolCandidates.at(j)->asObjCProtocol())
-                expandObjCProtocol(protocolSymbol, visibleScopes, expandedScopes);
-        }
-    }
+    return b;
 }
 
-void LookupContext::expandObjCProtocol(ObjCProtocol *protocol, const QList<Scope *> &visibleScopes, QList<Scope *> *expandedScopes) const
+void CreateBindings::process(Symbol *s, ClassOrNamespace *classOrNamespace)
 {
-    // First expand the protocol itself
-    expand(protocol->members(), visibleScopes, expandedScopes);
+    ClassOrNamespace *previous = switchCurrentClassOrNamespace(classOrNamespace);
+    accept(s);
+    (void) switchCurrentClassOrNamespace(previous);
+}
 
-    // Then do the same for any incorporated protocol
-    for (unsigned i = 0; i < protocol->protocolCount(); ++i) {
-        ObjCBaseProtocol *baseProtocol = protocol->protocolAt(i);
-        const QList<Symbol *> protocolList = resolveObjCProtocol(baseProtocol->name(), visibleScopes);
-        foreach (Symbol *symbol, protocolList)
-            if (ObjCProtocol *protocolSymbol = symbol->asObjCProtocol())
-                expandObjCProtocol(protocolSymbol, visibleScopes, expandedScopes);
-    }
+void CreateBindings::process(Symbol *symbol)
+{
+    _currentClassOrNamespace->addTodo(symbol);
 }
 
-void LookupContext::expand(Scope *scope,
-                           const QList<Scope *> &visibleScopes,
-                           QList<Scope *> *expandedScopes) const
+Control *CreateBindings::control() const
 {
-    if (expandedScopes->contains(scope))
-        return;
+    return _control;
+}
 
-    expandedScopes->append(scope);
-
-    if (Namespace *ns = scope->owner()->asNamespace()) {
-        expandNamespace(ns, visibleScopes, expandedScopes);
-    } else if (Class *klass = scope->owner()->asClass()) {
-        expandClass(klass, visibleScopes, expandedScopes);
-    } else if (Block *block = scope->owner()->asBlock()) {
-        expandBlock(block, visibleScopes, expandedScopes);
-    } else if (Function *fun = scope->owner()->asFunction()) {
-        expandFunction(fun, visibleScopes, expandedScopes);
-    } else if (ObjCMethod *meth = scope->owner()->asObjCMethod()) {
-        expandObjCMethod(meth, visibleScopes, expandedScopes);
-    } else if (ObjCClass *objcKlass = scope->owner()->asObjCClass()) {
-        expandObjCClass(objcKlass, visibleScopes, expandedScopes);
-    }
+ClassOrNamespace *CreateBindings::allocClassOrNamespace(ClassOrNamespace *parent)
+{
+    ClassOrNamespace *e = new ClassOrNamespace(this, parent);
+    _entities.append(e);
+    return e;
 }
 
-static void visibleClassBindings_helper(ClassBinding *classBinding,
-                                        QList<ClassBinding *> *allClassBindings,
-                                        QSet<ClassBinding *> *processed)
+void CreateBindings::process(Document::Ptr doc)
 {
-    if (! classBinding)
+    if (! doc)
         return;
 
-    else if (processed->contains(classBinding))
-        return;
+    else if (Namespace *globalNamespace = doc->globalNamespace()) {
+        if (! _processed.contains(globalNamespace)) {
+            _processed.insert(globalNamespace);
+
+            foreach (const Document::Include &i, doc->includes()) {
+                if (Document::Ptr incl = _snapshot.document(i.fileName()))
+                    process(incl);
+            }
 
-    processed->insert(classBinding);
+            accept(globalNamespace);
+        }
+    }
+}
 
-    foreach (ClassBinding *baseClassBinding, classBinding->baseClassBindings)
-        visibleClassBindings_helper(baseClassBinding, allClassBindings, processed);
+ClassOrNamespace *CreateBindings::enterClassOrNamespaceBinding(Symbol *symbol)
+{
+    ClassOrNamespace *entity = _currentClassOrNamespace->findOrCreateType(symbol->name());
+    entity->addSymbol(symbol);
 
-    allClassBindings->append(classBinding);
+    return switchCurrentClassOrNamespace(entity);
 }
 
-static QList<ClassBinding *> visibleClassBindings(Symbol *symbol, NamespaceBinding *globalNamespace)
+ClassOrNamespace *CreateBindings::enterGlobalClassOrNamespace(Symbol *symbol)
 {
-    QList<ClassBinding *> classBindings;
+    ClassOrNamespace *entity = _globalNamespace->findOrCreateType(symbol->name());
+    entity->addSymbol(symbol);
 
-    if (! symbol)
-        return classBindings;
+    return switchCurrentClassOrNamespace(entity);
+}
 
-    else if (Class *klass = symbol->asClass()) {
-        QSet<ClassBinding *> processed;
+bool CreateBindings::visit(Namespace *ns)
+{
+    ClassOrNamespace *previous = enterClassOrNamespaceBinding(ns);
 
-        visibleClassBindings_helper(NamespaceBinding::find(klass, globalNamespace),
-                                    &classBindings, &processed);
-    }
+    for (unsigned i = 0; i < ns->memberCount(); ++i)
+        process(ns->memberAt(i));
 
-    return classBindings;
+    _currentClassOrNamespace = previous;
+    return false;
 }
 
-Symbol *LookupContext::canonicalSymbol(Symbol *symbol,
-                                       NamespaceBinding *globalNamespace)
+bool CreateBindings::visit(Class *klass)
 {
-    Symbol *canonicalSymbol = LookupContext::canonicalSymbol(symbol);
-    if (! canonicalSymbol)
-        return 0;
+    ClassOrNamespace *previous = _currentClassOrNamespace;
+    ClassOrNamespace *binding = 0;
 
-    if (const Identifier *symbolId = canonicalSymbol->identifier()) {
-        if (symbolId && canonicalSymbol->type()->isFunctionType()) {
-            Class *enclosingClass = canonicalSymbol->scope()->owner()->asClass();
-            const QList<ClassBinding *> classBindings = visibleClassBindings(enclosingClass, globalNamespace);
+    if (klass->name() && klass->name()->isQualifiedNameId())
+        binding = _currentClassOrNamespace->lookupType(klass->name());
 
-            foreach (ClassBinding *baseClassBinding, classBindings) {
-                if (! baseClassBinding)
-                    continue;
+    if (! binding)
+        binding = _currentClassOrNamespace->findOrCreateType(klass->name());
 
-                foreach (Class *baseClass, baseClassBinding->symbols) {
-                    if (! baseClass)
-                        continue;
+    _currentClassOrNamespace = binding;
+    _currentClassOrNamespace->addSymbol(klass);
 
-                    for (Symbol *c = baseClass->members()->lookat(symbolId); c; c = c->next()) {
-                        if (! symbolId->isEqualTo(c->identifier()))
-                            continue;
-                        else if (Function *f = c->type()->asFunctionType()) {
-                            if (f->isVirtual())
-                                return LookupContext::canonicalSymbol(f);
-                        }
-                    }
+    for (unsigned i = 0; i < klass->baseClassCount(); ++i)
+        process(klass->baseClassAt(i));
+
+    for (unsigned i = 0; i < klass->memberCount(); ++i)
+        process(klass->memberAt(i));
+
+    _currentClassOrNamespace = previous;
+    return false;
+}
+
+bool CreateBindings::visit(ForwardClassDeclaration *klass)
+{
+    if (! klass->isFriend()) {
+        ClassOrNamespace *previous = enterClassOrNamespaceBinding(klass);
+        _currentClassOrNamespace = previous;
+    }
+
+    return false;
+}
+
+bool CreateBindings::visit(Enum *e)
+{
+    _currentClassOrNamespace->addEnum(e);
+    return false;
+}
+
+bool CreateBindings::visit(Declaration *decl)
+{
+    if (decl->isTypedef()) {
+        const FullySpecifiedType ty = decl->type();
+        const Identifier *typedefId = decl->identifier();
+
+        if (typedefId && ! (ty.isConst() || ty.isVolatile())) {
+            if (const NamedType *namedTy = ty->asNamedType()) {
+                if (ClassOrNamespace *e = _currentClassOrNamespace->lookupType(namedTy->name())) {
+                    _currentClassOrNamespace->addNestedType(decl->name(), e);
+                } else if (false) {
+                    Overview oo;
+                    qDebug() << "found entity not found for" << oo(namedTy->name());
                 }
             }
         }
     }
 
-    return canonicalSymbol;
+    return false;
 }
 
-Symbol *LookupContext::canonicalSymbol(const QList<Symbol *> &candidates,
-                                       NamespaceBinding *globalNamespaceBinding)
+bool CreateBindings::visit(Function *)
 {
-    if (candidates.isEmpty())
-        return 0;
+    return false;
+}
 
-    return canonicalSymbol(candidates.first(), globalNamespaceBinding);
+bool CreateBindings::visit(BaseClass *b)
+{
+    if (ClassOrNamespace *base = _currentClassOrNamespace->lookupType(b->name())) {
+        _currentClassOrNamespace->addUsing(base);
+    } else if (false) {
+        Overview oo;
+        qDebug() << "no entity for:" << oo(b->name());
+    }
+    return false;
 }
 
-Symbol *LookupContext::canonicalSymbol(const QList<LookupItem> &results,
-                                       NamespaceBinding *globalNamespaceBinding)
+bool CreateBindings::visit(UsingNamespaceDirective *u)
 {
-    QList<Symbol *> candidates;
+    if (ClassOrNamespace *e = _currentClassOrNamespace->lookupType(u->name())) {
+        _currentClassOrNamespace->addUsing(e);
+    } else if (false) {
+        Overview oo;
+        qDebug() << "no entity for namespace:" << oo(u->name());
+    }
+    return false;
+}
 
-    foreach (const LookupItem &result, results)
-        candidates.append(result.lastVisibleSymbol()); // ### not exactly.
+bool CreateBindings::visit(NamespaceAlias *a)
+{
+    if (! a->identifier()) {
+        return false;
 
-    return canonicalSymbol(candidates, globalNamespaceBinding);
-}
+    } else if (ClassOrNamespace *e = _currentClassOrNamespace->lookupType(a->namespaceName())) {
+        if (a->name()->isNameId() || a->name()->isTemplateNameId())
+            _currentClassOrNamespace->addNestedType(a->name(), e);
 
+    } else if (false) {
+        Overview oo;
+        qDebug() << "no entity for namespace:" << oo(a->namespaceName());
+    }
 
-Symbol *LookupContext::canonicalSymbol(Symbol *symbol)
+    return false;
+}
+
+bool CreateBindings::visit(ObjCClass *klass)
 {
-    Symbol *canonical = symbol;
-    Class *canonicalClass = 0;
-    ObjCClass *canonicalObjCClass = 0;
-    ObjCProtocol *canonicalObjCProto = 0;
+    ClassOrNamespace *previous = enterGlobalClassOrNamespace(klass);
 
-    for (; symbol; symbol = symbol->next()) {
-        if (symbol->identifier() == canonical->identifier()) {
-            canonical = symbol;
+    process(klass->baseClass());
 
-            if (Class *klass = symbol->asClass())
-                canonicalClass = klass;
-            else if (ObjCClass *clazz = symbol->asObjCClass())
-                canonicalObjCClass = clazz;
-            else if (ObjCProtocol *proto = symbol->asObjCProtocol())
-                canonicalObjCProto = proto;
-        }
+    for (unsigned i = 0; i < klass->protocolCount(); ++i)
+        process(klass->protocolAt(i));
+
+    for (unsigned i = 0; i < klass->memberCount(); ++i)
+        process(klass->memberAt(i));
+
+    _currentClassOrNamespace = previous;
+    return false;
+}
+
+bool CreateBindings::visit(ObjCBaseClass *b)
+{
+    if (ClassOrNamespace *base = _globalNamespace->lookupType(b->name())) {
+        _currentClassOrNamespace->addUsing(base);
+    } else if (false) {
+        Overview oo;
+        qDebug() << "no entity for:" << oo(b->name());
     }
+    return false;
+}
 
-    if (canonicalClass) {
-        Q_ASSERT(canonical != 0);
+bool CreateBindings::visit(ObjCForwardClassDeclaration *klass)
+{
+    ClassOrNamespace *previous = enterGlobalClassOrNamespace(klass);
+    _currentClassOrNamespace = previous;
+    return false;
+}
 
-        if (canonical->isForwardClassDeclaration())
-            return canonicalClass; // prefer class declarations when available.
-    } else if (canonicalObjCClass) {
-        Q_ASSERT(canonical != 0);
+bool CreateBindings::visit(ObjCProtocol *proto)
+{
+    ClassOrNamespace *previous = enterGlobalClassOrNamespace(proto);
 
-        if (canonical->isObjCForwardClassDeclaration())
-            return canonicalObjCClass;
-    } else if (canonicalObjCProto) {
-        Q_ASSERT(canonical != 0);
+    for (unsigned i = 0; i < proto->protocolCount(); ++i)
+        process(proto->protocolAt(i));
 
-        if (canonical->isObjCForwardProtocolDeclaration())
-            return canonicalObjCProto;
-    }
+    for (unsigned i = 0; i < proto->memberCount(); ++i)
+        process(proto->memberAt(i));
 
-    if (canonical && canonical->scope()->isClassScope()) {
-        Class *enclosingClass = canonical->scope()->owner()->asClass();
+    _currentClassOrNamespace = previous;
+    return false;
+}
 
-        if (enclosingClass->identifier() == canonical->identifier())
-            return enclosingClass;
+bool CreateBindings::visit(ObjCBaseProtocol *b)
+{
+    if (ClassOrNamespace *base = _globalNamespace->lookupType(b->name())) {
+        _currentClassOrNamespace->addUsing(base);
+    } else if (false) {
+        Overview oo;
+        qDebug() << "no entity for:" << oo(b->name());
     }
+    return false;
+}
+
+bool CreateBindings::visit(ObjCForwardProtocolDeclaration *proto)
+{
+    ClassOrNamespace *previous = enterGlobalClassOrNamespace(proto);
+    _currentClassOrNamespace = previous;
+    return false;
+}
 
-    return canonical;
+bool CreateBindings::visit(ObjCMethod *)
+{
+    return false;
 }
index 11689e9..060d7ab 100644 (file)
 #define CPLUSPLUS_LOOKUPCONTEXT_H
 
 #include "CppDocument.h"
+#include "LookupItem.h"
 #include <FullySpecifiedType.h>
+#include <Type.h>
+#include <SymbolVisitor.h>
+#include <QtCore/QSet>
+#include <map>
+#include <functional>
 
 namespace CPlusPlus {
 
-class CPLUSPLUS_EXPORT LookupItem
-{
-public:
-    LookupItem()
-        : _lastVisibleSymbol(0) {}
-
-    LookupItem(const FullySpecifiedType &type, Symbol *lastVisibleSymbol)
-        : _type(type), _lastVisibleSymbol(lastVisibleSymbol) {}
-
-    FullySpecifiedType type() const { return _type; }
-    void setType(const FullySpecifiedType &type) { _type = type; }
-
-    Symbol *lastVisibleSymbol() const { return _lastVisibleSymbol; }
-    void setLastVisibleSymbol(Symbol *symbol) { _lastVisibleSymbol = symbol; }
-
-    bool operator == (const LookupItem &other) const
-    {
-        if (_type == other._type)
-            return _lastVisibleSymbol == other._lastVisibleSymbol;
-
-        return false;
-    }
+class CreateBindings;
 
-    bool operator != (const LookupItem &result) const
-    { return ! operator == (result); }
-
-private:
-    FullySpecifiedType _type;
-    Symbol *_lastVisibleSymbol;
-};
-
-class CPLUSPLUS_EXPORT LookupContext
+class CPLUSPLUS_EXPORT ClassOrNamespace
 {
 public:
-    LookupContext(Control *control = 0);
-
-    LookupContext(Symbol *symbol,
-                  Document::Ptr expressionDocument,
-                  Document::Ptr thisDocument,
-                  const Snapshot &snapshot);
+    ClassOrNamespace(CreateBindings *factory, ClassOrNamespace *parent);
 
-    bool isValid() const;
+    const TemplateNameId *templateId() const;
+    ClassOrNamespace *parent() const;
+    QList<ClassOrNamespace *> usings() const;
+    QList<Enum *> enums() const;
+    QList<Symbol *> symbols() const;
 
-    Control *control() const;
-    Symbol *symbol() const;
-    Document::Ptr expressionDocument() const;
-    Document::Ptr thisDocument() const;
-    Document::Ptr document(const QString &fileName) const;
-    Snapshot snapshot() const;
+    ClassOrNamespace *globalNamespace() const;
 
-    static Symbol *canonicalSymbol(const QList<Symbol *> &candidates,
-                                   NamespaceBinding *globalNamespaceBinding);
+    QList<Symbol *> lookup(const Name *name);
+    QList<Symbol *> find(const Name *name);
 
-    static Symbol *canonicalSymbol(Symbol *symbol,
-                                   NamespaceBinding *globalNamespaceBinding);
+    ClassOrNamespace *lookupType(const Name *name);
+    ClassOrNamespace *findType(const Name *name);
 
-    static Symbol *canonicalSymbol(const QList<LookupItem> &candidates,
-                                   NamespaceBinding *globalNamespaceBinding);
+private:
+    /// \internal
+    void flush();
 
-    QList<Symbol *> resolve(const Name *name) const
-    { return resolve(name, visibleScopes()); }
+    /// \internal
+    ClassOrNamespace *findOrCreateType(const Name *name);
 
-    QList<Symbol *> resolveNamespace(const Name *name) const
-    { return resolveNamespace(name, visibleScopes()); }
+    void addTodo(Symbol *symbol);
+    void addSymbol(Symbol *symbol);
+    void addEnum(Enum *e);
+    void addUsing(ClassOrNamespace *u);
+    void addNestedType(const Name *alias, ClassOrNamespace *e);
 
-    QList<Symbol *> resolveClass(const Name *name) const
-    { return resolveClass(name, visibleScopes()); }
+    QList<Symbol *> lookup_helper(const Name *name, bool searchInEnclosingScope);
 
-    QList<Symbol *> resolveClassOrNamespace(const Name *name) const
-    { return resolveClassOrNamespace(name, visibleScopes()); }
+    void lookup_helper(const Name *name, ClassOrNamespace *binding,
+                       QList<Symbol *> *result,
+                       QSet<ClassOrNamespace *> *processed,
+                       const TemplateNameId *templateId);
 
-    QList<Symbol *> resolveObjCClass(const Name *name) const
-    { return resolveObjCClass(name, visibleScopes()); }
+    ClassOrNamespace *lookupType_helper(const Name *name, QSet<ClassOrNamespace *> *processed,
+                                        bool searchInEnclosingScope);
 
-    QList<Symbol *> resolveObjCProtocol(const Name *name) const
-    { return resolveObjCProtocol(name, visibleScopes()); }
+    ClassOrNamespace *nestedType(const Name *name) const;
 
-    enum ResolveMode {
-        ResolveSymbol           = 0x01,
-        ResolveClass            = 0x02,
-        ResolveNamespace        = 0x04,
-        ResolveClassOrNamespace = ResolveClass  | ResolveNamespace,
-        ResolveObjCClass        = 0x08,
-        ResolveObjCProtocol     = 0x10,
-        ResolveAll              = ResolveSymbol | ResolveClassOrNamespace | ResolveObjCClass | ResolveObjCProtocol
+private:
+    struct CompareName: std::binary_function<const Name *, const Name *, bool> {
+        bool operator()(const Name *name, const Name *other) const;
     };
 
-    QList<Symbol *> resolve(const Name *name, const QList<Scope *> &visibleScopes,
-                            ResolveMode mode = ResolveAll) const;
-
-    QList<Symbol *> resolveNamespace(const Name *name, const QList<Scope *> &visibleScopes) const
-    { return resolve(name, visibleScopes, ResolveNamespace); }
-
-    QList<Symbol *> resolveClass(const Name *name, const QList<Scope *> &visibleScopes) const
-    { return resolve(name, visibleScopes, ResolveClass); }
-
-    QList<Symbol *> resolveClassOrNamespace(const Name *name, const QList<Scope *> &visibleScopes) const
-    { return resolve(name, visibleScopes, ResolveClassOrNamespace); }
-
-    QList<Symbol *> resolveObjCClass(const Name *name, const QList<Scope *> &visibleScopes) const
-    { return resolve(name, visibleScopes, ResolveObjCClass); }
-
-    QList<Symbol *> resolveObjCProtocol(const Name *name, const QList<Scope *> &visibleScopes) const
-    { return resolve(name, visibleScopes, ResolveObjCProtocol); }
-
-    QList<Scope *> visibleScopes() const
-    { return _visibleScopes; }
-
-    QList<Scope *> visibleScopes(Symbol *symbol) const;
-    QList<Scope *> visibleScopes(const LookupItem &result) const;
-
-    QList<Scope *> expand(const QList<Scope *> &scopes) const;
+private:
+    typedef std::map<const Name *, ClassOrNamespace *, CompareName> Table;
+    CreateBindings *_factory;
+    ClassOrNamespace *_parent;
+    QList<Symbol *> _symbols;
+    QList<ClassOrNamespace *> _usings;
+    Table _classOrNamespaces;
+    QList<Enum *> _enums;
+    QList<Symbol *> _todo;
+
+    // it's an instantiation.
+    const TemplateNameId *_templateId;
+
+    // templates
+    QList<ClassOrNamespace *> _instantiations;
+
+    friend class CreateBindings;
+};
 
-    void expand(const QList<Scope *> &scopes, QList<Scope *> *expandedScopes) const;
+class CPLUSPLUS_EXPORT CreateBindings: protected SymbolVisitor
+{
+    Q_DISABLE_COPY(CreateBindings)
 
-    void expand(Scope *scope, const QList<Scope *> &visibleScopes,
-                QList<Scope *> *expandedScopes) const;
+public:
+    CreateBindings(Document::Ptr thisDocument, const Snapshot &snapshot);
+    virtual ~CreateBindings();
 
-    void expandNamespace(Namespace *namespaceSymbol,
-                         const QList<Scope *> &visibleScopes,
-                         QList<Scope *> *expandedScopes) const;
+    /// Returns the binding for the global namespace.
+    ClassOrNamespace *globalNamespace() const;
 
-    void expandClass(Class *classSymbol,
-                     const QList<Scope *> &visibleScopes,
-                     QList<Scope *> *expandedScopes) const;
+    /// Finds the binding associated to the given symbol.
+    ClassOrNamespace *lookupType(Symbol *symbol);
 
-    void expandBlock(Block *blockSymbol,
-                     const QList<Scope *> &visibleScopes,
-                     QList<Scope *> *expandedScopes) const;
+    /// Returns the Control that must be used to create temporary symbols.
+    /// \internal
+    Control *control() const;
 
-    void expandFunction(Function *functionSymbol,
-                        const QList<Scope *> &visibleScopes,
-                        QList<Scope *> *expandedScopes) const;
+    /// Searches in \a scope for symbols with the given \a name.
+    /// Store the result in \a results.
+    /// \internal
+    void lookupInScope(const Name *name, Scope *scope, QList<Symbol *> *result,
+                       const TemplateNameId *templateId);
+
+    /// Create bindings for the symbols reachable from \a rootSymbol.
+    /// \internal
+    void process(Symbol *rootSymbol, ClassOrNamespace *classOrNamespace);
+
+    /// Create an empty ClassOrNamespace binding with the given \a parent.
+    /// \internal
+    ClassOrNamespace *allocClassOrNamespace(ClassOrNamespace *parent);
+
+protected:
+    using SymbolVisitor::visit;
+
+    /// Change the current ClassOrNamespace binding.
+    ClassOrNamespace *switchCurrentClassOrNamespace(ClassOrNamespace *classOrNamespace);
+
+    /// Enters the ClassOrNamespace binding associated with the given \a symbol.
+    ClassOrNamespace *enterClassOrNamespaceBinding(Symbol *symbol);
+
+    /// Enters a ClassOrNamespace binding for the given \a symbol in the global
+    /// namespace binding.
+    ClassOrNamespace *enterGlobalClassOrNamespace(Symbol *symbol);
+
+    /// Creates bindings for the given \a document.
+    void process(Document::Ptr document);
+
+    /// Creates bindings for the symbols reachable from the \a root symbol.
+    void process(Symbol *root);
+
+    virtual bool visit(Namespace *ns);
+    virtual bool visit(Class *klass);
+    virtual bool visit(ForwardClassDeclaration *klass);
+    virtual bool visit(Enum *e);
+    virtual bool visit(Declaration *decl);
+    virtual bool visit(Function *);
+    virtual bool visit(BaseClass *b);
+    virtual bool visit(UsingNamespaceDirective *u);
+    virtual bool visit(NamespaceAlias *a);
+
+    virtual bool visit(ObjCClass *klass);
+    virtual bool visit(ObjCBaseClass *b);
+    virtual bool visit(ObjCForwardClassDeclaration *klass);
+    virtual bool visit(ObjCProtocol *proto);
+    virtual bool visit(ObjCBaseProtocol *b);
+    virtual bool visit(ObjCForwardProtocolDeclaration *proto);
+    virtual bool visit(ObjCMethod *);
 
-    void expandObjCMethod(ObjCMethod *method,
-                          const QList<Scope *> &visibleScopes,
-                          QList<Scope *> *expandedScopes) const;
+private:
+    Control *_control;
+    Snapshot _snapshot;
+    QSet<Namespace *> _processed;
+    QList<ClassOrNamespace *> _entities;
+    ClassOrNamespace *_globalNamespace;
+    ClassOrNamespace *_currentClassOrNamespace;
+};
 
-    void expandObjCClass(ObjCClass *klass,
-                         const QList<Scope *> &visibleScopes,
-                         QList<Scope *> *expandedScopes) const;
+class CPLUSPLUS_EXPORT LookupContext
+{
+public:
+    LookupContext();
 
-    void expandObjCProtocol(ObjCProtocol *protocol,
-                            const QList<Scope *> &visibleScopes,
-                            QList<Scope *> *expandedScopes) const;
+    LookupContext(Document::Ptr thisDocument,
+                  const Snapshot &snapshot);
 
-    void expandEnumOrAnonymousSymbol(ScopedSymbol *scopedSymbol,
-                                     QList<Scope *> *expandedScopes) const;
+    LookupContext(Document::Ptr expressionDocument,
+                  Document::Ptr thisDocument,
+                  const Snapshot &snapshot);
 
-private:
-    static Symbol *canonicalSymbol(Symbol *symbol);
+    LookupContext(const LookupContext &other);
+    LookupContext &operator = (const LookupContext &other);
 
-    QList<Symbol *> resolveQualifiedNameId(const QualifiedNameId *q,
-                                           const QList<Scope *> &visibleScopes,
-                                           ResolveMode mode) const;
+    Document::Ptr expressionDocument() const;
+    Document::Ptr thisDocument() const;
+    Document::Ptr document(const QString &fileName) const;
+    Snapshot snapshot() const;
 
-    QList<Symbol *> resolveOperatorNameId(const OperatorNameId *opId,
-                                          const QList<Scope *> &visibleScopes,
-                                          ResolveMode mode) const;
+    ClassOrNamespace *globalNamespace() const;
 
-    QList<Scope *> resolveNestedNameSpecifier(const QualifiedNameId *q,
-                                               const QList<Scope *> &visibleScopes) const;
+    QList<Symbol *> lookup(const Name *name, Scope *scope) const;
+    ClassOrNamespace *lookupType(const Name *name, Scope *scope) const;
+    ClassOrNamespace *lookupType(Symbol *symbol) const;
 
-    const Identifier *identifier(const Name *name) const;
+    /// \internal
+    QSharedPointer<CreateBindings> bindings() const;
 
-    QList<Scope *> buildVisibleScopes();
+    /// \internal
+    void setBindings(QSharedPointer<CreateBindings> bindings);
 
-    void buildVisibleScopes_helper(Document::Ptr doc, QList<Scope *> *scopes,
-                                   QSet<QString> *processed);
+    Control *control() const; // ### deprecate
 
-    static bool maybeValidSymbol(Symbol *symbol,
-                                 ResolveMode mode,
-                                 const QList<Symbol *> &candidates);
+    static QList<const Name *> fullyQualifiedName(Symbol *symbol);
 
 private:
-    Control *_control;
-
-    // The current symbol.
-    Symbol *_symbol;
-
     // The current expression.
     Document::Ptr _expressionDocument;
 
@@ -224,18 +235,10 @@ private:
     // All documents.
     Snapshot _snapshot;
 
-    // Visible scopes.
-    QList<Scope *> _visibleScopes;
+    // Bindings
+    mutable QSharedPointer<CreateBindings> _bindings;
 };
 
-uint qHash(const CPlusPlus::LookupItem &result);
-
 } // end of namespace CPlusPlus
 
-#if defined(Q_CC_MSVC) && _MSC_VER <= 1300
-//this ensures that code outside QmlJS can use the hash function
-//it also a workaround for some compilers
-inline uint qHash(const CPlusPlus::LookupItem &item) { return CPlusPlus::qHash(item); }
-#endif
-
 #endif // CPLUSPLUS_LOOKUPCONTEXT_H
diff --git a/src/libs/cplusplus/LookupItem.cpp b/src/libs/cplusplus/LookupItem.cpp
new file mode 100644 (file)
index 0000000..2502c02
--- /dev/null
@@ -0,0 +1,82 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "LookupItem.h"
+#include <FullySpecifiedType.h>
+#include <Symbol.h>
+#include <Control.h>
+
+#include <QtDebug>
+
+using namespace CPlusPlus;
+
+uint CPlusPlus::qHash(const CPlusPlus::LookupItem &key)
+{
+    const uint h1 = QT_PREPEND_NAMESPACE(qHash)(key.type().type());
+    const uint h2 = QT_PREPEND_NAMESPACE(qHash)(key.scope());
+    return ((h1 << 16) | (h1 >> 16)) ^ h2;
+}
+
+LookupItem::LookupItem()
+    : _scope(0), _declaration(0)
+{ }
+
+FullySpecifiedType LookupItem::type() const
+{ return _type; }
+
+void LookupItem::setType(const FullySpecifiedType &type)
+{ _type = type; }
+
+Symbol *LookupItem::declaration() const
+{ return _declaration; }
+
+void LookupItem::setDeclaration(Symbol *declaration)
+{ _declaration = declaration; }
+
+Scope *LookupItem::scope() const
+{
+    if (! _scope && _declaration)
+        return _declaration->scope();
+
+    return _scope;
+}
+
+void LookupItem::setScope(Scope *scope)
+{ _scope = scope; }
+
+bool LookupItem::operator == (const LookupItem &other) const
+{
+    if (_type == other._type && _declaration == other._declaration && _scope == other._scope)
+        return true;
+
+    return false;
+}
+
+bool LookupItem::operator != (const LookupItem &result) const
+{ return ! operator == (result); }
diff --git a/src/libs/cplusplus/LookupItem.h b/src/libs/cplusplus/LookupItem.h
new file mode 100644 (file)
index 0000000..14ba99c
--- /dev/null
@@ -0,0 +1,81 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef CPLUSPLUS_LOOKUPITEM_H
+#define CPLUSPLUS_LOOKUPITEM_H
+
+#include <FullySpecifiedType.h>
+#include <QtCore/QHash>
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT LookupItem
+{
+public:
+    /// Constructs an null LookupItem.
+    LookupItem();
+
+    /// Returns this item's type.
+    FullySpecifiedType type() const;
+
+    /// Sets this item's type.
+    void setType(const FullySpecifiedType &type);
+
+    /// Returns the last visible symbol.
+    Symbol *declaration() const;
+
+    /// Sets the last visible symbol.
+    void setDeclaration(Symbol *declaration);
+
+    /// Returns this item's scope.
+    Scope *scope() const;
+
+    /// Sets this item's scope.
+    void setScope(Scope *scope);
+
+    bool operator == (const LookupItem &other) const;
+    bool operator != (const LookupItem &other) const;
+
+private:
+    FullySpecifiedType _type;
+    Scope *_scope;
+    Symbol *_declaration;
+};
+
+uint qHash(const CPlusPlus::LookupItem &result);
+
+} // end of namespace CPlusPlus
+
+#if defined(Q_CC_MSVC) && _MSC_VER <= 1300
+//this ensures that code outside QmlJS can use the hash function
+//it also a workaround for some compilers
+inline uint qHash(const CPlusPlus::LookupItem &item) { return CPlusPlus::qHash(item); }
+#endif
+
+#endif // CPLUSPLUS_LOOKUPITEM_H
index 1b19ed4..a6b5203 100644 (file)
@@ -30,7 +30,7 @@
 #include "ResolveExpression.h"
 #include "LookupContext.h"
 #include "Overview.h"
-#include "GenTemplateInstance.h"
+#include "DeprecatedGenTemplateInstance.h"
 
 #include <Control.h>
 #include <AST.h>
 #include <NameVisitor.h>
 
 #include <QtCore/QList>
-#include <QtCore/QVarLengthArray>
 #include <QtCore/QtDebug>
 
 using namespace CPlusPlus;
 
 namespace {
 
+const bool debug = ! qgetenv("CPLUSPLUS_DEBUG").isEmpty();
+
 template <typename _Tp>
 static QList<_Tp> removeDuplicates(const QList<_Tp> &results)
 {
@@ -73,6 +74,7 @@ static QList<_Tp> removeDuplicates(const QList<_Tp> &results)
 /////////////////////////////////////////////////////////////////////
 ResolveExpression::ResolveExpression(const LookupContext &context)
     : ASTVisitor(context.expressionDocument()->translationUnit()),
+      _scope(0),
       _context(context),
       sem(context.expressionDocument()->translationUnit())
 { }
@@ -80,44 +82,54 @@ ResolveExpression::ResolveExpression(const LookupContext &context)
 ResolveExpression::~ResolveExpression()
 { }
 
-QList<LookupItem> ResolveExpression::operator()(ExpressionAST *ast)
+QList<LookupItem> ResolveExpression::operator()(ExpressionAST *ast, Scope *scope)
+{ return resolve(ast, scope); }
+
+QList<LookupItem> ResolveExpression::resolve(ExpressionAST *ast, Scope *scope)
+{
+    Q_ASSERT(scope != 0);
+
+    Scope *previousVisibleSymbol = _scope;
+    _scope = scope;
+    const QList<LookupItem> result = resolve(ast);
+    _scope = previousVisibleSymbol;
+    return result;
+}
+
+QList<LookupItem> ResolveExpression::resolve(ExpressionAST *ast)
 {
     const QList<LookupItem> previousResults = switchResults(QList<LookupItem>());
     accept(ast);
     return removeDuplicates(switchResults(previousResults));
 }
 
-QList<LookupItem>
-ResolveExpression::switchResults(const QList<LookupItem> &results)
+QList<LookupItem> ResolveExpression::switchResults(const QList<LookupItem> &results)
 {
     const QList<LookupItem> previousResults = _results;
     _results = results;
     return previousResults;
 }
 
-void ResolveExpression::addResults(const QList<LookupItem> &results)
+void ResolveExpression::addResults(const QList<Symbol *> &symbols)
 {
-    foreach (const LookupItem r, results)
-        addResult(r);
+    foreach (Symbol *symbol, symbols) {
+        LookupItem item;
+        item.setType(symbol->type());
+        item.setScope(symbol->scope());
+        item.setDeclaration(symbol);
+        _results.append(item);
+    }
 }
 
-void ResolveExpression::addResult(const FullySpecifiedType &ty, Symbol *symbol)
-{ return addResult(LookupItem(ty, symbol)); }
-
-void ResolveExpression::addResult(const LookupItem &r)
+void ResolveExpression::addResult(const FullySpecifiedType &ty, Scope *scope)
 {
-    LookupItem p = r;
+    LookupItem item;
+    item.setType(ty);
+    item.setScope(scope);
 
-    if (! p.lastVisibleSymbol())
-        p.setLastVisibleSymbol(_context.symbol());
-
-    if (! _results.contains(p))
-        _results.append(p);
+    _results.append(item);
 }
 
-QList<Scope *> ResolveExpression::visibleScopes(const LookupItem &result) const
-{ return _context.visibleScopes(result); }
-
 bool ResolveExpression::visit(BinaryExpressionAST *ast)
 {
     if (tokenKind(ast->binary_op_token) == T_COMMA && ast->right_expression && ast->right_expression->asQtMethod() != 0) {
@@ -130,9 +142,14 @@ bool ResolveExpression::visit(BinaryExpressionAST *ast)
         QtMethodAST *qtMethod = ast->right_expression->asQtMethod();
         if (DeclaratorAST *d = qtMethod->declarator) {
             if (d->core_declarator) {
-                if (DeclaratorIdAST *declaratorId = d->core_declarator->asDeclaratorId())
-                    if (NameAST *nameAST = declaratorId->name)
-                        _results = resolveMemberExpression(_results, T_ARROW, nameAST->name);
+                if (DeclaratorIdAST *declaratorId = d->core_declarator->asDeclaratorId()) {
+                    if (NameAST *nameAST = declaratorId->name) {
+                        if (ClassOrNamespace *binding = baseExpression(_results, T_ARROW)) {
+                            _results.clear();
+                            addResults(binding->lookup(nameAST->name));
+                        }
+                    }
+                }
             }
         }
 
@@ -145,7 +162,9 @@ bool ResolveExpression::visit(BinaryExpressionAST *ast)
 
 bool ResolveExpression::visit(CastExpressionAST *ast)
 {
-    addResult(sem.check(ast->type_id, _context.expressionDocument()->globalSymbols()));
+    Scope *dummyScope = _context.expressionDocument()->globalSymbols();
+    FullySpecifiedType ty = sem.check(ast->type_id, dummyScope);
+    addResult(ty, _scope);
     return false;
 }
 
@@ -168,14 +187,16 @@ bool ResolveExpression::visit(ConditionalExpressionAST *ast)
 
 bool ResolveExpression::visit(CppCastExpressionAST *ast)
 {
-    addResult(sem.check(ast->type_id, _context.expressionDocument()->globalSymbols()));
+    Scope *dummyScope = _context.expressionDocument()->globalSymbols();
+    FullySpecifiedType ty = sem.check(ast->type_id, dummyScope);
+    addResult(ty, _scope);
     return false;
 }
 
 bool ResolveExpression::visit(DeleteExpressionAST *)
 {
     FullySpecifiedType ty(control()->voidType());
-    addResult(ty);
+    addResult(ty, _scope);
     return false;
 }
 
@@ -188,11 +209,11 @@ bool ResolveExpression::visit(ArrayInitializerAST *)
 bool ResolveExpression::visit(NewExpressionAST *ast)
 {
     if (ast->new_type_id) {
-        Scope *scope = _context.expressionDocument()->globalSymbols();
-        FullySpecifiedType ty = sem.check(ast->new_type_id->type_specifier_list, scope);
-        ty = sem.check(ast->new_type_id->ptr_operator_list, ty, scope);
+        Scope *dummyScope = _context.expressionDocument()->globalSymbols();
+        FullySpecifiedType ty = sem.check(ast->new_type_id->type_specifier_list, dummyScope);
+        ty = sem.check(ast->new_type_id->ptr_operator_list, ty, dummyScope);
         FullySpecifiedType ptrTy(control()->pointerType(ty));
-        addResult(ptrTy);
+        addResult(ptrTy, _scope);
     }
     // nothing to do.
     return false;
@@ -206,7 +227,7 @@ bool ResolveExpression::visit(TypeidExpressionAST *)
 
     const Name *q = control()->qualifiedNameId(std_type_info, 2, /*global=*/ true);
     FullySpecifiedType ty(control()->namedType(q));
-    addResult(ty);
+    addResult(ty, _scope);
 
     return false;
 }
@@ -227,9 +248,8 @@ bool ResolveExpression::visit(PostfixExpressionAST *ast)
 {
     accept(ast->base_expression);
 
-    for (PostfixListAST *it = ast->postfix_expression_list; it; it = it->next) {
+    for (PostfixListAST *it = ast->postfix_expression_list; it; it = it->next)
         accept(it->value);
-    }
 
     return false;
 }
@@ -238,7 +258,7 @@ bool ResolveExpression::visit(SizeofExpressionAST *)
 {
     FullySpecifiedType ty(control()->integerType(IntegerType::Int));
     ty.setUnsigned(true);
-    addResult(ty);
+    addResult(ty, _scope);
     return false;
 }
 
@@ -270,14 +290,14 @@ bool ResolveExpression::visit(NumericLiteralAST *ast)
     if (literal->isUnsigned())
         ty.setUnsigned(true);
 
-    addResult(ty);
+    addResult(ty, _scope);
     return false;
 }
 
 bool ResolveExpression::visit(BoolLiteralAST *)
 {
     FullySpecifiedType ty(control()->integerType(IntegerType::Bool));
-    addResult(ty);
+    addResult(ty, _scope);
     return false;
 }
 
@@ -289,10 +309,7 @@ bool ResolveExpression::visit(ThisExpressionAST *)
 
 void ResolveExpression::thisObject()
 {
-    if (! _context.symbol())
-        return;
-
-    Scope *scope = _context.symbol()->scope();
+    Scope *scope = _scope;
     for (; scope; scope = scope->enclosingScope()) {
         if (scope->isFunctionScope()) {
             Function *fun = scope->owner()->asFunction();
@@ -300,7 +317,7 @@ void ResolveExpression::thisObject()
                 Class *klass = cscope->owner()->asClass();
                 FullySpecifiedType classTy(control()->namedType(klass->name()));
                 FullySpecifiedType ptrTy(control()->pointerType(classTy));
-                addResult(ptrTy, fun);
+                addResult(ptrTy, fun->scope());
                 break;
             } else if (const QualifiedNameId *q = fun->name()->asQualifiedNameId()) {
                 const Name *nestedNameSpecifier = 0;
@@ -310,7 +327,7 @@ void ResolveExpression::thisObject()
                     nestedNameSpecifier = control()->qualifiedNameId(q->names(), q->nameCount() - 1);
                 FullySpecifiedType classTy(control()->namedType(nestedNameSpecifier));
                 FullySpecifiedType ptrTy(control()->pointerType(classTy));
-                addResult(ptrTy, fun);
+                addResult(ptrTy, fun->scope());
                 break;
             }
         }
@@ -337,7 +354,7 @@ bool ResolveExpression::visit(StringLiteralAST *)
     FullySpecifiedType charTy = control()->integerType(IntegerType::Char);
     charTy.setConst(true);
     FullySpecifiedType ty(control()->pointerType(charTy));
-    addResult(ty);
+    addResult(ty, _scope);
     return false;
 }
 
@@ -387,61 +404,42 @@ bool ResolveExpression::visit(CompoundLiteralAST *ast)
 
 bool ResolveExpression::visit(QualifiedNameAST *ast)
 {
-    ResolveClass resolveClass;
-    const Name *name = ast->name;
-
-    QList<Symbol *> symbols = _context.resolve(name);
-    foreach (Symbol *symbol, symbols) {
-        if (symbol->isTypedef()) {
-            if (NamedType *namedTy = symbol->type()->asNamedType()) {
-                const LookupItem r(namedTy, symbol);
-                const QList<Symbol *> resolvedClasses =
-                        resolveClass(namedTy->name(), r, _context);
-                if (resolvedClasses.count()) {
-                    foreach (Symbol *s, resolvedClasses) {
-                        addResult(s->type(), s);
-                    }
-                    continue;
-                }
-            }
-        }
-        addResult(symbol->type(), symbol);
+    if (const Name *name = ast->name) {
+        const QList<Symbol *> candidates = _context.lookup(name, _scope);
+        addResults(candidates);
     }
-    return false;
-}
 
-bool ResolveExpression::visit(OperatorFunctionIdAST *)
-{
     return false;
 }
 
-bool ResolveExpression::visit(ConversionFunctionIdAST *)
+bool ResolveExpression::visit(SimpleNameAST *ast)
 {
+    const QList<Symbol *> candidates = _context.lookup(ast->name, _scope);
+    addResults(candidates);
     return false;
 }
 
-bool ResolveExpression::visit(SimpleNameAST *ast)
+bool ResolveExpression::visit(TemplateIdAST *ast)
 {
-    QList<Symbol *> symbols = _context.resolve(ast->name);
-    foreach (Symbol *symbol, symbols)
-        addResult(symbol->type(), symbol);
-
+    const QList<Symbol *> candidates = _context.lookup(ast->name, _scope);
+    addResults(candidates);
     return false;
 }
 
 bool ResolveExpression::visit(DestructorNameAST *)
 {
     FullySpecifiedType ty(control()->voidType());
-    addResult(ty);
+    addResult(ty, _scope);
     return false;
 }
 
-bool ResolveExpression::visit(TemplateIdAST *ast)
+bool ResolveExpression::visit(OperatorFunctionIdAST *)
 {
-    QList<Symbol *> symbols = _context.resolve(ast->name);
-    foreach (Symbol *symbol, symbols)
-        addResult(symbol->type(), symbol);
+    return false;
+}
 
+bool ResolveExpression::visit(ConversionFunctionIdAST *)
+{
     return false;
 }
 
@@ -470,8 +468,6 @@ bool ResolveExpression::maybeValidPrototype(Function *funTy, unsigned actualArgu
 
 bool ResolveExpression::visit(CallAST *ast)
 {
-    ResolveClass resolveClass;
-
     const QList<LookupItem> baseResults = _results;
     _results.clear();
 
@@ -480,7 +476,7 @@ bool ResolveExpression::visit(CallAST *ast)
 
     //QList< QList<Result> > arguments;
     for (ExpressionListAST *exprIt = ast->expression_list; exprIt; exprIt = exprIt->next) {
-        //arguments.append(operator()(exprIt->expression));
+        //arguments.append(resolve(exprIt->expression));
         ++actualArgumentCount;
     }
 
@@ -488,32 +484,28 @@ bool ResolveExpression::visit(CallAST *ast)
 
     foreach (const LookupItem &result, baseResults) {
         FullySpecifiedType ty = result.type().simplified();
-        Symbol *lastVisibleSymbol = result.lastVisibleSymbol();
+        Scope *scope = result.scope();
 
         if (NamedType *namedTy = ty->asNamedType()) {
-            const QList<Symbol *> classObjectCandidates = resolveClass(namedTy->name(), result, _context);
-
-            foreach (Symbol *classObject, classObjectCandidates) {
-                const QList<LookupItem> overloads = resolveMember(functionCallOp, classObject->asClass(), namedTy->name());
-
-                foreach (const LookupItem &o, overloads) {
-                    FullySpecifiedType overloadTy = o.type().simplified();
-
-                    if (Function *funTy = overloadTy->asFunctionType()) {
-                        if (maybeValidPrototype(funTy, actualArgumentCount))
-                            addResult(funTy->returnType().simplified(), lastVisibleSymbol);
+            if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), scope)) {
+                foreach (Symbol *overload, b->find(functionCallOp)) {
+                    if (Function *funTy = overload->type()->asFunctionType()) {
+                        if (maybeValidPrototype(funTy, actualArgumentCount)) {
+                            Function *proto = instantiate(namedTy->name(), funTy)->asFunctionType();
+                            addResult(proto->returnType().simplified(), scope);
+                        }
                     }
                 }
             }
 
         } else if (Function *funTy = ty->asFunctionType()) {
             if (maybeValidPrototype(funTy, actualArgumentCount))
-                addResult(funTy->returnType().simplified(), lastVisibleSymbol);
+                addResult(funTy->returnType().simplified(), scope);
 
         } else if (Class *classTy = ty->asClassType()) {
             // Constructor call
             FullySpecifiedType ctorTy = control()->namedType(classTy->name());
-            addResult(ctorTy, lastVisibleSymbol);
+            addResult(ctorTy, scope);
         }
     }
 
@@ -525,38 +517,30 @@ bool ResolveExpression::visit(ArrayAccessAST *ast)
     const QList<LookupItem> baseResults = _results;
     _results.clear();
 
-    const QList<LookupItem> indexResults = operator()(ast->expression);
-    ResolveClass resolveClass;
+    const QList<LookupItem> indexResults = resolve(ast->expression);
 
     const Name *arrayAccessOp = control()->operatorNameId(OperatorNameId::ArrayAccessOp);
 
     foreach (const LookupItem &result, baseResults) {
         FullySpecifiedType ty = result.type().simplified();
-        Symbol *contextSymbol = result.lastVisibleSymbol();
+        Scope *scope = result.scope();
 
         if (PointerType *ptrTy = ty->asPointerType()) {
-            addResult(ptrTy->elementType().simplified(), contextSymbol);
+            addResult(ptrTy->elementType().simplified(), scope);
 
         } else if (ArrayType *arrTy = ty->asArrayType()) {
-            addResult(arrTy->elementType().simplified(), contextSymbol);
+            addResult(arrTy->elementType().simplified(), scope);
 
         } else if (NamedType *namedTy = ty->asNamedType()) {
-            const QList<Symbol *> classObjectCandidates =
-                    resolveClass(namedTy->name(), result, _context);
-
-            foreach (Symbol *classObject, classObjectCandidates) {
-                Q_ASSERT(classObject->isClass());
-
-                const QList<LookupItem> overloads =
-                        resolveMember(arrayAccessOp, classObject->asClass(), namedTy->name());
-
-                foreach (LookupItem r, overloads) {
-                    FullySpecifiedType ty = r.type().simplified();
-                    if (Function *funTy = ty->asFunctionType()) {
-                        ty = funTy->returnType().simplified();
-                        addResult(ty, funTy);
+            if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), scope)) {
+                foreach (Symbol *overload, b->find(arrayAccessOp)) {
+                    if (Function *funTy = overload->type()->asFunctionType()) {
+                        Function *proto = instantiate(namedTy->name(), funTy)->asFunctionType();
+                        // ### TODO: check the actual arguments
+                        addResult(proto->returnType().simplified(), scope);
                     }
                 }
+
             }
         }
     }
@@ -567,7 +551,8 @@ bool ResolveExpression::visit(MemberAccessAST *ast)
 {
     // The candidate types for the base expression are stored in
     // _results.
-    QList<LookupItem> baseResults = _results;
+    const QList<LookupItem> baseResults = _results;
+    _results.clear();
 
     // Evaluate the expression-id that follows the access operator.
     const Name *memberName = 0;
@@ -577,227 +562,86 @@ bool ResolveExpression::visit(MemberAccessAST *ast)
     // Remember the access operator.
     const int accessOp = tokenKind(ast->access_token);
 
-    _results = resolveMemberExpression(baseResults, accessOp, memberName);
+    if (ClassOrNamespace *binding = baseExpression(baseResults, accessOp))
+        addResults(binding->lookup(memberName));
 
     return false;
 }
 
-QList<LookupItem>
-ResolveExpression::resolveBaseExpression(const QList<LookupItem> &baseResults, int accessOp,
-                                         bool *replacedDotOperator) const
-{
-    QList<LookupItem> results;
-
-    if (baseResults.isEmpty())
-        return results;
-
-    LookupItem result = baseResults.first();
-    FullySpecifiedType ty = result.type().simplified();
-    Symbol *lastVisibleSymbol = result.lastVisibleSymbol();
-
-    if (Function *funTy = ty->asFunctionType()) {
-        if (funTy->isAmbiguous())
-            ty = funTy->returnType().simplified();
-    }
-
-    if (accessOp == T_ARROW)  {
-        if (lastVisibleSymbol && ty->isClassType() && ! lastVisibleSymbol->isClass()) {
-            // ### remove ! lastVisibleSymbol->isClass() from the condition.
-            results.append(LookupItem(ty, lastVisibleSymbol));
-
-        } else if (NamedType *namedTy = ty->asNamedType()) {
-            // ### This code is pretty slow.
-            const QList<Symbol *> candidates = _context.resolve(namedTy->name());
-
-            foreach (Symbol *candidate, candidates) {
-                if (candidate->isTypedef()) {
-                    FullySpecifiedType declTy = candidate->type().simplified();
-                    const LookupItem r(declTy, candidate);
-
-                    // update the result
-                    result = r;
-
-                    // refresh the cached ty and lastVisibileSymbol.
-                    ty = result.type().simplified();
-                    lastVisibleSymbol = result.lastVisibleSymbol();
-                    break;
-                }
-            }
-        }
-
-        if (NamedType *namedTy = ty->asNamedType()) {
-            ResolveClass resolveClass;
-            const Name *arrowAccessOp = control()->operatorNameId(OperatorNameId::ArrowOp);
-            const QList<Symbol *> candidates = resolveClass(namedTy->name(), result, _context);
-
-            foreach (Symbol *classObject, candidates) {
-                const QList<LookupItem> overloads = resolveMember(arrowAccessOp, classObject->asClass(),
-                                                              namedTy->name());
-
-                foreach (const LookupItem &r, overloads) {
-                    FullySpecifiedType typeOfOverloadFunction = r.type().simplified();
-                    Symbol *lastVisibleSymbol = r.lastVisibleSymbol();
-                    Function *funTy = typeOfOverloadFunction->asFunctionType();
-                    if (! funTy)
-                        continue;
-
-                    typeOfOverloadFunction = funTy->returnType().simplified();
-
-                    if (PointerType *ptrTy = typeOfOverloadFunction->asPointerType()) {
-                        FullySpecifiedType elementTy = ptrTy->elementType().simplified();
-
-                        if (elementTy->isNamedType())
-                            results.append(LookupItem(elementTy, lastVisibleSymbol));
-                    }
-                }
-            }
-        } else if (PointerType *ptrTy = ty->asPointerType()) {
-            FullySpecifiedType elementTy = ptrTy->elementType().simplified();
-
-            if (elementTy->isNamedType() || elementTy->isClassType())
-                results.append(LookupItem(elementTy, lastVisibleSymbol));
-        }
-    } else if (accessOp == T_DOT) {
-        if (replacedDotOperator) {
-            if (PointerType *ptrTy = ty->asPointerType()) {
-                *replacedDotOperator = true;
-                ty = ptrTy->elementType().simplified();
-            } else if (ArrayType *arrTy = ty->asArrayType()) {
-                *replacedDotOperator = true;
-                ty = arrTy->elementType().simplified();
-            }
-        }
-
-        if (NamedType *namedTy = ty->asNamedType()) {
-            const QList<Scope *> visibleScopes = _context.visibleScopes(result);
-            const QList<Symbol *> candidates = _context.resolve(namedTy->name(), visibleScopes);
-            foreach (Symbol *candidate, candidates) {
-                if (candidate->isTypedef() && candidate->type()->isNamedType()) {
-                    ty = candidate->type();
-                    lastVisibleSymbol = candidate;
-                    break;
-                } else if (TypenameArgument *arg = candidate->asTypenameArgument()) {
-                    ty = arg->type();
-                    lastVisibleSymbol = candidate;
-                    break;
-                }
-            }
-
-            results.append(LookupItem(ty, lastVisibleSymbol));
-
-        } else if (Function *fun = ty->asFunctionType()) {
-            Scope *funScope = fun->scope();
-
-            if (funScope && (funScope->isBlockScope() || funScope->isNamespaceScope())) {
-                FullySpecifiedType retTy = fun->returnType().simplified();
-                results.append(LookupItem(retTy, lastVisibleSymbol));
-            }
-        }
-    }
-
-    return removeDuplicates(results);
-}
-
-QList<LookupItem>
-ResolveExpression::resolveMemberExpression(const QList<LookupItem> &baseResults,
-                                           unsigned accessOp,
-                                           const Name *memberName,
-                                           bool *replacedDotOperator) const
+ClassOrNamespace *ResolveExpression::findClass(const FullySpecifiedType &originalTy, Scope *scope) const
 {
-    ResolveClass resolveClass;
-    QList<LookupItem> results;
+    FullySpecifiedType ty = originalTy.simplified();
+    ClassOrNamespace *binding = 0;
 
-    const QList<LookupItem> classObjectResults = resolveBaseExpression(baseResults, accessOp, replacedDotOperator);
-    foreach (const LookupItem &r, classObjectResults) {
-        FullySpecifiedType ty = r.type();
+    if (Class *klass = ty->asClassType())
+        binding = _context.lookupType(klass);
 
-        if (Class *klass = ty->asClassType())
-            results += resolveMember(memberName, klass);
+    else if (NamedType *namedTy = ty->asNamedType())
+        binding = _context.lookupType(namedTy->name(), scope);
 
-        else if (NamedType *namedTy = ty->asNamedType()) {
-            const Name *className = namedTy->name();
-            const QList<Symbol *> classes = resolveClass(className, r, _context);
+    else if (Function *funTy = ty->asFunctionType())
+        return findClass(funTy->returnType(), scope);
 
-            foreach (Symbol *c, classes) {
-                if (Class *klass = c->asClass())
-                    results += resolveMember(memberName, klass, className);
-            }
-        }
-    }
-
-    return removeDuplicates(results);
+    return binding;
 }
 
-QList<LookupItem>
-ResolveExpression::resolveMember(const Name *memberName, Class *klass,
-                                 const Name *className) const
+ClassOrNamespace *ResolveExpression::baseExpression(const QList<LookupItem> &baseResults,
+                                                    int accessOp,
+                                                    bool *replacedDotOperator) const
 {
-    QList<LookupItem> results;
-
-    if (! className)
-        className = klass->name();
-
-    if (! className)
-        return results;
-
-    QList<Scope *> scopes;
-    _context.expand(klass->members(), _context.visibleScopes(), &scopes);
+    foreach (const LookupItem &r, baseResults) {
+        FullySpecifiedType ty = r.type().simplified();
+        Scope *scope = r.scope();
 
-    const QList<Symbol *> candidates = _context.resolve(memberName, scopes);
-
-    foreach (Symbol *candidate, candidates) {
-        FullySpecifiedType ty = candidate->type();
-        const Name *unqualifiedNameId = className;
-
-        if (const QualifiedNameId *q = className->asQualifiedNameId())
-            unqualifiedNameId = q->unqualifiedNameId();
-
-        if (const TemplateNameId *templId = unqualifiedNameId->asTemplateNameId()) {
-            GenTemplateInstance::Substitution subst;
-
-            for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) {
-                FullySpecifiedType templArgTy = templId->templateArgumentAt(i);
-
-                if (i < klass->templateParameterCount()) {
-                    const Name *templArgName = klass->templateParameterAt(i)->name();
-                    if (templArgName && templArgName->identifier()) {
-                        const Identifier *templArgId = templArgName->identifier();
-                        subst.append(qMakePair(templArgId, templArgTy));
+        if (accessOp == T_ARROW) {
+            if (PointerType *ptrTy = ty->asPointerType()) {
+                if (ClassOrNamespace *binding = findClass(ptrTy->elementType(), scope))
+                    return binding;
+
+            } else if (ClassOrNamespace *binding = findClass(ty, scope)) {
+                // lookup for overloads of operator->
+                const OperatorNameId *arrowOp = control()->operatorNameId(OperatorNameId::ArrowOp);
+
+                foreach (Symbol *overload, binding->find(arrowOp)) {
+                    if (overload->type()->isFunctionType()) {
+                        FullySpecifiedType overloadTy = DeprecatedGenTemplateInstance::instantiate(binding->templateId(), overload, control());
+                        Function *instantiatedFunction = overloadTy->asFunctionType();
+                        Q_ASSERT(instantiatedFunction != 0);
+
+                        FullySpecifiedType retTy = instantiatedFunction->returnType().simplified();
+
+                        if (PointerType *ptrTy = retTy->asPointerType()) {
+                            if (ClassOrNamespace *retBinding = findClass(ptrTy->elementType(), overload->scope()))
+                                return retBinding;
+
+                            else if (debug) {
+                                Overview oo;
+                                qDebug() << "no class for:" << oo(ptrTy->elementType());
+                            }
+                        }
                     }
                 }
             }
+        } else if (accessOp == T_DOT) {
+            if (replacedDotOperator) {
+                if (PointerType *ptrTy = ty->asPointerType()) {
+                    // replace . with ->
+                    ty = ptrTy->elementType();
+                    *replacedDotOperator = true;
+                }
+            }
 
-            GenTemplateInstance inst(_context, subst);
-            ty = inst(candidate);
+            if (ClassOrNamespace *binding = findClass(ty, scope))
+                return binding;
         }
-
-        results.append(LookupItem(ty, candidate));
     }
 
-    return removeDuplicates(results);
+    return 0;
 }
 
-
-QList<LookupItem>
-ResolveExpression::resolveMember(const Name *memberName, ObjCClass *klass) const
+FullySpecifiedType ResolveExpression::instantiate(const Name *className, Symbol *candidate) const
 {
-    QList<LookupItem> results;
-
-    if (!memberName || !klass)
-        return results;
-
-    QList<Scope *> scopes;
-    _context.expand(klass->members(), _context.visibleScopes(), &scopes);
-
-    QList<Symbol *> candidates = _context.resolve(memberName, scopes);
-
-    foreach (Symbol *candidate, candidates) {
-        FullySpecifiedType ty = candidate->type();
-
-        results.append(LookupItem(ty, candidate));
-    }
-
-    return removeDuplicates(results);
+    return DeprecatedGenTemplateInstance::instantiate(className, candidate, _context.control());
 }
 
 bool ResolveExpression::visit(PostIncrDecrAST *)
@@ -807,135 +651,28 @@ bool ResolveExpression::visit(PostIncrDecrAST *)
 
 bool ResolveExpression::visit(ObjCMessageExpressionAST *ast)
 {
-    QList<LookupItem> receiverResults = operator()(ast->receiver_expression);
+    const QList<LookupItem> receiverResults = resolve(ast->receiver_expression);
 
-    if (!receiverResults.isEmpty()) {
-        LookupItem result = receiverResults.first();
+    foreach (const LookupItem &result, receiverResults) {
         FullySpecifiedType ty = result.type().simplified();
-        const Name *klassName = 0;
+        ClassOrNamespace *binding = 0;
 
-        if (const ObjCClass *classTy = ty->asObjCClassType()) {
+        if (ObjCClass *clazz = ty->asObjCClassType()) {
             // static access, e.g.:
-            // [NSObject description];
-            klassName = classTy->name();
-        } else if (const PointerType *ptrTy = ty->asPointerType()) {
-            const FullySpecifiedType pointeeTy = ptrTy->elementType();
-            if (pointeeTy && pointeeTy->isNamedType()) {
+            //   [NSObject description];
+            binding = _context.lookupType(clazz);
+        } else if (PointerType *ptrTy = ty->asPointerType()) {
+            if (NamedType *namedTy = ptrTy->asNamedType()) {
                 // dynamic access, e.g.:
-                // NSObject *obj = ...; [obj release];
-                klassName = pointeeTy->asNamedType()->name();
+                //   NSObject *obj = ...; [obj release];
+                binding = _context.lookupType(namedTy->name(), result.scope());
             }
         }
 
-        if (klassName&&ast->selector && ast->selector->name) {
-            ResolveObjCClass resolveObjCClass;
-            QList<Symbol *> resolvedSymbols = resolveObjCClass(klassName, result, _context);
-            foreach (Symbol *resolvedSymbol, resolvedSymbols)
-                if (ObjCClass *klass = resolvedSymbol->asObjCClass())
-                    _results.append(resolveMember(ast->selector->name, klass));
-        }
+        if (binding)
+            addResults(binding->lookup(ast->selector->name));
     }
 
     return false;
 }
 
-////////////////////////////////////////////////////////////////////////////////
-ResolveClass::ResolveClass()
-{ }
-
-QList<Symbol *> ResolveClass::operator()(const Name *name,
-                                         const LookupItem &p,
-                                         const LookupContext &context)
-{
-    const QList<LookupItem> previousBlackList = _blackList;
-    const QList<Symbol *> symbols = resolveClass(name, p, context);
-    _blackList = previousBlackList;
-    return symbols;
-}
-
-QList<Symbol *> ResolveClass::resolveClass(const Name *name,
-                                           const LookupItem &p,
-                                           const LookupContext &context)
-{
-    QList<Symbol *> resolvedSymbols;
-
-    if (_blackList.contains(p))
-        return resolvedSymbols;
-
-    _blackList.append(p);
-
-    const QList<Symbol *> candidates =
-            context.resolve(name, context.visibleScopes(p));
-
-    foreach (Symbol *candidate, candidates) {
-        if (Class *klass = candidate->asClass()) {
-            if (resolvedSymbols.contains(klass))
-                continue; // we already know about `klass'
-            resolvedSymbols.append(klass);
-        } else if (candidate->isTypedef()) {
-            if (Declaration *decl = candidate->asDeclaration()) {
-                if (Class *asClass = decl->type()->asClassType()) {
-                    // typedef struct { } Point;
-                    // Point pt;
-                    // pt.
-                    resolvedSymbols.append(asClass);
-                } else {
-                    // typedef Point Boh;
-                    // Boh b;
-                    // b.
-                    FullySpecifiedType declType = decl->type().simplified();
-                    if (NamedType *namedTy = declType->asNamedType()) {
-                        const LookupItem r(declType, decl);
-                        resolvedSymbols += resolveClass(namedTy->name(), r, context);
-                    }
-                }
-            }
-        } else if (Declaration *decl = candidate->asDeclaration()) {
-            if (Function *funTy = decl->type()->asFunctionType()) {
-                // QString foo("ciao");
-                // foo.
-                if (funTy->scope() && (funTy->scope()->isBlockScope() || funTy->scope()->isNamespaceScope())) {
-                    FullySpecifiedType retTy = funTy->returnType().simplified();
-                    if (NamedType *namedTy = retTy->asNamedType()) {
-                        const LookupItem r(retTy, decl);
-                        resolvedSymbols += resolveClass(namedTy->name(), r, context);
-                    }
-                }
-            }
-        }
-    }
-
-    return resolvedSymbols;
-}
-
-ResolveObjCClass::ResolveObjCClass()
-{}
-
-QList<Symbol *> ResolveObjCClass::operator ()(const Name *name,
-                                              const LookupItem &p,
-                                              const LookupContext &context)
-{
-    QList<Symbol *> resolvedSymbols;
-
-    const QList<Symbol *> candidates =
-            context.resolve(name, context.visibleScopes(p));
-
-    foreach (Symbol *candidate, candidates) {
-        if (ObjCClass *klass = candidate->asObjCClass()) {
-            if (resolvedSymbols.contains(klass))
-                continue; // we already know about `klass'
-            resolvedSymbols.append(klass);
-        } else if (candidate->isTypedef()) {
-            if (Declaration *decl = candidate->asDeclaration()) {
-                if (decl->type()->isObjCClassType()) {
-                    ObjCClass *klass = decl->type()->asObjCClassType();
-                    if (resolvedSymbols.contains(klass))
-                        continue;
-                    resolvedSymbols.append(klass);
-                }
-            }
-        }
-    }
-
-    return resolvedSymbols;
-}
index eba5b29..830b210 100644 (file)
@@ -44,29 +44,25 @@ public:
     ResolveExpression(const LookupContext &context);
     virtual ~ResolveExpression();
 
-    QList<LookupItem> operator()(ExpressionAST *ast);
+    QList<LookupItem> operator()(ExpressionAST *ast, Scope *scope);
+    QList<LookupItem> resolve(ExpressionAST *ast, Scope *scope);
 
-    QList<LookupItem> resolveMemberExpression(const QList<LookupItem> &baseResults,
-                                          unsigned accessOp,
-                                          const Name *memberName,
-                                          bool *replacedDotOperator = 0) const;
+    ClassOrNamespace *baseExpression(const QList<LookupItem> &baseResults,
+                                     int accessOp,
+                                     bool *replacedDotOperator = 0) const;
 
-    QList<LookupItem> resolveBaseExpression(const QList<LookupItem> &baseResults,
-                                        int accessOp,
-                                        bool *replacedDotOperator = 0) const;
-
-    QList<LookupItem> resolveMember(const Name *memberName, Class *klass,
-                                    const Name *className = 0) const;
+protected:
+    ClassOrNamespace *findClass(const FullySpecifiedType &ty, Scope *scope) const;
 
-    QList<LookupItem> resolveMember(const Name *memberName, ObjCClass *klass) const;
+    QList<LookupItem> resolve(ExpressionAST *ast);
 
-protected:
     QList<LookupItem> switchResults(const QList<LookupItem> &symbols);
+    FullySpecifiedType instantiate(const Name *className, Symbol *candidate) const;
 
     void thisObject();
-    void addResult(const FullySpecifiedType &ty, Symbol *symbol = 0);
-    void addResult(const LookupItem &result);
-    void addResults(const QList<LookupItem> &results);
+
+    void addResult(const FullySpecifiedType &ty, Scope *scope);
+    void addResults(const QList<Symbol *> &symbols);
 
     bool maybeValidPrototype(Function *funTy, unsigned actualArgumentCount) const;
 
@@ -113,44 +109,14 @@ protected:
     // Objective-C expressions
     virtual bool visit(ObjCMessageExpressionAST *ast);
 
-    QList<Scope *> visibleScopes(const LookupItem &result) const;
-
 private:
+    Scope *_scope;
     LookupContext _context;
     Semantic sem;
     QList<LookupItem> _results;
     Symbol *_declSymbol;
 };
 
-class CPLUSPLUS_EXPORT ResolveClass
-{
-public:
-    ResolveClass();
-
-    QList<Symbol *> operator()(const Name *name,
-                               const LookupItem &p,
-                               const LookupContext &context);
-
-private:
-    QList<Symbol *> resolveClass(const Name *name,
-                                 const LookupItem &p,
-                                 const LookupContext &context);
-
-private:
-    QList<LookupItem> _blackList;
-};
-
-class CPLUSPLUS_EXPORT ResolveObjCClass
-{
-public:
-    ResolveObjCClass();
-
-    QList<Symbol *> operator()(const Name *name,
-                               const LookupItem &p,
-                               const LookupContext &context);
-};
-
-
 } // end of namespace CPlusPlus
 
 #endif // CPLUSPLUS_RESOLVEEXPRESSION_H
index ce5fa1b..40e8776 100644 (file)
 #include "pp.h"
 
 #include <AST.h>
+#include <Symbol.h>
 #include <QSet>
 
 using namespace CPlusPlus;
 
 TypeOfExpression::TypeOfExpression():
-    m_ast(0)
+    m_ast(0),
+    m_scope(0)
 {
 }
 
-Snapshot TypeOfExpression::snapshot() const
+void TypeOfExpression::reset()
 {
-    return m_snapshot;
+    m_thisDocument.clear();
+    m_snapshot = Snapshot();
+    m_ast = 0;
+    m_scope = 0;
+    m_lookupContext = LookupContext();
+    m_bindings.clear();
+    m_environment.clear();
 }
 
-void TypeOfExpression::setSnapshot(const Snapshot &documents)
+void TypeOfExpression::init(Document::Ptr thisDocument, const Snapshot &snapshot,
+                            QSharedPointer<CreateBindings> bindings)
 {
-    m_snapshot = documents;
+    m_thisDocument = thisDocument;
+    m_snapshot = snapshot;
+    m_ast = 0;
+    m_scope = 0;
     m_lookupContext = LookupContext();
+    m_bindings = bindings;
+    m_environment.clear();
 }
 
 QList<LookupItem> TypeOfExpression::operator()(const QString &expression,
-                                           Document::Ptr document,
-                                           Symbol *lastVisibleSymbol,
-                                           PreprocessMode mode)
+                                               Scope *scope,
+                                               PreprocessMode mode)
 {
     QString code = expression;
+
     if (mode == Preprocess)
-        code = preprocessedExpression(expression, m_snapshot, document);
+        code = preprocessedExpression(expression);
+
     Document::Ptr expressionDoc = documentForExpression(code);
     expressionDoc->check();
     m_ast = extractExpressionAST(expressionDoc);
 
-    m_lookupContext = LookupContext(lastVisibleSymbol, expressionDoc,
-                                    document, m_snapshot);
+    m_scope = scope;
 
-    ResolveExpression resolveExpression(m_lookupContext);
-    return resolveExpression(m_ast);
+    m_lookupContext = LookupContext(expressionDoc, m_thisDocument, m_snapshot);
+    m_lookupContext.setBindings(m_bindings);
+
+    ResolveExpression resolve(m_lookupContext);
+    return resolve(m_ast, scope);
 }
 
-QString TypeOfExpression::preprocess(const QString &expression,
-                                     Document::Ptr document) const
+QString TypeOfExpression::preprocess(const QString &expression) const
 {
-    return preprocessedExpression(expression, m_snapshot, document);
+    return preprocessedExpression(expression);
 }
 
 ExpressionAST *TypeOfExpression::ast() const
@@ -84,7 +100,12 @@ ExpressionAST *TypeOfExpression::ast() const
     return m_ast;
 }
 
-const LookupContext &TypeOfExpression::lookupContext() const
+Scope *TypeOfExpression::scope() const
+{
+    return m_scope;
+}
+
+const LookupContext &TypeOfExpression::context() const
 {
     return m_lookupContext;
 }
@@ -112,37 +133,35 @@ Document::Ptr TypeOfExpression::documentForExpression(const QString &expression)
     return doc;
 }
 
-void TypeOfExpression::processEnvironment(Snapshot documents,
-                                          Document::Ptr doc, Environment *env,
+void TypeOfExpression::processEnvironment(Document::Ptr doc, Environment *env,
                                           QSet<QString> *processed) const
 {
-    if (! doc)
-        return;
-    if (processed->contains(doc->fileName()))
-        return;
-    processed->insert(doc->fileName());
-    foreach (const Document::Include &incl, doc->includes()) {
-        processEnvironment(documents,
-                           documents.document(incl.fileName()),
-                           env, processed);
+    if (doc && ! processed->contains(doc->fileName())) {
+        processed->insert(doc->fileName());
+
+        foreach (const Document::Include &incl, doc->includes())
+            processEnvironment(m_snapshot.document(incl.fileName()), env, processed);
+
+        foreach (const Macro &macro, doc->definedMacros())
+            env->bind(macro);
     }
-    foreach (const Macro &macro, doc->definedMacros())
-        env->bind(macro);
 }
 
-QString TypeOfExpression::preprocessedExpression(const QString &expression,
-                                                 Snapshot documents,
-                                                 Document::Ptr thisDocument) const
+QString TypeOfExpression::preprocessedExpression(const QString &expression) const
 {
     if (expression.trimmed().isEmpty())
         return expression;
 
-    Environment env;
-    QSet<QString> processed;
-    processEnvironment(documents, thisDocument,
-                       &env, &processed);
+    if (! m_environment) {
+        Environment *env = new Environment(); // ### cache the environment.
+
+        QSet<QString> processed;
+        processEnvironment(m_thisDocument, env, &processed);
+        m_environment = QSharedPointer<Environment>(env);
+    }
+
     const QByteArray code = expression.toUtf8();
-    Preprocessor preproc(0, &env);
+    Preprocessor preproc(0, m_environment.data());
     const QByteArray preprocessedCode = preproc("<expression>", code);
     return QString::fromUtf8(preprocessedCode.constData(), preprocessedCode.size());
 }
index a5b0989..9d32e57 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "CppDocument.h"
 #include "LookupContext.h"
+#include "PreprocessorEnvironment.h"
 
 #include <ASTfwd.h>
 #include <QtCore/QMap>
@@ -44,11 +45,11 @@ class Macro;
 
 class CPLUSPLUS_EXPORT TypeOfExpression
 {
+    Q_DISABLE_COPY(TypeOfExpression)
+
 public:
     TypeOfExpression();
 
-    Snapshot snapshot() const;
-
     /**
      * Sets the documents used to evaluate expressions. Should be set before
      * calling this functor.
@@ -56,7 +57,10 @@ public:
      * Also clears the lookup context, so can be used to make sure references
      * to the documents previously used are removed.
      */
-    void setSnapshot(const Snapshot &documents);
+    void init(Document::Ptr thisDocument, const Snapshot &snapshot,
+              QSharedPointer<CreateBindings> bindings = QSharedPointer<CreateBindings>());
+
+    void reset();
 
     enum PreprocessMode {
         NoPreprocess,
@@ -72,14 +76,13 @@ public:
      * has been made!
      *
      * @param expression        The expression to evaluate.
-     * @param document          The document the expression is part of.
-     * @param lastVisibleSymbol The last visible symbol in the document.
+     * @param scope             The scope enclosing the expression.
      */
-    QList<LookupItem> operator()(const QString &expression, Document::Ptr document,
-                             Symbol *lastVisibleSymbol,
-                             PreprocessMode mode = NoPreprocess);
+    QList<LookupItem> operator()(const QString &expression,
+                                 Scope *scope,
+                                 PreprocessMode mode = NoPreprocess);
 
-    QString preprocess(const QString &expression, Document::Ptr document) const;
+    QString preprocess(const QString &expression) const;
 
     /**
      * Returns the AST of the last evaluated expression.
@@ -89,7 +92,8 @@ public:
     /**
      * Returns the lookup context of the last evaluated expression.
      */
-    const LookupContext &lookupContext() const;
+    const LookupContext &context() const;
+    Scope *scope() const;
 
     ExpressionAST *expressionAST() const;
 
@@ -97,17 +101,19 @@ private:
     ExpressionAST *extractExpressionAST(Document::Ptr doc) const;
     Document::Ptr documentForExpression(const QString &expression) const;
 
-    void processEnvironment(CPlusPlus::Snapshot documents,
-                            CPlusPlus::Document::Ptr doc, CPlusPlus::Environment *env,
+    void processEnvironment(Document::Ptr doc, Environment *env,
                             QSet<QString> *processed) const;
 
-    QString preprocessedExpression(const QString &expression,
-                                   CPlusPlus::Snapshot documents,
-                                   CPlusPlus::Document::Ptr thisDocument) const;
+    QString preprocessedExpression(const QString &expression) const;
 
+private:
+    Document::Ptr m_thisDocument;
     Snapshot m_snapshot;
+    QSharedPointer<CreateBindings> m_bindings;
     ExpressionAST *m_ast;
+    Scope *m_scope;
     LookupContext m_lookupContext;
+    mutable QSharedPointer<Environment> m_environment;
 };
 
 } // namespace CPlusPlus
index c5d4ff0..07bf949 100644 (file)
@@ -34,10 +34,12 @@ HEADERS += \
     $$PWD/TypeOfExpression.h \
     $$PWD/TypePrettyPrinter.h \
     $$PWD/ResolveExpression.h \
+    $$PWD/LookupItem.h \
     $$PWD/LookupContext.h \
+    $$PWD/DeprecatedLookupContext.h \
     $$PWD/CppBindings.h \
     $$PWD/ASTParent.h \
-    $$PWD/GenTemplateInstance.h \
+    $$PWD/DeprecatedGenTemplateInstance.h \
     $$PWD/FindUsages.h \
     $$PWD/CheckUndefinedSymbols.h \
     $$PWD/DependencyTable.h \
@@ -59,10 +61,12 @@ SOURCES += \
     $$PWD/TypeOfExpression.cpp \
     $$PWD/TypePrettyPrinter.cpp \
     $$PWD/ResolveExpression.cpp \
+    $$PWD/LookupItem.cpp \
     $$PWD/LookupContext.cpp \
+    $$PWD/DeprecatedLookupContext.cpp \
     $$PWD/CppBindings.cpp \
     $$PWD/ASTParent.cpp \
-    $$PWD/GenTemplateInstance.cpp \
+    $$PWD/DeprecatedGenTemplateInstance.cpp \
     $$PWD/FindUsages.cpp \
     $$PWD/CheckUndefinedSymbols.cpp \
     $$PWD/DependencyTable.cpp \
index 41800a0..59b260e 100644 (file)
@@ -42,7 +42,7 @@ struct CheckableMessageBoxPrivate;
 
 /* A messagebox suitable for questions with a
  * "Do not ask me again" checkbox. Emulates the QMessageBox API with
- * static conveniences. */
+ * static conveniences. The message label can open external URLs. */
 
 class QTCREATOR_UTILS_EXPORT CheckableMessageBox : public QDialog
 {
index 7491a84..cc60cf7 100644 (file)
@@ -2,14 +2,6 @@
 <ui version="4.0">
  <class>Utils::CheckableMessageBox</class>
  <widget class="QDialog" name="Utils::CheckableMessageBox">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>195</width>
-    <height>107</height>
-   </rect>
-  </property>
   <property name="windowTitle">
    <string>Dialog</string>
   </property>
      <item>
       <layout class="QVBoxLayout" name="verticalLayout">
        <item>
-        <widget class="QLabel" name="pixmapLabel"/>
+        <widget class="QLabel" name="pixmapLabel">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+        </widget>
        </item>
        <item>
         <spacer name="pixmapSpacer">
      </item>
      <item>
       <widget class="QLabel" name="messageLabel">
+       <property name="minimumSize">
+        <size>
+         <width>300</width>
+         <height>0</height>
+        </size>
+       </property>
        <property name="text">
-        <string>TextLabel</string>
+        <string notr="true">dummyText</string>
+       </property>
+       <property name="wordWrap">
+        <bool>true</bool>
+       </property>
+       <property name="openExternalLinks">
+        <bool>true</bool>
+       </property>
+       <property name="textInteractionFlags">
+        <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
        </property>
       </widget>
      </item>
@@ -66,7 +80,7 @@
      <item>
       <widget class="QCheckBox" name="checkBox">
        <property name="text">
-        <string>CheckBox</string>
+        <string notr="true">CheckBox</string>
        </property>
       </widget>
      </item>
index c6e4b62..761a040 100644 (file)
 **************************************************************************/
 
 #include "uncommentselection.h"
+#include <QtCore/QtGlobal>
 #include <QtGui/QPlainTextEdit>
 #include <QtGui/QTextCursor>
 #include <QtGui/QTextBlock>
 #include <QtGui/QTextDocument>
 
-void Utils::unCommentSelection(QPlainTextEdit *edit)
+using namespace Utils;
+
+CommentDefinition::CommentDefinition() :
+    m_afterWhiteSpaces(false),
+    m_singleLine(QLatin1String("//")),
+    m_multiLineStart(QLatin1String("/*")),
+    m_multiLineEnd(QLatin1String("*/"))
+{}
+
+CommentDefinition &CommentDefinition::setAfterWhiteSpaces(const bool afterWhiteSpaces)
+{
+    m_afterWhiteSpaces = afterWhiteSpaces;
+    return *this;
+}
+
+CommentDefinition &CommentDefinition::setSingleLine(const QString &singleLine)
+{
+    m_singleLine = singleLine;
+    return *this;
+}
+
+CommentDefinition &CommentDefinition::setMultiLineStart(const QString &multiLineStart)
+{
+    m_multiLineStart = multiLineStart;
+    return *this;
+}
+
+CommentDefinition &CommentDefinition::setMultiLineEnd(const QString &multiLineEnd)
 {
+    m_multiLineEnd = multiLineEnd;
+    return *this;
+}
+
+bool CommentDefinition::isAfterWhiteSpaces() const
+{ return m_afterWhiteSpaces; }
+
+const QString &CommentDefinition::singleLine() const
+{ return m_singleLine; }
+
+const QString &CommentDefinition::multiLineStart() const
+{ return m_multiLineStart; }
+
+const QString &CommentDefinition::multiLineEnd() const
+{ return m_multiLineEnd; }
+
+bool CommentDefinition::hasSingleLineStyle() const
+{ return !m_singleLine.isEmpty(); }
+
+bool CommentDefinition::hasMultiLineStyle() const
+{ return !m_multiLineStart.isEmpty() && !m_multiLineEnd.isEmpty(); }
+
+void CommentDefinition::clearCommentStyles()
+{
+    m_singleLine.clear();
+    m_multiLineStart.clear();
+    m_multiLineEnd.clear();
+}
+
+namespace {
+
+bool isComment(const QString &text,
+               int index,
+               const CommentDefinition &definition,
+               const QString & (CommentDefinition::* comment) () const)
+{
+    const QString &commentType = ((definition).*(comment))();
+    const int length = commentType.length();
+
+    Q_ASSERT(text.length() - index >= length);
+
+    int i = 0;
+    while (i < length) {
+        if (text.at(index + i) != commentType.at(i))
+            return false;
+        ++i;
+    }
+    return true;
+}
+
+} // namespace anynomous
+
+
+void Utils::unCommentSelection(QPlainTextEdit *edit, const CommentDefinition &definition)
+{
+    if (!definition.hasSingleLineStyle() && !definition.hasMultiLineStyle())
+        return;
+
     QTextCursor cursor = edit->textCursor();
     QTextDocument *doc = cursor.document();
     cursor.beginEditBlock();
@@ -53,78 +139,116 @@ void Utils::unCommentSelection(QPlainTextEdit *edit)
         endBlock = endBlock.previous();
     }
 
-    bool doCStyleUncomment = false;
-    bool doCStyleComment = false;
-    bool doCppStyleUncomment = false;
+    bool doMultiLineStyleUncomment = false;
+    bool doMultiLineStyleComment = false;
+    bool doSingleLineStyleUncomment = false;
 
     bool hasSelection = cursor.hasSelection();
 
-    if (hasSelection) {
+    if (hasSelection && definition.hasMultiLineStyle()) {
+
         QString startText = startBlock.text();
         int startPos = start - startBlock.position();
+        const int multiLineStartLength = definition.multiLineStart().length();
         bool hasLeadingCharacters = !startText.left(startPos).trimmed().isEmpty();
-        if ((startPos >= 2
-            && startText.at(startPos-2) == QLatin1Char('/')
-             && startText.at(startPos-1) == QLatin1Char('*'))) {
-            startPos -= 2;
-            start -= 2;
-        }
 
-        bool hasSelStart = (startPos < startText.length() - 1
-                            && startText.at(startPos) == QLatin1Char('/')
-                            && startText.at(startPos+1) == QLatin1Char('*'));
+        if (startPos >= multiLineStartLength
+            && isComment(startText,
+                         startPos - multiLineStartLength,
+                         definition,
+                         &CommentDefinition::multiLineStart)) {
+            startPos -= multiLineStartLength;
+            start -= multiLineStartLength;
+        }
 
+        bool hasSelStart = (startPos <= startText.length() - multiLineStartLength
+                            && isComment(startText,
+                                         startPos,
+                                         definition,
+                                         &CommentDefinition::multiLineStart));
 
         QString endText = endBlock.text();
         int endPos = end - endBlock.position();
-        bool hasTrailingCharacters = !endText.left(endPos).remove(QLatin1String("//")).trimmed().isEmpty()
-                                     && !endText.mid(endPos).trimmed().isEmpty();
-        if ((endPos <= endText.length() - 2
-            && endText.at(endPos) == QLatin1Char('*')
-             && endText.at(endPos+1) == QLatin1Char('/'))) {
-            endPos += 2;
-            end += 2;
+        const int multiLineEndLength = definition.multiLineEnd().length();
+        bool hasTrailingCharacters =
+                !endText.left(endPos).remove(definition.singleLine()).trimmed().isEmpty()
+                && !endText.mid(endPos).trimmed().isEmpty();
+
+        if (endPos <= endText.length() - multiLineEndLength
+            && isComment(endText, endPos, definition, &CommentDefinition::multiLineEnd)) {
+            endPos += multiLineEndLength;
+            end += multiLineEndLength;
         }
 
-        bool hasSelEnd = (endPos >= 2
-                          && endText.at(endPos-2) == QLatin1Char('*')
-                          && endText.at(endPos-1) == QLatin1Char('/'));
+        bool hasSelEnd = (endPos >= multiLineEndLength
+                          && isComment(endText,
+                                       endPos - multiLineEndLength,
+                                       definition,
+                                       &CommentDefinition::multiLineEnd));
+
+        doMultiLineStyleUncomment = hasSelStart && hasSelEnd;
+        doMultiLineStyleComment = !doMultiLineStyleUncomment
+                                  && (hasLeadingCharacters
+                                      || hasTrailingCharacters
+                                      || !definition.hasSingleLineStyle());
+    } else if (!hasSelection && !definition.hasSingleLineStyle()) {
 
-        doCStyleUncomment = hasSelStart && hasSelEnd;
-        doCStyleComment = !doCStyleUncomment && (hasLeadingCharacters || hasTrailingCharacters);
+        QString text = startBlock.text().trimmed();
+        doMultiLineStyleUncomment = text.startsWith(definition.multiLineStart())
+                                    && text.endsWith(definition.multiLineEnd());
+        doMultiLineStyleComment = !doMultiLineStyleUncomment && !text.isEmpty();
+
+        start = startBlock.position();
+        end = endBlock.position() + endBlock.length() - 1;
+
+        if (doMultiLineStyleUncomment) {
+            int offset = 0;
+            text = startBlock.text();
+            const int length = text.length();
+            while (offset < length && text.at(offset).isSpace())
+                ++offset;
+            start += offset;
+        }
     }
 
-    if (doCStyleUncomment) {
+    if (doMultiLineStyleUncomment) {
         cursor.setPosition(end);
-        cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, 2);
+        cursor.movePosition(QTextCursor::PreviousCharacter,
+                            QTextCursor::KeepAnchor,
+                            definition.multiLineEnd().length());
         cursor.removeSelectedText();
         cursor.setPosition(start);
-        cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 2);
+        cursor.movePosition(QTextCursor::NextCharacter,
+                            QTextCursor::KeepAnchor,
+                            definition.multiLineStart().length());
         cursor.removeSelectedText();
-    } else if (doCStyleComment) {
+    } else if (doMultiLineStyleComment) {
         cursor.setPosition(end);
-        cursor.insertText(QLatin1String("*/"));
+        cursor.insertText(definition.multiLineEnd());
         cursor.setPosition(start);
-        cursor.insertText(QLatin1String("/*"));
+        cursor.insertText(definition.multiLineStart());
     } else {
         endBlock = endBlock.next();
-        doCppStyleUncomment = true;
+        doSingleLineStyleUncomment = true;
         for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
             QString text = block.text().trimmed();
-            if (!text.isEmpty() && !text.startsWith(QLatin1String("//"))) {
-                doCppStyleUncomment = false;
+            if (!text.isEmpty() && !text.startsWith(definition.singleLine())) {
+                doSingleLineStyleUncomment = false;
                 break;
             }
         }
+
+        const int singleLineLength = definition.singleLine().length();
         for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
-            if (doCppStyleUncomment) {
+            if (doSingleLineStyleUncomment) {
                 QString text = block.text();
                 int i = 0;
-                while (i < text.size() - 1) {
-                    if (text.at(i) == QLatin1Char('/')
-                        && text.at(i + 1) == QLatin1Char('/')) {
+                while (i <= text.size() - singleLineLength) {
+                    if (isComment(text, i, definition, &CommentDefinition::singleLine)) {
                         cursor.setPosition(block.position() + i);
-                        cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 2);
+                        cursor.movePosition(QTextCursor::NextCharacter,
+                                            QTextCursor::KeepAnchor,
+                                            singleLineLength);
                         cursor.removeSelectedText();
                         break;
                     }
@@ -136,8 +260,11 @@ void Utils::unCommentSelection(QPlainTextEdit *edit)
                 QString text = block.text();
                 foreach(QChar c, text) {
                     if (!c.isSpace()) {
-                        cursor.setPosition(block.position());
-                        cursor.insertText(QLatin1String("//"));
+                        if (definition.isAfterWhiteSpaces())
+                            cursor.setPosition(block.position() + text.indexOf(c));
+                        else
+                            cursor.setPosition(block.position());
+                        cursor.insertText(definition.singleLine());
                         break;
                     }
                 }
@@ -146,10 +273,10 @@ void Utils::unCommentSelection(QPlainTextEdit *edit)
     }
 
     // adjust selection when commenting out
-    if (hasSelection && !doCStyleUncomment && !doCppStyleUncomment) {
+    if (hasSelection && !doMultiLineStyleUncomment && !doSingleLineStyleUncomment) {
         cursor = edit->textCursor();
-        if (!doCStyleComment)
-            start = startBlock.position(); // move the double slashes into the selection
+        if (!doMultiLineStyleComment)
+            start = startBlock.position(); // move the comment into the selection
         int lastSelPos = anchorIsStart ? cursor.position() : cursor.anchor();
         if (anchorIsStart) {
             cursor.setPosition(start);
@@ -163,4 +290,3 @@ void Utils::unCommentSelection(QPlainTextEdit *edit)
 
     cursor.endEditBlock();
 }
-
index 4a4a666..42a7dc1 100644 (file)
 
 #include "utils_global.h"
 
+#include <QtCore/QString>
+
 QT_BEGIN_NAMESPACE
 class QPlainTextEdit;
 QT_END_NAMESPACE
 
 namespace Utils {
 
-QTCREATOR_UTILS_EXPORT void unCommentSelection(QPlainTextEdit *edit);
+class QTCREATOR_UTILS_EXPORT CommentDefinition
+{
+public:
+    CommentDefinition();
+
+    CommentDefinition &setAfterWhiteSpaces(const bool);
+    CommentDefinition &setSingleLine(const QString &singleLine);
+    CommentDefinition &setMultiLineStart(const QString &multiLineStart);
+    CommentDefinition &setMultiLineEnd(const QString &multiLineEnd);
+
+    bool isAfterWhiteSpaces() const;
+    const QString &singleLine() const;
+    const QString &multiLineStart() const;
+    const QString &multiLineEnd() const;
+
+    bool hasSingleLineStyle() const;
+    bool hasMultiLineStyle() const;
+
+    void clearCommentStyles();
+
+private:
+    bool m_afterWhiteSpaces;
+    QString m_singleLine;
+    QString m_multiLineStart;
+    QString m_multiLineEnd;
+};
+
+QTCREATOR_UTILS_EXPORT
+void unCommentSelection(QPlainTextEdit *edit,
+                        const CommentDefinition &definiton = CommentDefinition());
 
 } // end of namespace Utils
 
index bfbe5e3..46026e0 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="BinEditor" version="1.3.84" compatVersion="1.3.84">
+<plugin name="BinEditor" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,7 +14,7 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Binary editor component.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="Core" version="1.3.84"/>
-        <dependency name="TextEditor" version="1.3.84"/>
+        <dependency name="Core" version="2.0.80"/>
+        <dependency name="TextEditor" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 656d80b..6376eee 100644 (file)
@@ -422,8 +422,9 @@ void BinEditor::setLazyData(quint64 startAddr, int range, int blockSize)
     m_baseAddr = static_cast<quint64>(range/2) > startAddr
                 ? 0 : startAddr - range/2;
     m_baseAddr = (m_baseAddr / blockSize) * blockSize;
-    m_size = m_baseAddr != 0 && static_cast<quint64>(range) >= -m_baseAddr
-             ? -m_baseAddr : range;
+    const quint64 maxRange = Q_UINT64_C(0xffffffffffffffff) - m_baseAddr + 1;
+    m_size = m_baseAddr != 0 && static_cast<quint64>(range) >= maxRange
+             ? maxRange : range;
     m_addressBytes = (m_baseAddr + m_size < quint64(1) << 32
                       && m_baseAddr + m_size >= m_baseAddr) ? 4 : 8;
 
index 432df20..6c8bfc9 100644 (file)
@@ -196,6 +196,12 @@ public:
         }
     }
 
+    void rename(const QString &newName) {
+        m_fileName = newName;
+        m_editor->editorInterface()->setDisplayName(QFileInfo(fileName()).fileName());
+        emit changed();
+    }
+
     bool open(const QString &fileName) {
         QFile file(fileName);
         if (file.open(QIODevice::ReadOnly)) {
@@ -305,6 +311,7 @@ public:
         m_toolBar->addWidget(w);
 
         connect(m_editor, SIGNAL(cursorPositionChanged(int)), this, SLOT(updateCursorPosition(int)));
+        connect(m_file, SIGNAL(changed()), this, SIGNAL(changed()));
     }
     ~BinEditorInterface() {
         delete m_editor;
index e8a5d7c..57fdf99 100644 (file)
@@ -155,6 +155,9 @@ ImageViewer::ImageViewer(QObject *parent)
     layout->setMargin(0);
     m_imageView->setLayout(layout);
     layout->addWidget(m_label, 0, 0, 1, 1);
+
+    connect(m_file, SIGNAL(changed()),
+            this, SIGNAL(changed()));
 }
 
 ImageViewer::~ImageViewer()
index 09be3e1..b74ad90 100644 (file)
@@ -70,6 +70,7 @@ public:
     explicit ImageViewerFile(ImageViewer *parent = 0);
 
     bool save(const QString &fileName = QString()) { Q_UNUSED(fileName); return false; }
+    void rename(const QString &newName) { m_fileName = newName; }
     QString fileName() const { return m_fileName; }
 
     QString defaultPath() const { return QString(); }
index 363de9a..fa3c094 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="Bookmarks" version="1.3.84" compatVersion="1.3.84">
+<plugin name="Bookmarks" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,8 +14,8 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Bookmarks in text editors.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="TextEditor" version="1.3.84"/>
-        <dependency name="ProjectExplorer" version="1.3.84"/>
-        <dependency name="Core" version="1.3.84"/>
+        <dependency name="TextEditor" version="2.0.80"/>
+        <dependency name="ProjectExplorer" version="2.0.80"/>
+        <dependency name="Core" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 52bc871..6e1222c 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="CMakeProjectManager" version="1.3.84" compatVersion="1.3.84">
+<plugin name="CMakeProjectManager" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,9 +14,9 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>CMake support</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="TextEditor" version="1.3.84"/>
-        <dependency name="ProjectExplorer" version="1.3.84"/>
-        <dependency name="CppTools" version="1.3.84"/>
-        <dependency name="CppEditor" version="1.3.84"/>
+        <dependency name="TextEditor" version="2.0.80"/>
+        <dependency name="ProjectExplorer" version="2.0.80"/>
+        <dependency name="CppTools" version="2.0.80"/>
+        <dependency name="CppEditor" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 7e92e01..283d076 100644 (file)
@@ -595,6 +595,13 @@ bool CMakeFile::isSaveAsAllowed() const
     return false;
 }
 
+void CMakeFile::rename(const QString &newName)
+{
+    Q_ASSERT(false);
+    Q_UNUSED(newName);
+    // Can't happen....
+}
+
 Core::IFile::ReloadBehavior CMakeFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
 {
     Q_UNUSED(state)
index 3f383cc..36f3945 100644 (file)
@@ -196,6 +196,8 @@ public:
     ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
     void reload(ReloadFlag flag, ChangeType type);
 
+    void rename(const QString &newName);
+
 private:
     CMakeProject *m_project;
     QString m_fileName;
index 4d98025..ce2e2d4 100644 (file)
@@ -43,8 +43,9 @@ bool CMakeProjectNode::hasBuildTargets() const
     return true;
 }
 
-QList<ProjectExplorer::ProjectNode::ProjectAction> CMakeProjectNode::supportedActions() const
+QList<ProjectExplorer::ProjectNode::ProjectAction> CMakeProjectNode::supportedActions(Node *node) const
 {
+    Q_UNUSED(node);
     return QList<ProjectAction>();
 }
 
index dbb6250..6a75e1d 100644 (file)
@@ -42,7 +42,7 @@ class CMakeProjectNode : public ProjectExplorer::ProjectNode
 public:
     CMakeProjectNode(const QString &fileName);
     virtual bool hasBuildTargets() const;
-    virtual QList<ProjectExplorer::ProjectNode::ProjectAction> supportedActions() const;
+    virtual QList<ProjectExplorer::ProjectNode::ProjectAction> supportedActions(Node *node) const;
     virtual bool addSubProjects(const QStringList &proFilePaths);
     virtual bool removeSubProjects(const QStringList &proFilePaths);
     virtual bool addFiles(const ProjectExplorer::FileType fileType,
index f909778..ae65cb2 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="Core" version="1.3.84" compatVersion="1.3.84">
+<plugin name="Core" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
index 0decf8a..9bce32a 100644 (file)
@@ -35,9 +35,9 @@
 namespace Core {
 namespace Constants {
 
-#define IDE_VERSION_MAJOR 1
-#define IDE_VERSION_MINOR 3
-#define IDE_VERSION_RELEASE 84
+#define IDE_VERSION_MAJOR 2
+#define IDE_VERSION_MINOR 0
+#define IDE_VERSION_RELEASE 80
 
 #define STRINGIFY_INTERNAL(x) #x
 #define STRINGIFY(x) STRINGIFY_INTERNAL(x)
index d9d07a2..10b0929 100644 (file)
@@ -130,22 +130,23 @@ EditorView::EditorView(QWidget *parent) :
     {
         m_statusHLine->setFrameStyle(QFrame::HLine);
 
-        m_statusWidget->setFrameStyle(QFrame::Panel | QFrame::Raised);
-        m_statusWidget->setLineWidth(1);
+        m_statusWidget->setFrameStyle(QFrame::NoFrame);
+        m_statusWidget->setLineWidth(0);
         //m_statusWidget->setForegroundRole(QPalette::ToolTipText);
         //m_statusWidget->setBackgroundRole(QPalette::ToolTipBase);
         m_statusWidget->setAutoFillBackground(true);
 
-
         QHBoxLayout *hbox = new QHBoxLayout(m_statusWidget);
-        hbox->setMargin(2);
-        m_statusWidgetLabel = new QLabel("Placeholder");
+        hbox->setContentsMargins(1, 0, 1, 1);
+        m_statusWidgetLabel = new QLabel;
         m_statusWidgetLabel->setForegroundRole(QPalette::ToolTipText);
+        m_statusWidgetLabel->setContentsMargins(3, 0, 3, 0);
         hbox->addWidget(m_statusWidgetLabel);
         hbox->addStretch(1);
 
         m_statusWidgetButton = new QToolButton;
-        m_statusWidgetButton->setText(tr("Placeholder"));
+        m_statusWidgetButton->setContentsMargins(0, 0, 0, 0);
+        //m_statusWidgetButton->setIcon(QIcon(":/core/images/clear.png"));
         hbox->addWidget(m_statusWidgetButton);
 
         m_statusHLine->setVisible(false);
@@ -206,6 +207,7 @@ void EditorView::showEditorStatusBar(const QString &id,
     m_statusWidgetId = id;
     m_statusWidgetLabel->setText(infoText);
     m_statusWidgetButton->setText(buttonText);
+    m_statusWidgetButton->setToolTip(buttonText);
     m_statusWidgetButton->disconnect();
     if (object && member)
         connect(m_statusWidgetButton, SIGNAL(clicked()), object, member);
index b38b522..61c2223 100644 (file)
@@ -123,6 +123,11 @@ struct FileManagerPrivate {
     QString m_lastVisitedDirectory;
     QString m_projectsDirectory;
     bool m_useProjectsDirectory;
+    // When we are callling into a IFile
+    // we don't want to receive a changed()
+    // signal
+    // That makes the code easier
+    IFile *m_blockedIFile;
 };
 
 FileManagerPrivate::FileManagerPrivate(QObject *q, QMainWindow *mw) :
@@ -131,10 +136,11 @@ FileManagerPrivate::FileManagerPrivate(QObject *q, QMainWindow *mw) :
     m_blockActivated(false),
     m_lastVisitedDirectory(QDir::currentPath()),
 #ifdef Q_OS_MAC  // Creator is in bizarre places when launched via finder.
-    m_useProjectsDirectory(true)
+    m_useProjectsDirectory(true),
 #else
-    m_useProjectsDirectory(false)
+    m_useProjectsDirectory(false),
 #endif
+    m_blockedIFile(0)
 {
 }
 
@@ -252,6 +258,55 @@ void FileManager::updateFileInfo(IFile *file)
         d->m_states[fixedname].lastUpdatedState.insert(file, item);
 }
 
+/// Dumps the state of the file manager's map
+/// For debugging purposes
+void FileManager::dump()
+{
+    QMap<QString, Internal::FileState>::const_iterator it, end;
+    it = d->m_states.constBegin();
+    end = d->m_states.constEnd();
+    for (; it != end; ++it) {
+        qDebug()<<" ";
+        qDebug() << it.key();
+        qDebug() << it.value().expected.modified;
+
+        QMap<IFile *, Internal::FileStateItem>::const_iterator jt, jend;
+        jt = it.value().lastUpdatedState.constBegin();
+        jend = it.value().lastUpdatedState.constEnd();
+        for (; jt != jend; ++jt) {
+            qDebug() << jt.key() << jt.value().modified;
+        }
+    }
+}
+
+void FileManager::renamedFile(const QString &from, QString &to)
+{
+    QString fixedFrom = fixFileName(from);
+    QString fixedTo = fixFileName(to);
+    if (d->m_states.contains(fixedFrom)) {
+        QTC_ASSERT(!d->m_states.contains(to), return);
+        d->m_states.insert(fixedTo, d->m_states.value(fixedFrom));
+        d->m_states.remove(fixedFrom);
+        QFileInfo fi(to);
+        d->m_states[fixedTo].expected.modified = fi.lastModified();
+        d->m_states[fixedTo].expected.permissions = fi.permissions();
+
+        d->m_fileWatcher->removePath(fixedFrom);
+        d->m_fileWatcher->addPath(fixedTo);
+
+        QMap<IFile *, Internal::FileStateItem>::iterator it, end;
+        it = d->m_states[fixedTo].lastUpdatedState.begin();
+        end = d->m_states[fixedTo].lastUpdatedState.end();
+
+        for ( ; it != end; ++it) {
+            d->m_blockedIFile = it.key();
+            it.key()->rename(to);
+            d->m_blockedIFile = it.key();
+            it.value().modified = fi.lastModified();
+        }
+    }
+}
+
 ///
 /// Does not use file->fileName, as such is save to use
 /// with renamed files and deleted files
@@ -336,6 +391,10 @@ bool FileManager::removeFile(IFile *file)
 void FileManager::checkForNewFileName()
 {
     IFile *file = qobject_cast<IFile *>(sender());
+    // We modified the IFile
+    // Trust the other code to also update the m_states map
+    if (file == d->m_blockedIFile)
+        return;
     QTC_ASSERT(file, return);
     const QString &fileName = fixFileName(file->fileName());
 
@@ -751,6 +810,7 @@ void FileManager::checkForReload()
         end = lastUpdated.constEnd();
         for ( ; it != end; ++it) {
             IFile *file = it.key();
+            d->m_blockedIFile = file;
             // Compare
             if (it.value().modified == fi.lastModified()
                 && it.value().permissions == fi.permissions()) {
@@ -832,6 +892,7 @@ void FileManager::checkForReload()
             }
 
             updateFileInfo(file);
+            d->m_blockedIFile = 0;
         }
     }
 
index 4f5e3d8..9834bce 100644 (file)
@@ -63,6 +63,8 @@ public:
     bool isFileManaged(const QString &fileName) const;
     QList<IFile *> modifiedFiles() const;
 
+    void renamedFile(const QString &from, QString &to);
+
     void blockFileChange(IFile *file);
     void unblockFileChange(IFile *file);
 
@@ -74,6 +76,7 @@ public:
     QStringList recentFiles() const;
     void saveRecentFiles();
 
+
     // current file
     void setCurrentFile(const QString &filePath);
     QString currentFile() const;
@@ -128,6 +131,7 @@ private slots:
     void syncWithEditor(Core::IContext *context);
 
 private:
+    void dump();
     void addFileInfo(IFile *file);
     void removeFileInfo(IFile *file);
     void removeFileInfo(const QString &fileName, IFile *file);
index 575cac9..42da335 100644 (file)
@@ -87,6 +87,7 @@ public:
 
     virtual ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const = 0;
     virtual void reload(ReloadFlag flag, ChangeType type) = 0;
+    virtual void rename(const QString &newName) = 0;
 
     virtual void checkPermissions() {}
 
index 13b43a6..0cd29f9 100644 (file)
@@ -42,7 +42,7 @@ class CORE_EXPORT IVersionControl : public QObject
     Q_OBJECT
 public:
     enum Operation {
-        AddOperation, DeleteOperation, OpenOperation,
+        AddOperation, DeleteOperation, OpenOperation, MoveOperation,
         CreateRepositoryOperation,
         SnapshotOperations,
         AnnotateOperation
@@ -56,21 +56,12 @@ public:
     /*!
      * Returns whether files in this directory should be managed with this
      * version control.
+     * If \a topLevel is non-null, it should return the topmost directory,
+     * for which this IVersionControl should be used. The VCSManager assumes
+     * that all files in the returned directory are managed by the same IVersionControl.
      */
-    virtual bool managesDirectory(const QString &filename) const = 0;
 
-    /*!
-     * This function should return the topmost directory, for which this
-     * IVersionControl should be used. The VCSManager assumes that all files in
-     * the returned directory are managed by the same IVersionControl.
-     *
-     * Note that this is used as an optimization, so that the VCSManager
-     * doesn't need to call managesDirectory(..) for each directory.
-     *
-     * This function is called after finding out that the directory is managed
-     * by a specific version control.
-     */
-    virtual QString findTopLevelForDirectory(const QString &directory) const = 0;
+    virtual bool managesDirectory(const QString &filename, QString *topLevel = 0) const = 0;
 
     /*!
      * Called to query whether a VCS supports the respective operations.
@@ -102,6 +93,12 @@ public:
     virtual bool vcsDelete(const QString &filename) = 0;
 
     /*!
+     * Called to rename a file, should do the actual on disk renaming
+     * (e.g. git mv, svn move, p4 move)
+     */
+    virtual bool vcsMove(const QString &from, const QString &to) = 0;
+
+    /*!
      * Called to initialize the version control system in a directory.
      */
     virtual bool vcsCreateRepository(const QString &directory) = 0;
index 4b3f174..7433bbe 100644 (file)
@@ -46,7 +46,9 @@
 #include <QtCore/QCoreApplication>
 #include <QtCore/QDir>
 #include <QtCore/QFileInfo>
+#include <QtCore/QMutex>
 #include <QtCore/QThread>
+#include <QtCore/QWaitCondition>
 
 #include <ne7ssh.h>
 
@@ -71,14 +73,14 @@ public:
         quit();
     }
 
-    bool start(bool shell)
+    bool start(bool shell, void (*callbackFunc)(void *), void *callbackArg)
     {
         Q_ASSERT(m_channel == -1);
 
         try {
             const QString *authString;
             int (ne7ssh::*connFunc)(const char *, int, const char *,
-                                    const char *, bool, int);
+                const char *, bool, int, void (*)(void *), void *);
             if (m_server.authType == SshServerInfo::AuthByPwd) {
                 authString = &m_server.pwd;
                 connFunc = &ne7ssh::connectWithPassword;
@@ -87,14 +89,14 @@ public:
                 connFunc = &ne7ssh::connectWithKey;
             }
             m_channel = (ssh.data()->*connFunc)(m_server.host.toLatin1(),
-                            m_server.port, m_server.uname.toAscii(),
-                            authString->toLatin1(), shell, m_server.timeout);
+                m_server.port, m_server.uname.toAscii(), authString->toLatin1(),
+                shell, m_server.timeout, callbackFunc, callbackArg);
             if (m_channel == -1) {
                 setError(tr("Could not connect to host."), false);
                 return false;
             }
         } catch (const std::exception &e) {
-        // Should in theory not be necessary, but Net7 leaks Botan exceptions.
+            // Should in theory not be necessary, but Net7 leaks Botan exceptions.
             setError(tr("Error in cryptography backend: %1")
                      .arg(QLatin1String(e.what())), false);
             return false;
@@ -113,6 +115,7 @@ public:
         }
     }
 
+    bool isConnected() const { return channel() != -1; }
     bool hasError() const { return !m_error.isEmpty(); }
     QString error() const { return m_error; }
     int channel() const { return m_channel; }
@@ -133,7 +136,6 @@ private:
     int m_channel;
 };
 
-
 char *alloc(size_t n)
 {
     return new char[n];
@@ -150,6 +152,9 @@ struct InteractiveSshConnectionPrivate
 
     GenericSshConnection conn;
     ConnectionOutputReader *outputReader;
+    QByteArray remoteOutput;
+    QMutex mutex;
+    QWaitCondition waitCond;
 };
 
 struct NonInteractiveSshConnectionPrivate
@@ -165,7 +170,8 @@ class ConnectionOutputReader : public QThread
 {
 public:
     ConnectionOutputReader(InteractiveSshConnection *parent)
-        : QThread(parent), m_conn(parent), m_stopRequested(false)
+        : QThread(parent), m_conn(parent), m_stopRequested(false),
+          m_dataAvailable(false)
     {}
 
     ~ConnectionOutputReader()
@@ -174,35 +180,67 @@ public:
         wait();
     }
 
-    // TODO: Use a wakeup mechanism here as soon as we no longer poll for output
-    // from Net7.
     void stop()
     {
+        m_mutex.lock();
         m_stopRequested = true;
+        m_waitCond.wakeOne();
+        m_mutex.unlock();
+    }
+
+    void dataAvailable()
+    {
+        m_mutex.lock();
+        m_dataAvailable = true;
+        m_waitCond.wakeOne();
+        m_mutex.unlock();
     }
 
 private:
     virtual void run()
     {
-        while (!m_stopRequested) {
+        while (true) {
+            m_mutex.lock();
+            if (m_stopRequested) {
+                m_mutex.unlock();
+                return;
+            }
             const int channel = m_conn->d->conn.channel();
-            if (channel != -1) {
-                QScopedPointer<char, QScopedPointerArrayDeleter<char> >
+            if (!m_dataAvailable || channel == -1)
+                m_waitCond.wait(&m_mutex);
+            m_dataAvailable = false;
+            m_mutex.unlock();
+            QScopedPointer<char, QScopedPointerArrayDeleter<char> >
                     output(m_conn->d->conn.ssh->readAndReset(channel, alloc));
-                if (output)
-                    emit m_conn->remoteOutput(QByteArray(output.data()));
+            if (output) {
+                m_conn->d->mutex.lock();
+                m_conn->d->remoteOutput += output.data();
+                emit m_conn->remoteOutputAvailable();
+                m_conn->d->mutex.unlock();
             }
-            usleep(100000); // TODO: Hack Net7 to enable wait() functionality.
         }
     }
 
     InteractiveSshConnection *m_conn;
     bool m_stopRequested;
+    bool m_dataAvailable;
+    QMutex m_mutex;
+    QWaitCondition m_waitCond;
 };
 
 } // namespace Internal
 
 
+namespace {
+
+void wakeupReader(void *opaqueReader)
+{
+    static_cast<Internal::ConnectionOutputReader*>(opaqueReader)->dataAvailable();
+}
+
+} // Anonymous namespace
+
+
 InteractiveSshConnection::InteractiveSshConnection(const SshServerInfo &server)
     : d(new Internal::InteractiveSshConnectionPrivate(server))
 {
@@ -218,7 +256,10 @@ InteractiveSshConnection::~InteractiveSshConnection()
 
 bool InteractiveSshConnection::start()
 {
-    if (!d->conn.start(true))
+    if (isConnected())
+        return true;
+
+    if (!d->conn.start(true, wakeupReader, d->outputReader))
         return false;
 
     d->outputReader->start();
@@ -236,15 +277,35 @@ bool InteractiveSshConnection::sendInput(const QByteArray &input)
 
 void InteractiveSshConnection::quit()
 {
+    d->mutex.lock();
+    d->waitCond.wakeOne();
+    d->mutex.unlock();
     d->outputReader->stop();
     d->conn.quit();
 }
 
+QByteArray InteractiveSshConnection::waitForRemoteOutput(int msecs)
+{
+    d->mutex.lock();
+    if (d->remoteOutput.isEmpty())
+        d->waitCond.wait(&d->mutex, msecs == -1 ? ULONG_MAX : msecs);
+    const QByteArray remoteOutput = d->remoteOutput;
+    d->remoteOutput.clear();
+    d->mutex.unlock();
+    return remoteOutput;
+}
+
+
 InteractiveSshConnection::Ptr InteractiveSshConnection::create(const SshServerInfo &server)
 {
     return Ptr(new InteractiveSshConnection(server));
 }
 
+bool InteractiveSshConnection::isConnected() const
+{
+    return d->conn.isConnected();
+}
+
 bool InteractiveSshConnection::hasError() const
 {
     return d->conn.hasError();
@@ -283,11 +344,14 @@ SftpConnection::~SftpConnection()
 
 bool SftpConnection::start()
 {
-    if (!d->conn.start(false))
+    if (isConnected())
+        return true;
+    if (!d->conn.start(false, 0, 0))
         return false;
     if (!d->conn.ssh->initSftp(d->sftp, d->conn.channel())
         || !d->sftp.setTimeout(d->conn.server().timeout)) {
         d->conn.setError(tr("Error setting up SFTP subsystem"), true);
+        quit();
         return false;
     }
     return true;
@@ -404,6 +468,11 @@ void SftpConnection::quit()
     d->conn.quit();
 }
 
+bool SftpConnection::isConnected() const
+{
+    return d->conn.isConnected();
+}
+
 bool SftpConnection::hasError() const
 {
     return d->conn.hasError();
index 7671487..8c7b59f 100644 (file)
@@ -81,13 +81,15 @@ public:
 
     bool start();
     void quit();
+    bool isConnected() const;
     bool sendInput(const QByteArray &input); // Should normally end in newline.
+    QByteArray waitForRemoteOutput(int msecs = -1);
     bool hasError() const;
     QString error() const;
     ~InteractiveSshConnection();
 
 signals:
-    void remoteOutput(const QByteArray &output);
+    void remoteOutputAvailable();
 
 private:
     InteractiveSshConnection(const SshServerInfo &server);
@@ -123,6 +125,7 @@ public:
     static Ptr create(const SshServerInfo &server);
     bool start();
     void quit();
+    bool isConnected() const;
     bool hasError() const;
     QString error() const;
     bool upload(const QString &localFilePath, const QByteArray &remoteFilePath);
index 35d5b2f..0221e29 100644 (file)
@@ -90,6 +90,18 @@ IVersionControl* VCSManager::findVersionControlForDirectory(const QString &direc
                                                             QString *topLevelDirectory)
 {
     typedef VersionControlCache::const_iterator VersionControlCacheConstIterator;
+
+    if (debug) {
+        qDebug(">findVersionControlForDirectory %s topLevelPtr %d",
+               qPrintable(directory), (topLevelDirectory != 0));
+        if (debug > 1) {
+            const VersionControlCacheConstIterator cend = m_d->m_cachedMatches.constEnd();
+            for (VersionControlCacheConstIterator it = m_d->m_cachedMatches.constBegin(); it != cend; ++it)
+                qDebug("Cache %s -> '%s'", qPrintable(it.key()), qPrintable(it.value()->displayName()));
+        }
+    }
+    QTC_ASSERT(!directory.isEmpty(), return 0);
+
     const VersionControlCacheConstIterator cacheEnd = m_d->m_cachedMatches.constEnd();
 
     if (topLevelDirectory)
@@ -100,37 +112,51 @@ IVersionControl* VCSManager::findVersionControlForDirectory(const QString &direc
     if (fullPathIt != cacheEnd) {
         if (topLevelDirectory)
             *topLevelDirectory = directory;
+        if (debug)
+            qDebug("<findVersionControlForDirectory: full cache match for VCS '%s'", qPrintable(fullPathIt.value()->displayName()));
         return fullPathIt.value();
     }
 
-    // Split the path, starting from top, try to find the matching repository
-    int pos = 0;
+    // Split the path, trying to find the matching repository. We start from the reverse
+    // in order to detected nested repositories correctly (say, a git checkout under SVN).
+    // Note that detection of a nested version control will still fail if the
+    // above-located version control is detected and entered into the cache first.
+    // The nested one can then no longer be found due to the splitting of the paths.
+    int pos = directory.size() - 1;
     const QChar slash = QLatin1Char('/');
     while (true) {
-        const int index = directory.indexOf(slash, pos);
-        if (index == -1)
+        const int index = directory.lastIndexOf(slash, pos);
+        if (index <= 0) // Stop at '/' or not found
             break;
         const QString directoryPart = directory.left(index);
         const VersionControlCacheConstIterator it = m_d->m_cachedMatches.constFind(directoryPart);
         if (it != cacheEnd) {
             if (topLevelDirectory)
                 *topLevelDirectory = it.key();
+            if (debug)
+                qDebug("<findVersionControlForDirectory: cache match for VCS '%s', topLevel: %s",
+                       qPrintable(it.value()->displayName()), qPrintable(it.key()));
             return it.value();
         }
-        pos = index + 1;
+        pos = index - 1;
     }
 
     // Nothing: ask the IVersionControls directly, insert the toplevel into the cache.
     const VersionControlList versionControls = allVersionControls();
     foreach (IVersionControl * versionControl, versionControls) {
-        if (versionControl->managesDirectory(directory)) {
-            const QString topLevel = versionControl->findTopLevelForDirectory(directory);
+        QString topLevel;
+        if (versionControl->managesDirectory(directory, &topLevel)) {
             m_d->m_cachedMatches.insert(topLevel, versionControl);
             if (topLevelDirectory)
                 *topLevelDirectory = topLevel;
+            if (debug)
+                qDebug("<findVersionControlForDirectory: invocation of '%s' matches: %s",
+                       qPrintable(versionControl->displayName()), qPrintable(topLevel));
             return versionControl;
         }
     }
+    if (debug)
+        qDebug("<findVersionControlForDirectory: No match for %s", qPrintable(directory));
     return 0;
 }
 
index b1c22b7..cff88e5 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="CodePaster" version="1.3.84" compatVersion="1.3.84">
+<plugin name="CodePaster" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -13,8 +13,8 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Codepaster plugin for pushing/fetching diff from server</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="TextEditor" version="1.3.84"/>
-        <dependency name="ProjectExplorer" version="1.3.84"/>
-        <dependency name="Core" version="1.3.84"/>
+        <dependency name="TextEditor" version="2.0.80"/>
+        <dependency name="ProjectExplorer" version="2.0.80"/>
+        <dependency name="Core" version="2.0.80"/>
     </dependencyList>
 </plugin>
index f25b415..ab6a8a4 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="CppEditor" version="1.3.84" compatVersion="1.3.84">
+<plugin name="CppEditor" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,8 +14,8 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>C/C++ editor component.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="Core" version="1.3.84"/>
-        <dependency name="TextEditor" version="1.3.84"/>
-        <dependency name="CppTools" version="1.3.84"/>
+        <dependency name="Core" version="2.0.80"/>
+        <dependency name="TextEditor" version="2.0.80"/>
+        <dependency name="CppTools" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 39acd23..c300f87 100644 (file)
@@ -48,7 +48,7 @@
 #include <TranslationUnit.h>
 #include <cplusplus/ExpressionUnderCursor.h>
 #include <cplusplus/TypeOfExpression.h>
-#include <cplusplus/LookupContext.h>
+#include <cplusplus/DeprecatedLookupContext.h>
 #include <cplusplus/Overview.h>
 #include <cplusplus/OverviewModel.h>
 #include <cplusplus/SimpleLexer.h>
@@ -560,40 +560,6 @@ protected:
 
 } // end of anonymous namespace
 
-static const QualifiedNameId *qualifiedNameIdForSymbol(Symbol *s, const LookupContext &context)
-{
-    const Name *symbolName = s->name();
-    if (! symbolName)
-        return 0; // nothing to do.
-
-    QVector<const Name *> names;
-
-    for (Scope *scope = s->scope(); scope; scope = scope->enclosingScope()) {
-        if (scope->isClassScope() || scope->isNamespaceScope()) {
-            if (scope->owner() && scope->owner()->name()) {
-                const Name *ownerName = scope->owner()->name();
-                if (const QualifiedNameId *q = ownerName->asQualifiedNameId()) {
-                    for (unsigned i = 0; i < q->nameCount(); ++i) {
-                        names.prepend(q->nameAt(i));
-                    }
-                } else {
-                    names.prepend(ownerName);
-                }
-            }
-        }
-    }
-
-    if (const QualifiedNameId *q = symbolName->asQualifiedNameId()) {
-        for (unsigned i = 0; i < q->nameCount(); ++i) {
-            names.append(q->nameAt(i));
-        }
-    } else {
-        names.append(symbolName);
-    }
-
-    return context.control()->qualifiedNameId(names.constData(), names.size());
-}
-
 CPPEditorEditable::CPPEditorEditable(CPPEditor *editor)
     : BaseTextEditorEditable(editor)
 {
@@ -869,16 +835,13 @@ CPlusPlus::Symbol *CPPEditor::findCanonicalSymbol(const QTextCursor &cursor,
     // qDebug() << "code:" << code;
 
     TypeOfExpression typeOfExpression;
-    typeOfExpression.setSnapshot(snapshot);
-
-    Symbol *lastVisibleSymbol = doc->findSymbolAt(line, col);
+    typeOfExpression.init(doc, snapshot);
 
-    const QList<LookupItem> results = typeOfExpression(code, doc,
-                                                   lastVisibleSymbol,
-                                                   TypeOfExpression::Preprocess);
+    const QList<LookupItem> results = typeOfExpression(code, doc->scopeAt(line, col),
+                                                       TypeOfExpression::Preprocess);
 
     NamespaceBindingPtr glo = bind(doc, snapshot);
-    Symbol *canonicalSymbol = LookupContext::canonicalSymbol(results, glo.data());
+    Symbol *canonicalSymbol = DeprecatedLookupContext::canonicalSymbol(results, glo.data());
 
     return canonicalSymbol;
 }
@@ -1175,108 +1138,46 @@ void CPPEditor::updateUsesNow()
     semanticRehighlight();
 }
 
-static bool isCompatible(const Name *name, const Name *otherName)
-{
-    if (const NameId *nameId = name->asNameId()) {
-        if (const TemplateNameId *otherTemplId = otherName->asTemplateNameId())
-            return nameId->identifier()->isEqualTo(otherTemplId->identifier());
-    } else if (const TemplateNameId *templId = name->asTemplateNameId()) {
-        if (const NameId *otherNameId = otherName->asNameId())
-            return templId->identifier()->isEqualTo(otherNameId->identifier());
-    }
-
-    return name->isEqualTo(otherName);
-}
-
-static bool isCompatible(Function *definition, Symbol *declaration,
-                         const QualifiedNameId *declarationName)
-{
-    Function *declTy = declaration->type()->asFunctionType();
-    if (! declTy)
-        return false;
-
-    const Name *definitionName = definition->name();
-    if (const QualifiedNameId *q = definitionName->asQualifiedNameId()) {
-        if (! isCompatible(q->unqualifiedNameId(), declaration->name()))
-            return false;
-        else if (q->nameCount() > declarationName->nameCount())
-            return false;
-        else if (declTy->argumentCount() != definition->argumentCount())
-            return false;
-        else if (declTy->isConst() != definition->isConst())
-            return false;
-        else if (declTy->isVolatile() != definition->isVolatile())
-            return false;
-
-        for (unsigned i = 0; i < definition->argumentCount(); ++i) {
-            Symbol *arg = definition->argumentAt(i);
-            Symbol *otherArg = declTy->argumentAt(i);
-            if (! arg->type().isEqualTo(otherArg->type()))
-                return false;
-        }
-
-        for (unsigned i = 0; i != q->nameCount(); ++i) {
-            const Name *n = q->nameAt(q->nameCount() - i - 1);
-            const Name *m = declarationName->nameAt(declarationName->nameCount() - i - 1);
-            if (! isCompatible(n, m))
-                return false;
-        }
-        return true;
-    } else {
-        // ### TODO: implement isCompatible for unqualified name ids.
-    }
-    return false;
-}
-
 void CPPEditor::switchDeclarationDefinition()
 {
-    int line = 0, column = 0;
-    convertPosition(position(), &line, &column);
-
-    if (!m_modelManager)
+    if (! m_modelManager)
         return;
 
     const Snapshot snapshot = m_modelManager->snapshot();
 
-    Document::Ptr doc = snapshot.document(file()->fileName());
-    if (!doc)
-        return;
-    Symbol *lastSymbol = doc->findSymbolAt(line, column);
-    if (!lastSymbol || !lastSymbol->scope())
-        return;
-
-    Function *f = lastSymbol->asFunction();
-    if (!f) {
-        Scope *fs = lastSymbol->scope();
-        if (!fs->isFunctionScope())
-            fs = fs->enclosingFunctionScope();
-        if (fs)
-            f = fs->owner()->asFunction();
-    }
+    if (Document::Ptr thisDocument = snapshot.document(file()->fileName())) {
+        int line = 0, column = 0;
+        convertPosition(position(), &line, &column);
 
-    if (f) {
-        TypeOfExpression typeOfExpression;
-        typeOfExpression.setSnapshot(m_modelManager->snapshot());
-        QList<LookupItem> resolvedSymbols = typeOfExpression(QString(), doc, lastSymbol);
-        const LookupContext &context = typeOfExpression.lookupContext();
+        Scope *scope = thisDocument->scopeAt(line, column);
+        Symbol *lastVisibleSymbol = thisDocument->lastVisibleSymbolAt(line, column);
 
-        const QualifiedNameId *q = qualifiedNameIdForSymbol(f, context);
-        QList<Symbol *> symbols = context.resolve(q);
+        Scope *functionScope = 0;
+        if (scope->isFunctionScope())
+            functionScope = scope;
+        else
+            functionScope = scope->enclosingFunctionScope();
 
-        Symbol *declaration = 0;
-        foreach (declaration, symbols) {
-            if (isCompatible(f, declaration, q))
-                break;
+        if (! functionScope && lastVisibleSymbol) {
+            if (Function *def = lastVisibleSymbol->asFunction())
+                functionScope = def->members();
         }
 
-        if (! declaration && ! symbols.isEmpty())
-            declaration = symbols.first();
+        if (functionScope) {
+            LookupContext context(thisDocument, snapshot);
+
+            Function *functionDefinition = functionScope->owner()->asFunction();
+            const QList<Symbol *> declarations = context.lookup(functionDefinition->name(), functionDefinition->scope());
+            foreach (Symbol *decl, declarations) {
+                // TODO: check decl.
+                openCppEditorAt(linkToSymbol(decl));
+                break;
+            }
 
-        if (declaration)
-            openCppEditorAt(linkToSymbol(declaration));
-    } else if (lastSymbol->type()->isFunctionType()) {
-        if (Symbol *def = findDefinition(lastSymbol))
-            openCppEditorAt(linkToSymbol(def));
+        } else if (lastVisibleSymbol && lastVisibleSymbol->isDeclaration() && lastVisibleSymbol->type()->isFunctionType()) {
+            if (Symbol *def = snapshot.findMatchingDefinition(lastVisibleSymbol))
+                openCppEditorAt(linkToSymbol(def));
+        }
     }
 }
 
@@ -1429,8 +1330,8 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor,
     }
 
     // Find the last symbol up to the cursor position
-    Symbol *lastSymbol = doc->findSymbolAt(line, column);
-    if (!lastSymbol)
+    Scope *scope = doc->scopeAt(line, column);
+    if (!scope)
         return link;
 
     // Evaluate the type of the expression under the cursor
@@ -1438,17 +1339,21 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor,
     const QString expression = expressionUnderCursor(tc);
 
     TypeOfExpression typeOfExpression;
-    typeOfExpression.setSnapshot(snapshot);
-    QList<LookupItem> resolvedSymbols =
-            typeOfExpression(expression, doc, lastSymbol);
+    typeOfExpression.init(doc, snapshot);
+    const QList<LookupItem> resolvedSymbols = typeOfExpression(expression, scope, TypeOfExpression::Preprocess);
 
     if (!resolvedSymbols.isEmpty()) {
-        LookupItem result = skipForwardDeclarations(resolvedSymbols);
+        const LookupItem result = skipForwardDeclarations(resolvedSymbols);
 
-        if (Symbol *symbol = result.lastVisibleSymbol()) {
+        if (Symbol *symbol = result.declaration()) {
             Symbol *def = 0;
-            if (resolveTarget && !lastSymbol->isFunction())
-                def = findDefinition(symbol);
+
+            if (resolveTarget) {
+                def = findDefinition(symbol, snapshot);
+
+                if (def == doc->lastVisibleSymbolAt(line, column))
+                    def = 0; // jump to declaration then.
+            }
 
             link = linkToSymbol(def ? def : symbol);
             link.begin = beginOfToken;
@@ -1486,91 +1391,15 @@ void CPPEditor::jumpToDefinition()
     openLink(findLinkAt(textCursor()));
 }
 
-Symbol *CPPEditor::findDefinition(Symbol *symbol)
+Symbol *CPPEditor::findDefinition(Symbol *symbol, const Snapshot &snapshot)
 {
     if (symbol->isFunction())
         return 0; // symbol is a function definition.
 
-    Function *funTy = symbol->type()->asFunctionType();
-    if (! funTy)
-        return 0; // symbol does not have function type.
-
-    const Name *name = symbol->name();
-    if (! name)
-        return 0; // skip anonymous functions!
-
-    if (const QualifiedNameId *q = name->asQualifiedNameId())
-        name = q->unqualifiedNameId();
-
-    // map from file names to function definitions.
-    QMap<QString, QList<Function *> > functionDefinitions;
-
-    // find function definitions.
-    FindFunctionDefinitions findFunctionDefinitions;
-
-    // save the current snapshot
-    const Snapshot snapshot = m_modelManager->snapshot();
-
-    foreach (Document::Ptr doc, snapshot) {
-        if (Scope *globals = doc->globalSymbols()) {
-            QList<Function *> *localFunctionDefinitions =
-                    &functionDefinitions[doc->fileName()];
-
-            findFunctionDefinitions(name, globals,
-                                    localFunctionDefinitions);
-        }
-    }
-
-    // a dummy document.
-    Document::Ptr expressionDocument = Document::create("<empty>");
-
-    Function *bestMatch = 0;
-    int bestScore = -1;
-
-    QMapIterator<QString, QList<Function *> > it(functionDefinitions);
-    while (it.hasNext()) {
-        it.next();
-
-        // get the instance of the document.
-        Document::Ptr thisDocument = snapshot.document(it.key());
-
-        foreach (Function *f, it.value()) {
-            int score = 0; // current function's score
-
-            const int funTyArgsCount = funTy->argumentCount();
-            const int fArgsCount = f->argumentCount();
-
-            // max score if arguments count equals
-            if (funTyArgsCount == fArgsCount)
-                score += funTyArgsCount + 1;
-            else
-                score += (funTyArgsCount < fArgsCount) ? funTyArgsCount : fArgsCount;
-
-            // +1 to score for every equal parameter
-            unsigned minCount = (funTyArgsCount < fArgsCount) ? funTyArgsCount : fArgsCount;
-            for (unsigned i = 0; i < minCount; ++i)
-                if (Symbol *funTyArg = funTy->argumentAt(i))
-                    if (Symbol *fArg = f->argumentAt(i))
-                        if (funTyArg->type().isEqualTo(fArg->type()))
-                            score++;
-
-            if (score > bestScore) {
-                // create a lookup context
-                const LookupContext context(f, expressionDocument,
-                                            thisDocument, snapshot);
-
-                // search the matching definition for the function declaration `symbol'.
-                foreach (Symbol *s, context.resolve(f->name())) {
-                    if (s == symbol) {
-                        bestMatch = f;
-                        bestScore = score;
-                    }
-                }
-            }
-        }
-    }
+    else if (! symbol->type()->isFunctionType())
+        return 0; // not a function declaration
 
-    return bestMatch;
+    return snapshot.findMatchingDefinition(symbol);
 }
 
 unsigned CPPEditor::editorRevision() const
index 8ab0ab0..4e59ffc 100644 (file)
@@ -252,7 +252,7 @@ private:
 
     CPlusPlus::Symbol *markSymbols();
     bool sortedMethodOverview() const;
-    CPlusPlus::Symbol *findDefinition(CPlusPlus::Symbol *symbol);
+    CPlusPlus::Symbol *findDefinition(CPlusPlus::Symbol *symbol, const CPlusPlus::Snapshot &snapshot);
     virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
 
     TextEditor::ITextEditor *openCppEditorAt(const QString &fileName, int line,
index 77c9d1e..a8a02fd 100644 (file)
@@ -65,15 +65,19 @@ void CppHighlighter::highlightBlock(const QString &text)
     const QList<SimpleToken> tokens = tokenize(text, initialState);
     state = tokenize.state(); // refresh the state
 
+    int foldingIndent = initialBraceDepth;
+    if (TextBlockUserData *userData = BaseTextDocumentLayout::testUserData(currentBlock())) {
+        userData->setFoldingIndent(0);
+        userData->setFoldingStartIncluded(false);
+        userData->setFoldingEndIncluded(false);
+    }
+
     if (tokens.isEmpty()) {
         setCurrentBlockState(previousState);
-        if (TextBlockUserData *userData = BaseTextDocumentLayout::testUserData(currentBlock())) {
-            userData->setClosingCollapseMode(TextBlockUserData::NoClosingCollapse);
-            userData->setCollapseMode(TextBlockUserData::NoCollapse);
-        }
         BaseTextDocumentLayout::clearParentheses(currentBlock());
         if (text.length()) // the empty line can still contain whitespace
             setFormat(0, text.length(), m_formats[CppVisualWhitespace]);
+        BaseTextDocumentLayout::setFoldingIndent(currentBlock(), foldingIndent);
         return;
     }
 
@@ -102,13 +106,29 @@ void CppHighlighter::highlightBlock(const QString &text)
         if (tk.is(T_LPAREN) || tk.is(T_LBRACE) || tk.is(T_LBRACKET)) {
             const QChar c(tk.text().at(0));
             parentheses.append(Parenthesis(Parenthesis::Opened, c, tk.position()));
-            if (tk.is(T_LBRACE))
+            if (tk.is(T_LBRACE)) {
                 ++braceDepth;
+
+                // if a folding block opens at the beginning of a line, treat the entire line
+                // as if it were inside the folding block
+                if (tk.position() == firstNonSpace) {
+                    ++foldingIndent;
+                    BaseTextDocumentLayout::userData(currentBlock())->setFoldingStartIncluded(true);
+                }
+            }
         } else if (tk.is(T_RPAREN) || tk.is(T_RBRACE) || tk.is(T_RBRACKET)) {
             const QChar c(tk.text().at(0));
             parentheses.append(Parenthesis(Parenthesis::Closed, c, tk.position()));
-            if (tk.is(T_RBRACE))
+            if (tk.is(T_RBRACE)) {
                 --braceDepth;
+                if (braceDepth < foldingIndent) {
+                    // unless we are at the end of the block, we reduce the folding indent
+                    if (i == tokens.size()-1 || tokens.at(i+1).is(T_SEMICOLON))
+                        BaseTextDocumentLayout::userData(currentBlock())->setFoldingEndIncluded(true);
+                    else
+                        foldingIndent = qMin(braceDepth, foldingIndent);
+                }
+            }
         }
 
         bool highlightCurrentWordAsPreprocessor = highlightAsPreprocessor;
@@ -148,7 +168,11 @@ void CppHighlighter::highlightBlock(const QString &text)
             //  - is not a continuation line (tokens.size() > 1 || ! state)
             if (initialState && i == 0 && (tokens.size() > 1 || ! state)) {
                 --braceDepth;
-
+                // unless we are at the end of the block, we reduce the folding indent
+                if (i == tokens.size()-1)
+                    BaseTextDocumentLayout::userData(currentBlock())->setFoldingEndIncluded(true);
+                else
+                    foldingIndent = qMin(braceDepth, foldingIndent);
                 const int tokenEnd = tk.position() + tk.length() - 1;
                 parentheses.append(Parenthesis(Parenthesis::Closed, QLatin1Char('-'), tokenEnd));
 
@@ -167,6 +191,7 @@ void CppHighlighter::highlightBlock(const QString &text)
 
         else if (tk.is(T_IDENTIFIER))
             highlightWord(tk.text(), tk.position(), tk.length());
+
     }
 
     // mark the trailing white spaces
@@ -177,43 +202,23 @@ void CppHighlighter::highlightBlock(const QString &text)
             highlightLine(text, lastTokenEnd, text.length() - lastTokenEnd, QTextCharFormat());
     }
 
-    if (TextBlockUserData *userData = BaseTextDocumentLayout::testUserData(currentBlock())) {
-        userData->setClosingCollapseMode(TextBlockUserData::NoClosingCollapse);
-        userData->setCollapseMode(TextBlockUserData::NoCollapse);
-    }
-
     if (! initialState && state && ! tokens.isEmpty()) {
         parentheses.append(Parenthesis(Parenthesis::Opened, QLatin1Char('+'),
                                        tokens.last().position()));
         ++braceDepth;
     }
 
-    QChar c;
-    int collapse = Parenthesis::collapseAtPos(parentheses, &c);
-    if (collapse >= 0) {
-        TextBlockUserData::CollapseMode collapseMode = TextBlockUserData::CollapseAfter;
-        if (collapse == firstNonSpace && c != QLatin1Char('+'))
-            collapseMode = TextBlockUserData::CollapseThis;
-        BaseTextDocumentLayout::userData(currentBlock())->setCollapseMode(collapseMode);
-    }
-
-
-    int cc = Parenthesis::closeCollapseAtPos(parentheses);
-    if (cc >= 0) {
-        TextBlockUserData *userData = BaseTextDocumentLayout::userData(currentBlock());
-        userData->setClosingCollapseMode(TextBlockUserData::ClosingCollapse);
-        QString trailingText = text.mid(cc+1).simplified();
-        if (trailingText.isEmpty() || trailingText == QLatin1String(";")) {
-            userData->setClosingCollapseMode(TextBlockUserData::ClosingCollapseAtEnd);
-        }
-    }
-
     BaseTextDocumentLayout::setParentheses(currentBlock(), parentheses);
 
     // if the block is ifdefed out, we only store the parentheses, but
+
     // do not adjust the brace depth.
-    if (BaseTextDocumentLayout::ifdefedOut(currentBlock()))
+    if (BaseTextDocumentLayout::ifdefedOut(currentBlock())) {
         braceDepth = initialBraceDepth;
+        foldingIndent = initialBraceDepth;
+    }
+
+    BaseTextDocumentLayout::setFoldingIndent(currentBlock(), foldingIndent);
 
     // optimization: if only the brace depth changes, we adjust subsequent blocks
     // to have QSyntaxHighlighter stop the rehighlighting
@@ -226,6 +231,7 @@ void CppHighlighter::highlightBlock(const QString &text)
             QTextBlock block = currentBlock().next();
             while (block.isValid() && block.userState() != -1) {
                 BaseTextDocumentLayout::changeBraceDepth(block, delta);
+                BaseTextDocumentLayout::changeFoldingIndent(block, delta);
                 block = block.next();
             }
         }
index 2c91f5c..bd4754c 100644 (file)
@@ -178,82 +178,6 @@ static QString buildHelpId(Symbol *symbol, const Name *name)
     return qualifiedNames.join(QLatin1String("::"));
 }
 
-// ### move me
-static FullySpecifiedType resolve(const FullySpecifiedType &ty,
-                                  const LookupContext &context,
-                                  Symbol **resolvedSymbol,
-                                  const Name **resolvedName)
-{
-    Control *control = context.control();
-
-    if (const PointerType *ptrTy = ty->asPointerType()) {
-        return control->pointerType(resolve(ptrTy->elementType(), context,
-                                            resolvedSymbol, resolvedName));
-
-    } else if (const ReferenceType *refTy = ty->asReferenceType()) {
-        return control->referenceType(resolve(refTy->elementType(), context,
-                                              resolvedSymbol, resolvedName));
-
-    } else if (const PointerToMemberType *ptrToMemTy = ty->asPointerToMemberType()) {
-        return control->pointerToMemberType(ptrToMemTy->memberName(),
-                                            resolve(ptrToMemTy->elementType(), context,
-                                                    resolvedSymbol, resolvedName));
-
-    } else if (const NamedType *namedTy = ty->asNamedType()) {
-        if (resolvedName)
-            *resolvedName = namedTy->name();
-
-        const QList<Symbol *> candidates = context.resolve(namedTy->name());
-
-        foreach (Symbol *c, candidates) {
-            if (c->isClass() || c->isEnum()) {
-                if (resolvedSymbol)
-                    *resolvedSymbol = c;
-
-                return c->type();
-            }
-        }
-
-    } else if (const Namespace *nsTy = ty->asNamespaceType()) {
-        if (resolvedName)
-            *resolvedName = nsTy->name();
-
-        if (resolvedSymbol)
-            *resolvedSymbol = const_cast<Namespace *>(nsTy);
-
-    } else if (const Class *classTy = ty->asClassType()) {
-        if (resolvedName)
-            *resolvedName = classTy->name();
-
-        if (resolvedSymbol)
-            *resolvedSymbol = const_cast<Class *>(classTy);
-
-    } else if (const ForwardClassDeclaration *fwdClassTy = ty->asForwardClassDeclarationType()) {
-        if (resolvedName)
-            *resolvedName = fwdClassTy->name();
-
-        if (resolvedSymbol)
-            *resolvedSymbol = const_cast<ForwardClassDeclaration *>(fwdClassTy);
-
-    } else if (const Enum *enumTy = ty->asEnumType()) {
-        if (resolvedName)
-            *resolvedName = enumTy->name();
-
-        if (resolvedSymbol)
-            *resolvedSymbol = const_cast<Enum *>(enumTy);
-
-    } else if (const Function *funTy = ty->asFunctionType()) {
-        if (resolvedName)
-            *resolvedName = funTy->name();
-
-        if (resolvedSymbol)
-            *resolvedSymbol = const_cast<Function *>(funTy);
-
-    }
-
-    return ty;
-}
-
 void CppHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, int pos)
 {
     m_helpId.clear();
@@ -266,9 +190,9 @@ void CppHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, in
     if (!edit)
         return;
 
-    const Snapshot documents = m_modelManager->snapshot();
+    const Snapshot snapshot = m_modelManager->snapshot();
     const QString fileName = editor->file()->fileName();
-    Document::Ptr doc = documents.document(fileName);
+    Document::Ptr doc = snapshot.document(fileName);
     if (!doc)
         return; // nothing to do
 
@@ -281,10 +205,10 @@ void CppHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, in
     // Find the last symbol up to the cursor position
     int line = 0, column = 0;
     editor->convertPosition(tc.position(), &line, &column);
-    Symbol *lastSymbol = doc->findSymbolAt(line, column);
+    Scope *scope = doc->scopeAt(line, column);
 
     TypeOfExpression typeOfExpression;
-    typeOfExpression.setSnapshot(documents);
+    typeOfExpression.init(doc, snapshot);
 
     // We only want to show F1 if the tooltip matches the help id
     bool showF1 = true;
@@ -332,52 +256,49 @@ void CppHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, in
         ExpressionUnderCursor expressionUnderCursor;
         const QString expression = expressionUnderCursor(tc);
 
-        const QList<LookupItem> types = typeOfExpression(expression, doc, lastSymbol);
+        const QList<LookupItem> types = typeOfExpression(expression, scope);
 
-        if (!types.isEmpty()) {
-            const LookupItem result = types.first();
 
-            FullySpecifiedType firstType = result.type(); // result of `type of expression'.
-            Symbol *lookupSymbol = result.lastVisibleSymbol(); // lookup symbol
-
-            Symbol *resolvedSymbol = lookupSymbol;
-            const Name *resolvedName = lookupSymbol ? lookupSymbol->name() : 0;
-            firstType = resolve(firstType, typeOfExpression.lookupContext(),
-                                &resolvedSymbol, &resolvedName);
-
-            if (resolvedSymbol && resolvedSymbol->scope()
-                && resolvedSymbol->scope()->isClassScope()) {
-                Class *enclosingClass = resolvedSymbol->scope()->owner()->asClass();
+        if (!types.isEmpty()) {
+            Overview overview;
+            overview.setShowArgumentNames(true);
+            overview.setShowReturnTypes(true);
+            overview.setShowFullyQualifiedNamed(true);
+
+            const LookupItem result = types.first(); // ### TODO: select the best candidate.
+            FullySpecifiedType symbolTy = result.type(); // result of `type of expression'.
+            Symbol *declaration = result.declaration(); // lookup symbol
+            const Name *declarationName = declaration ? declaration->name() : 0;
+
+            if (declaration && declaration->scope()
+                && declaration->scope()->isClassScope()) {
+                Class *enclosingClass = declaration->scope()->owner()->asClass();
                 if (const Identifier *id = enclosingClass->identifier()) {
-                    if (id->isEqualTo(resolvedSymbol->identifier()))
-                        resolvedSymbol = enclosingClass;
+                    if (id->isEqualTo(declaration->identifier()))
+                        declaration = enclosingClass;
                 }
             }
 
-            m_helpId = buildHelpId(resolvedSymbol, resolvedName);
+            m_helpId = buildHelpId(declaration, declarationName);
 
             if (m_toolTip.isEmpty()) {
-                Symbol *symbol = result.lastVisibleSymbol();
-                if (resolvedSymbol)
-                    symbol = resolvedSymbol;
+                Symbol *symbol = declaration;
 
-                Overview overview;
-                overview.setShowArgumentNames(true);
-                overview.setShowReturnTypes(true);
-                overview.setShowFullyQualifiedNamed(true);
+                if (declaration)
+                    symbol = declaration;
 
-                if (symbol && symbol == resolvedSymbol && symbol->isClass()) {
+                if (symbol && symbol == declaration && symbol->isClass()) {
                     m_toolTip = m_helpId;
 
-                } else if (lookupSymbol && (lookupSymbol->isDeclaration() || lookupSymbol->isArgument())) {
-                    m_toolTip = overview.prettyType(firstType, buildHelpId(lookupSymbol, lookupSymbol->name()));
+                } else if (declaration && (declaration->isDeclaration() || declaration->isArgument())) {
+                    m_toolTip = overview.prettyType(symbolTy, buildHelpId(declaration, declaration->name()));
 
-                } else if (firstType->isClassType() || firstType->isEnumType() ||
-                           firstType->isForwardClassDeclarationType()) {
+                } else if (symbolTy->isClassType() || symbolTy->isEnumType() ||
+                           symbolTy->isForwardClassDeclarationType()) {
                     m_toolTip = m_helpId;
 
                 } else {
-                    m_toolTip = overview.prettyType(firstType, m_helpId);
+                    m_toolTip = overview.prettyType(symbolTy, m_helpId);
 
                 }
             }
index 553d443..def7d89 100644 (file)
@@ -1326,14 +1326,21 @@ void QuickFixOperation::apply()
  */
 const QList<LookupItem> QuickFixOperation::typeOf(CPlusPlus::ExpressionAST *ast)
 {
+#ifdef __GNUC__
+#  warning port me
+#endif
+
+    qWarning() << Q_FUNC_INFO << __LINE__;
+    return QList<LookupItem>();
+
+#if 0
     unsigned line, column;
     document()->translationUnit()->getTokenStartPosition(ast->firstToken(), &line, &column);
     Symbol *lastVisibleSymbol = document()->findSymbolAt(line, column);
 
-    _lookupContext = LookupContext(lastVisibleSymbol, document(), document(), snapshot());
-
-    ResolveExpression resolveExpression(_lookupContext);
+    ResolveExpression resolveExpression(lastVisibleSymbol, _lookupContext);
     return resolveExpression(ast);
+#endif
 }
 
 CPPQuickFixCollector::CPPQuickFixCollector()
index 480abcd..74fc890 100644 (file)
@@ -33,7 +33,7 @@
 #include <texteditor/icompletioncollector.h>
 
 #include <cplusplus/CppDocument.h>
-#include <cplusplus/LookupContext.h>
+#include <cplusplus/DeprecatedLookupContext.h>
 #include <ASTfwd.h>
 
 #include <utils/changeset.h>
@@ -138,7 +138,7 @@ private:
     Utils::ChangeSet _changeSet;
     CPPEditor *_editor;
     CPlusPlus::AST *_topLevelNode;
-    CPlusPlus::LookupContext _lookupContext;
+    CPlusPlus::DeprecatedLookupContext _lookupContext;
 };
 
 class CPPQuickFixCollector: public TextEditor::IQuickFixCollector
index 567949b..d43d7b9 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="CppTools" version="1.3.84" compatVersion="1.3.84">
+<plugin name="CppTools" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,8 +14,8 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Tools for analyzing C/C++ code.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="TextEditor" version="1.3.84"/>
-        <dependency name="ProjectExplorer" version="1.3.84"/>
-        <dependency name="Locator" version="1.3.84"/>
+        <dependency name="TextEditor" version="2.0.80"/>
+        <dependency name="ProjectExplorer" version="2.0.80"/>
+        <dependency name="Locator" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 6a31d88..0502e5d 100644 (file)
@@ -66,7 +66,7 @@ QString AbstractEditorSupport::functionAt(const CppModelManagerInterface *modelM
     const CPlusPlus::Document::Ptr document = snapshot.document(fileName);
     if (!document)
         return QString();
-    if (const CPlusPlus::Symbol *symbol = document->findSymbolAt(line, column))
+    if (const CPlusPlus::Symbol *symbol = document->lastVisibleSymbolAt(line, column))
         if (const CPlusPlus::Scope *scope = symbol->scope())
             if (const CPlusPlus::Scope *functionScope = scope->enclosingFunctionScope())
                 if (const CPlusPlus::Symbol *function = functionScope->owner()) {
index 19e8e94..a68a4cd 100644 (file)
 #include <TranslationUnit.h>
 
 #include <cplusplus/ResolveExpression.h>
-#include <cplusplus/LookupContext.h>
+#include <cplusplus/DeprecatedLookupContext.h>
 #include <cplusplus/MatchingText.h>
 #include <cplusplus/Overview.h>
 #include <cplusplus/ExpressionUnderCursor.h>
 #include <cplusplus/BackwardsScanner.h>
 #include <cplusplus/TokenUnderCursor.h>
+#include <cplusplus/LookupContext.h>
 
 #include <coreplugin/icore.h>
 #include <coreplugin/mimedatabase.h>
 #include <QtGui/QToolButton>
 #include <QtGui/QVBoxLayout>
 
+namespace {
+    const bool debug = ! qgetenv("CPLUSPLUS_DEBUG").isEmpty();
+}
+
 using namespace CPlusPlus;
 
 namespace CppTools {
@@ -518,6 +523,10 @@ static int startOfOperator(TextEditor::ITextEditable *editor,
         completionKind = T_SLASH;
         --start;
         break;
+    case '#':
+        completionKind = T_POUND;
+        --start;
+        break;
     }
 
     if (start == pos)
@@ -627,6 +636,16 @@ bool CppCodeCompletion::triggersCompletion(TextEditor::ITextEditable *editor)
 {
     const int pos = editor->position();
     if (startOfOperator(editor, pos, /*token =*/ 0, /*want function call=*/ true) != pos) {
+        if (m_completionOperator == T_POUND) {
+            if (TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget())) {
+                QTextCursor tc(edit->document());
+                tc.setPosition(pos);
+                return tc.columnNumber() == 1;
+            }
+
+            return false;
+        }
+
         return true;
     }
 
@@ -673,6 +692,13 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
         return m_startPosition;
     }
 
+    // Pre-processor completion
+    if (m_completionOperator == T_POUND) {
+        completePreprocessor();
+        m_startPosition = startOfName;
+        return m_startPosition;
+    }
+
     // Include completion
     if (m_completionOperator == T_STRING_LITERAL
         || m_completionOperator == T_ANGLE_STRING_LITERAL
@@ -740,8 +766,8 @@ int CppCodeCompletion::startCompletionInternal(TextEditor::BaseTextEditor *edit,
     if (! thisDocument)
         return -1;
 
-    typeOfExpression.setSnapshot(snapshot);
-    Symbol *lastVisibleSymbol = thisDocument->findSymbolAt(line, column);
+    typeOfExpression.init(thisDocument, snapshot);
+    Symbol *lastVisibleSymbol = thisDocument->lastVisibleSymbolAt(line, column);
 
     if (expression.isEmpty()) {
         if (m_completionOperator == T_EOF_SYMBOL || m_completionOperator == T_COLON_COLON)
@@ -753,22 +779,27 @@ int CppCodeCompletion::startCompletionInternal(TextEditor::BaseTextEditor *edit,
         }
     }
 
+    Scope *scope = thisDocument->scopeAt(line, column);
+    Q_ASSERT(scope != 0);
 
-    QList<LookupItem> results = typeOfExpression(expression, thisDocument, lastVisibleSymbol, TypeOfExpression::Preprocess);
-    LookupContext context = typeOfExpression.lookupContext();
+    if (debug)
+        qDebug() << "scope:" << scope->owner()->fileName() << scope->owner()->line() << scope->owner()->column();
+
+    QList<LookupItem> results = typeOfExpression(expression, scope, TypeOfExpression::Preprocess);
+
+    if (debug)
+        qDebug() << "got:" << results.size() << "results";
 
     if (results.isEmpty()) {
         if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
             if (! (expression.isEmpty() || expression == QLatin1String("this"))) {
                 expression = QLatin1String("this");
-                results = typeOfExpression(expression, thisDocument, lastVisibleSymbol);
+                results = typeOfExpression(expression, scope);
             }
 
             if (results.isEmpty())
                 return -1;
 
-            context = typeOfExpression.lookupContext();
-
         } else if (m_completionOperator == T_LPAREN) {
             // Find the expression that precedes the current name
             int index = endOfExpression;
@@ -784,14 +815,13 @@ int CppCodeCompletion::startCompletionInternal(TextEditor::BaseTextEditor *edit,
 
             // Resolve the type of this expression
             const QList<LookupItem> results =
-                    typeOfExpression(baseExpression, thisDocument,
-                                     lastVisibleSymbol,
+                    typeOfExpression(baseExpression, scope,
                                      TypeOfExpression::Preprocess);
 
             // If it's a class, add completions for the constructors
             foreach (const LookupItem &result, results) {
                 if (result.type()->isClassType()) {
-                    if (completeConstructorOrFunction(results, context, endOfExpression, true))
+                    if (completeConstructorOrFunction(results, endOfExpression, true))
                         return m_startPosition;
 
                     break;
@@ -808,28 +838,28 @@ int CppCodeCompletion::startCompletionInternal(TextEditor::BaseTextEditor *edit,
 
     switch (m_completionOperator) {
     case T_LPAREN:
-        if (completeConstructorOrFunction(results, context, endOfExpression, false))
+        if (completeConstructorOrFunction(results, endOfExpression, false))
             return m_startPosition;
         break;
 
     case T_DOT:
     case T_ARROW:
-        if (completeMember(results, context))
+        if (completeMember(results))
             return m_startPosition;
         break;
 
     case T_COLON_COLON:
-        if (completeScope(results, context))
+        if (completeScope(results))
             return m_startPosition;
         break;
 
     case T_SIGNAL:
-        if (completeSignal(results, context))
+        if (completeSignal(results))
             return m_startPosition;
         break;
 
     case T_SLOT:
-        if (completeSlot(results, context))
+        if (completeSlot(results))
             return m_startPosition;
         break;
 
@@ -851,7 +881,7 @@ int CppCodeCompletion::globalCompletion(Symbol *lastVisibleSymbol,
     }
 
     Document::Ptr exprDoc = Document::create(QLatin1String("<expression>"));
-    const LookupContext context(lastVisibleSymbol, exprDoc, thisDocument, snapshot);
+    const DeprecatedLookupContext context(lastVisibleSymbol, exprDoc, thisDocument, snapshot);
     const QList<Scope *> scopes = context.expand(context.visibleScopes());
 
     foreach (Scope *scope, scopes) {
@@ -864,9 +894,9 @@ int CppCodeCompletion::globalCompletion(Symbol *lastVisibleSymbol,
 }
 
 bool CppCodeCompletion::completeConstructorOrFunction(const QList<LookupItem> &results,
-                                                      const LookupContext &context,
                                                       int endOfExpression, bool toolTipOnly)
 {
+    const LookupContext &context = typeOfExpression.context();
     QList<Function *> functions;
 
     foreach (const LookupItem &result, results) {
@@ -926,28 +956,19 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<LookupItem> &r
     }
 
     if (functions.isEmpty()) {
-        ResolveExpression resolveExpression(context);
-        ResolveClass resolveClass;
         const Name *functionCallOp = context.control()->operatorNameId(OperatorNameId::FunctionCallOp);
 
         foreach (const LookupItem &result, results) {
             FullySpecifiedType ty = result.type().simplified();
+            Scope *scope = result.scope();
 
             if (NamedType *namedTy = ty->asNamedType()) {
-                const QList<Symbol *> classObjectCandidates = resolveClass(namedTy->name(), result, context);
-
-                foreach (Symbol *classObjectCandidate, classObjectCandidates) {
-                    if (Class *klass = classObjectCandidate->asClass()) {
-                        const QList<LookupItem> overloads =
-                                resolveExpression.resolveMember(functionCallOp, klass,
-                                                                namedTy->name());
+                if (ClassOrNamespace *b = context.lookupType(namedTy->name(), scope)) {
+                    foreach (Symbol *overload, b->lookup(functionCallOp)) {
+                        FullySpecifiedType overloadTy = overload->type().simplified();
 
-                        foreach (const LookupItem &overloadResult, overloads) {
-                            FullySpecifiedType overloadTy = overloadResult.type().simplified();
-
-                            if (Function *funTy = overloadTy->asFunctionType())
-                                functions.append(funTy);
-                        }
+                        if (Function *funTy = overloadTy->asFunctionType())
+                            functions.append(funTy);
                     }
                 }
             }
@@ -975,8 +996,8 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<LookupItem> &r
         // find a scope that encloses the current location, starting from the lastVisibileSymbol
         // and moving outwards
         Scope *sc = 0;
-        if (context.symbol())
-            sc = context.symbol()->scope();
+        if (typeOfExpression.scope())
+            sc = typeOfExpression.scope();
         else if (context.thisDocument())
             sc = context.thisDocument()->globalSymbols();
 
@@ -1050,81 +1071,85 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<LookupItem> &r
             m_functionArgumentWidget = new FunctionArgumentWidget;
 
         m_functionArgumentWidget->showFunctionHint(functions,
-                                                   typeOfExpression.lookupContext(),
+                                                   typeOfExpression.context(),
                                                    m_startPosition);
     }
 
     return false;
 }
 
-bool CppCodeCompletion::completeMember(const QList<LookupItem> &baseResults,
-                                       const LookupContext &context)
+bool CppCodeCompletion::completeMember(const QList<LookupItem> &baseResults)
 {
+    const LookupContext &context = typeOfExpression.context();
+
+    if (debug)
+        qDebug() << Q_FUNC_INFO << __LINE__;
+
     if (baseResults.isEmpty())
         return false;
 
     ResolveExpression resolveExpression(context);
-    ResolveClass resolveClass;
 
     bool replacedDotOperator = false;
-    const QList<LookupItem> classObjectResults =
-            resolveExpression.resolveBaseExpression(baseResults,
-                                                    m_completionOperator,
-                                                    &replacedDotOperator);
-
-    QList<Symbol *> classObjectCandidates;
-    foreach (const LookupItem &r, classObjectResults) {
-        FullySpecifiedType ty = r.type().simplified();
 
-        if (Class *klass = ty->asClassType())
-            classObjectCandidates.append(klass);
+    if (ClassOrNamespace *binding = resolveExpression.baseExpression(baseResults,
+                                                                     m_completionOperator,
+                                                                     &replacedDotOperator)) {
+        if (debug)
+            qDebug() << "cool we got a binding for the base expression";
+
+        if (replacedDotOperator && binding) {
+            // Replace . with ->
+            int length = m_editor->position() - m_startPosition + 1;
+            m_editor->setCurPos(m_startPosition - 1);
+            m_editor->replace(length, QLatin1String("->"));
+            ++m_startPosition;
+        }
 
-        else if (NamedType *namedTy = ty->asNamedType()) {
-            const Name *className = namedTy->name();
-            const QList<Symbol *> classes = resolveClass(className, r, context);
+        if (binding)
+            completeClass(binding, /*static lookup = */ false);
 
-            foreach (Symbol *c, classes) {
-                if (Class *klass = c->asClass())
-                    classObjectCandidates.append(klass);
-            }
-        }
+        return ! m_completions.isEmpty();
     }
 
-    if (replacedDotOperator && ! classObjectCandidates.isEmpty()) {
-        // Replace . with ->
-        int length = m_editor->position() - m_startPosition + 1;
-        m_editor->setCurPos(m_startPosition - 1);
-        m_editor->replace(length, QLatin1String("->"));
-        ++m_startPosition;
+    if (debug) {
+        Overview oo;
+        qDebug() << "hmm, got:" << oo(baseResults.first().type());
     }
 
-    completeClass(classObjectCandidates, context, /*static lookup = */ false);
-    if (! m_completions.isEmpty())
-        return true;
-
     return false;
 }
 
-bool CppCodeCompletion::completeScope(const QList<LookupItem> &results,
-                                      const LookupContext &context)
+bool CppCodeCompletion::completeScope(const QList<LookupItem> &results)
 {
-    QList<Symbol *> classes, namespaces;
+    const LookupContext &context = typeOfExpression.context();
+    if (results.isEmpty())
+        return false;
 
     foreach (const LookupItem &result, results) {
         FullySpecifiedType ty = result.type();
+        Scope *scope = result.scope();
 
-        if (Class *classTy = ty->asClassType())
-            classes.append(classTy);
+        if (NamedType *namedTy = ty->asNamedType()) {
+            if (ClassOrNamespace *b = context.lookupType(namedTy->name(), scope)) {
+                completeClass(b);
+                break;
+            }
 
-        else if (Namespace *namespaceTy = ty->asNamespaceType())
-            namespaces.append(namespaceTy);
-    }
+        } else if (Class *classTy = ty->asClassType()) {
+            if (ClassOrNamespace *b = context.lookupType(classTy)) {
+                completeClass(b);
+                break;
+            }
 
-    if (! classes.isEmpty())
-        completeClass(classes, context);
+        } else if (Namespace *nsTy = ty->asNamespaceType()) {
+            if (ClassOrNamespace *b = context.lookupType(nsTy)) {
+                completeNamespace(b);
+                break;
+            }
 
-    else if (! namespaces.isEmpty() && m_completions.isEmpty())
-        completeNamespace(namespaces, context);
+        }
+    }
 
     return ! m_completions.isEmpty();
 }
@@ -1252,69 +1277,137 @@ bool CppCodeCompletion::completeInclude(const QTextCursor &cursor)
     return !m_completions.isEmpty();
 }
 
-void CppCodeCompletion::completeNamespace(const QList<Symbol *> &candidates,
-                                          const LookupContext &context)
+QStringList CppCodeCompletion::preprocessorCompletions
+        = QStringList()
+          << QLatin1String("define")
+          << QLatin1String("error")
+          << QLatin1String("include")
+          << QLatin1String("line")
+          << QLatin1String("pragma")
+          << QLatin1String("undef")
+          << QLatin1String("if")
+          << QLatin1String("ifdef")
+          << QLatin1String("ifndef")
+          << QLatin1String("elif")
+          << QLatin1String("else")
+          << QLatin1String("endif")
+          ;
+
+void CppCodeCompletion::completePreprocessor()
 {
-    QList<Scope *> todo;
-    QList<Scope *> visibleScopes = context.visibleScopes();
-    foreach (Symbol *candidate, candidates) {
-        if (Namespace *ns = candidate->asNamespace())
-            context.expand(ns->members(), visibleScopes, &todo);
+    TextEditor::CompletionItem item(this);
+
+    foreach (const QString &preprocessorCompletion, preprocessorCompletions) {
+        item.text = preprocessorCompletion;
+        m_completions.append(item);
     }
 
-    foreach (Scope *scope, todo) {
-        if (! (scope->isNamespaceScope() || scope->isEnumScope()))
+    if (objcKeywordsWanted()) {
+        item.text = QLatin1String("import");
+        m_completions.append(item);
+    }
+}
+
+void CppCodeCompletion::completeNamespace(ClassOrNamespace *b)
+{
+    QSet<ClassOrNamespace *> bindingsVisited;
+    QList<ClassOrNamespace *> bindingsToVisit;
+    bindingsToVisit.append(b);
+
+    while (! bindingsToVisit.isEmpty()) {
+        ClassOrNamespace *binding = bindingsToVisit.takeFirst();
+        if (! binding || bindingsVisited.contains(binding))
             continue;
 
-        addCompletionItem(scope->owner());
+        bindingsVisited.insert(binding);
+        bindingsToVisit += binding->usings();
 
-        for (unsigned i = 0; i < scope->symbolCount(); ++i) {
-            addCompletionItem(scope->symbolAt(i));
+        QList<Scope *> scopesToVisit;
+        QSet<Scope *> scopesVisited;
+
+        foreach (Symbol *bb, binding->symbols()) {
+            if (Namespace *ns = bb->asNamespace())
+                scopesToVisit.append(ns->members());
+        }
+
+        foreach (Enum *e, binding->enums()) {
+            scopesToVisit.append(e->members());
+        }
+
+        while (! scopesToVisit.isEmpty()) {
+            Scope *scope = scopesToVisit.takeFirst();
+            if (! scope || scopesVisited.contains(scope))
+                continue;
+
+            scopesVisited.insert(scope);
+
+            for (Scope::iterator it = scope->firstSymbol(); it != scope->lastSymbol(); ++it) {
+                Symbol *member = *it;
+                addCompletionItem(member);
+            }
         }
     }
 }
 
-void CppCodeCompletion::completeClass(const QList<Symbol *> &candidates,
-                                      const LookupContext &context,
-                                      bool staticLookup)
+void CppCodeCompletion::completeClass(ClassOrNamespace *b, bool staticLookup)
 {
-    if (candidates.isEmpty())
-        return;
+    QSet<ClassOrNamespace *> bindingsVisited;
+    QList<ClassOrNamespace *> bindingsToVisit;
+    bindingsToVisit.append(b);
 
-    Class *klass = candidates.first()->asClass();
+    while (! bindingsToVisit.isEmpty()) {
+        ClassOrNamespace *binding = bindingsToVisit.takeFirst();
+        if (! binding || bindingsVisited.contains(binding))
+            continue;
 
-    QList<Scope *> todo;
-    context.expand(klass->members(), context.visibleScopes(), &todo);
+        bindingsVisited.insert(binding);
+        bindingsToVisit += binding->usings();
 
-    foreach (Scope *scope, todo) {
-        if (! (scope->isClassScope() || scope->isEnumScope()))
-            continue;
+        QList<Scope *> scopesToVisit;
+        QSet<Scope *> scopesVisited;
 
-        addCompletionItem(scope->owner());
+        foreach (Symbol *bb, binding->symbols()) {
+            if (Class *k = bb->asClass())
+                scopesToVisit.append(k->members());
+        }
 
-        for (unsigned i = 0; i < scope->symbolCount(); ++i) {
-            Symbol *symbol = scope->symbolAt(i);
+        foreach (Enum *e, binding->enums())
+            scopesToVisit.append(e->members());
 
-            if (symbol->type().isFriend())
-                continue;
-            else if (! staticLookup && (symbol->isTypedef() ||
-                                        symbol->isEnum()    ||
-                                        symbol->isClass()))
+        while (! scopesToVisit.isEmpty()) {
+            Scope *scope = scopesToVisit.takeFirst();
+            if (! scope || scopesVisited.contains(scope))
                 continue;
 
-            addCompletionItem(symbol);
+            scopesVisited.insert(scope);
+
+            for (Scope::iterator it = scope->firstSymbol(); it != scope->lastSymbol(); ++it) {
+                Symbol *member = *it;
+                if (member->isFriend())
+                    continue;
+                else if (! staticLookup && (member->isTypedef() ||
+                                            member->isEnum()    ||
+                                            member->isClass()))
+                    continue;
+
+                addCompletionItem(member);
+            }
         }
     }
 }
 
 bool CppCodeCompletion::completeQtMethod(const QList<LookupItem> &results,
-                                         const LookupContext &context,
                                          bool wantSignals)
 {
     if (results.isEmpty())
         return false;
 
-    ResolveClass resolveClass;
+    const LookupContext &context = typeOfExpression.context();
+
+    DeprecatedLookupContext depContext(typeOfExpression.scope()->owner(),
+                                       context.expressionDocument(),
+                                       context.thisDocument(),
+                                       context.snapshot());
 
     ConvertToCompletionItem toCompletionItem(this);
     Overview o;
@@ -1335,17 +1428,28 @@ bool CppCodeCompletion::completeQtMethod(const QList<LookupItem> &results,
         if (! namedTy) // not a class name.
             continue;
 
-        const QList<Symbol *> classObjects =
-                resolveClass(namedTy->name(), p, context);
+        ClassOrNamespace *b = context.lookupType(namedTy->name(), p.scope());
+        if (! b)
+            continue;
+
+        const QList<Symbol *> classObjects = b->symbols();
 
         if (classObjects.isEmpty())
             continue;
 
-        Class *klass = classObjects.first()->asClass();
+        Class *klass = 0;
+        foreach (Symbol *c, classObjects) {
+            klass = c->asClass();
+            if (klass != 0)
+                break;
+        }
+
+        if (! klass)
+            continue;
 
         QList<Scope *> todo;
-        const QList<Scope *> visibleScopes = context.visibleScopes(p);
-        context.expand(klass->members(), visibleScopes, &todo);
+        const QList<Scope *> visibleScopes = depContext.visibleScopes(p);
+        depContext.expand(klass->members(), visibleScopes, &todo);
 
         foreach (Scope *scope, todo) {
             if (! scope->isClassScope())
@@ -1510,7 +1614,7 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
                     }
                 } else if (! function->isAmbiguous()) {
                     if (completionSettings().m_spaceAfterFunctionName)
-                       extraChars += QLatin1Char(' ');
+                        extraChars += QLatin1Char(' ');
                     extraChars += QLatin1Char('(');
 
                     // If the function doesn't return anything, automatically place the semicolon,
@@ -1586,7 +1690,7 @@ void CppCodeCompletion::cleanup()
 
     // Set empty map in order to avoid referencing old versions of the documents
     // until the next completion
-    typeOfExpression.setSnapshot(Snapshot());
+    typeOfExpression.reset();
 }
 
 int CppCodeCompletion::findStartOfName(int pos) const
index b4bff01..edc7610 100644 (file)
@@ -50,6 +50,11 @@ class ITextEditor;
 class BaseTextEditor;
 }
 
+namespace CPlusPlus {
+class LookupItem;
+class ClassOrNamespace;
+}
+
 namespace CppTools {
 namespace Internal {
 
@@ -89,41 +94,33 @@ private:
     void addCompletionItem(CPlusPlus::Symbol *symbol);
 
     bool completeInclude(const QTextCursor &cursor);
+    void completePreprocessor();
 
     int globalCompletion(CPlusPlus::Symbol *lastVisibleSymbol,
                          CPlusPlus::Document::Ptr thisDocument,
                          const CPlusPlus::Snapshot &snapshot);
 
-    bool completeConstructorOrFunction(const QList<CPlusPlus::LookupItem> &,
-                                       const CPlusPlus::LookupContext &,
+    bool completeConstructorOrFunction(const QList<CPlusPlus::LookupItem> &results,
                                        int endOfExpression, bool toolTipOnly);
 
-    bool completeMember(const QList<CPlusPlus::LookupItem> &,
-                        const CPlusPlus::LookupContext &context);
+    bool completeMember(const QList<CPlusPlus::LookupItem> &results);
+    bool completeScope(const QList<CPlusPlus::LookupItem> &results);
 
-    bool completeScope(const QList<CPlusPlus::LookupItem> &,
-                       const CPlusPlus::LookupContext &context);
+    void completeNamespace(CPlusPlus::ClassOrNamespace *binding);
 
-    void completeNamespace(const QList<CPlusPlus::Symbol *> &candidates,
-                           const CPlusPlus::LookupContext &context);
-
-    void completeClass(const QList<CPlusPlus::Symbol *> &candidates,
-                       const CPlusPlus::LookupContext &context,
+    void completeClass(CPlusPlus::ClassOrNamespace *b,
                        bool staticLookup = true);
 
     bool completeConstructors(CPlusPlus::Class *klass);
 
-    bool completeQtMethod(const QList<CPlusPlus::LookupItem> &,
-                          const CPlusPlus::LookupContext &context,
+    bool completeQtMethod(const QList<CPlusPlus::LookupItem> &results,
                           bool wantSignals);
 
-    bool completeSignal(const QList<CPlusPlus::LookupItem> &results,
-                        const CPlusPlus::LookupContext &context)
-    { return completeQtMethod(results, context, true); }
+    bool completeSignal(const QList<CPlusPlus::LookupItem> &results)
+    { return completeQtMethod(results, true); }
 
-    bool completeSlot(const QList<CPlusPlus::LookupItem> &results,
-                      const CPlusPlus::LookupContext &context)
-    { return completeQtMethod(results, context, false); }
+    bool completeSlot(const QList<CPlusPlus::LookupItem> &results)
+    { return completeQtMethod(results, false); }
 
     int findStartOfName(int pos = -1) const;
 
@@ -136,6 +133,8 @@ private:
 private:
     bool objcKeywordsWanted() const;
 
+    static QStringList preprocessorCompletions;
+
     CppModelManager *m_manager;
     TextEditor::ITextEditable *m_editor;
     int m_startPosition;     // Position of the cursor from which completion started
index 87ad8c3..9048fb9 100644 (file)
@@ -77,7 +77,7 @@
 #include <Parser.h>
 #include <Control.h>
 
-#include <cplusplus/LookupContext.h>
+#include <cplusplus/DeprecatedLookupContext.h>
 
 #include <QtCore/QCoreApplication>
 #include <QtCore/QDebug>
@@ -270,85 +270,43 @@ class Process: public std::unary_function<Document::Ptr, void>
 {
     QPointer<CppModelManager> _modelManager;
     Snapshot _snapshot;
-    CppModelManager::WorkingCopy _workingCopy;
     Document::Ptr _doc;
+    Document::CheckMode _mode;
 
 public:
     Process(QPointer<CppModelManager> modelManager,
-            Snapshot snapshot,
+            Document::Ptr doc,
+            const Snapshot &snapshot,
             const CppModelManager::WorkingCopy &workingCopy)
         : _modelManager(modelManager),
           _snapshot(snapshot),
-          _workingCopy(workingCopy)
-    { }
-
-    LookupContext lookupContext(unsigned line, unsigned column) const
-    { return lookupContext(_doc->findSymbolAt(line, column)); }
-
-    LookupContext lookupContext(Symbol *symbol) const
+          _doc(doc),
+          _mode(Document::FastCheck)
     {
-        LookupContext context(symbol, Document::create(QLatin1String("<none>")), _doc, _snapshot);
-        return context;
+
+        if (workingCopy.contains(_doc->fileName()))
+            _mode = Document::FullCheck;
     }
 
-    void operator()(Document::Ptr doc)
+    void operator()()
     {
-        _doc = doc;
-
-        Document::CheckMode mode = Document::FastCheck;
-
-        if (_workingCopy.contains(doc->fileName()))
-            mode = Document::FullCheck;
-
-        if (doc->isParsed() && mode == Document::FastCheck) {
-            TranslationUnit *unit = doc->translationUnit();
-            MemoryPool *pool = unit->memoryPool();
+        _doc->check(_mode);
 
-            Parser parser(unit);
-            Semantic semantic(unit);
+        if (_mode == Document::FullCheck) {
+            // run the binding pass
+            NamespaceBindingPtr ns = bind(_doc, _snapshot);
 
-            Namespace *globalNamespace = doc->control()->newNamespace(0);
-            doc->setGlobalNamespace(globalNamespace);
+            // check for undefined symbols.
+            CheckUndefinedSymbols checkUndefinedSymbols(_doc);
+            checkUndefinedSymbols.setGlobalNamespaceBinding(ns);
 
-            Scope *globals = globalNamespace->members();
-
-            while (parser.LA()) {
-                unsigned start_declaration = parser.cursor();
-                DeclarationAST *declaration = 0;
-
-                if (parser.parseDeclaration(declaration)) {
-                    semantic.check(declaration, globals);
-
-                } else {
-                    doc->translationUnit()->error(start_declaration, "expected a declaration");
-                    parser.rewind(start_declaration + 1);
-                    parser.skipUntilDeclaration();
-                }
-
-                parser.clearTemplateArgumentList();
-                pool->reset();
-            }
-
-        } else {
-            doc->parse();
-            doc->check(mode);
-
-            if (mode == Document::FullCheck) {
-                // run the binding pass
-                NamespaceBindingPtr ns = bind(doc, _snapshot);
-
-                // check for undefined symbols.
-                CheckUndefinedSymbols checkUndefinedSymbols(doc);
-                checkUndefinedSymbols.setGlobalNamespaceBinding(ns);
-
-                checkUndefinedSymbols(doc->translationUnit()->ast()); // ### FIXME
-            }
+            checkUndefinedSymbols(_doc->translationUnit()->ast()); // ### FIXME
         }
 
-        doc->releaseTranslationUnit();
+        _doc->releaseTranslationUnit();
 
         if (_modelManager)
-            _modelManager->emitDocumentUpdated(doc); // ### TODO: compress
+            _modelManager->emitDocumentUpdated(_doc); // ### TODO: compress
     }
 };
 } // end of anonymous namespace
@@ -398,6 +356,28 @@ bool CppPreprocessor::includeFile(const QString &absoluteFilePath, QString *resu
 
 QString CppPreprocessor::tryIncludeFile(QString &fileName, IncludeType type, unsigned *revision)
 {
+    if (type == IncludeGlobal) {
+        const QString fn = m_fileNameCache.value(fileName);
+
+        if (! fn.isEmpty()) {
+            fileName = fn;
+
+            if (revision)
+                *revision = 0;
+
+            return QString();
+        }
+    }
+
+    const QString originalFileName = fileName;
+    const QString contents = tryIncludeFile_helper(fileName, type, revision);
+    if (type == IncludeGlobal)
+        m_fileNameCache.insert(originalFileName, fileName);
+    return contents;
+}
+
+QString CppPreprocessor::tryIncludeFile_helper(QString &fileName, IncludeType type, unsigned *revision)
+{
     QFileInfo fileInfo(fileName);
     if (fileName == QLatin1String(pp_configuration_file) || fileInfo.isAbsolute()) {
         QString contents;
@@ -619,9 +599,9 @@ void CppPreprocessor::sourceNeeded(QString &fileName, IncludeType type, unsigned
     m_todo.remove(fileName);
 
 #ifndef ICHECK_BUILD
-    Process process(m_modelManager, snapshot, m_workingCopy);
+    Process process(m_modelManager, doc, snapshot, m_workingCopy);
 
-    process(doc);
+    process();
 
     (void) switchDocument(previousDoc);
 #else
@@ -825,7 +805,7 @@ QList<int> CppModelManager::references(CPlusPlus::Symbol *symbol,
                                        const CPlusPlus::Snapshot &snapshot)
 {
     NamespaceBindingPtr glo = bind(doc, snapshot);
-    return m_findReferences->references(LookupContext::canonicalSymbol(symbol, glo.data()), doc, snapshot);
+    return m_findReferences->references(DeprecatedLookupContext::canonicalSymbol(symbol, glo.data()), doc, snapshot);
 }
 
 void CppModelManager::findUsages(CPlusPlus::Document::Ptr symbolDocument, CPlusPlus::Symbol *symbol)
@@ -1326,41 +1306,6 @@ void CppModelManager::updateIncludesInPaths(QFutureInterface<void> &future,
     future.reportFinished();
 }
 
-// Function that sorts headers and sources apart to be used for
-// MimeDB::findByFile() on a sequence of file names.
-class HeaderSourceSorter {
-public:
-    explicit HeaderSourceSorter(QStringList *sources, QStringList *headers);
-    void operator()(const Core::MimeType &, const QFileInfo &, const QString &);
-
-private:
-    QStringList m_sourceMimeTypes;
-    QStringList m_headerMimeTypes;
-
-    QStringList *m_sources;
-    QStringList *m_headers;
-};
-
-HeaderSourceSorter::HeaderSourceSorter(QStringList *sources, QStringList *headers) :
-        m_sources(sources),
-        m_headers(headers)
-{
-    m_headerMimeTypes << QLatin1String("text/x-hdr") << QLatin1String("text/x-c++hdr");
-    m_sourceMimeTypes << QLatin1String("text/x-csrc") << QLatin1String("text/x-c++src")
-                      << QLatin1String("text/x-objcsrc");
-}
-
-void HeaderSourceSorter::operator()(const Core::MimeType &mimeType, const QFileInfo &, const QString &name)
-{
-    if (mimeType) {
-        if (m_sourceMimeTypes.contains(mimeType.type())) {
-            m_sources->append(name);
-        } else if (m_headerMimeTypes.contains(mimeType.type())) {
-            m_headers->append(name);
-        }
-    }
-}
-
 void CppModelManager::parse(QFutureInterface<void> &future,
                             CppPreprocessor *preproc,
                             QStringList files)
@@ -1368,14 +1313,28 @@ void CppModelManager::parse(QFutureInterface<void> &future,
     if (files.isEmpty())
         return;
 
-    foreach (const QString &file, files)
-        preproc->snapshot.remove(file);
+    const Core::MimeDatabase *mimeDb = Core::ICore::instance()->mimeDatabase();
+    Core::MimeType cSourceTy = mimeDb->findByType(QLatin1String("text/x-csrc"));
+    Core::MimeType cppSourceTy = mimeDb->findByType(QLatin1String("text/x-c++src"));
+    Core::MimeType mSourceTy = mimeDb->findByType(QLatin1String("text/x-objcsrc"));
 
     QStringList sources;
     QStringList headers;
-    const Core::MimeDatabase *mimeDb = Core::ICore::instance()->mimeDatabase();
-    mimeDb->findByFile(files.constBegin(), files.constEnd(),
-                       HeaderSourceSorter(&sources, &headers));
+
+    QStringList suffixes = cSourceTy.suffixes();
+    suffixes += cppSourceTy.suffixes();
+    suffixes += mSourceTy.suffixes();
+
+    foreach (const QString &file, files) {
+        QFileInfo info(file);
+
+        preproc->snapshot.remove(file);
+
+        if (suffixes.contains(info.suffix()))
+            sources.append(file);
+        else
+            headers.append(file);
+    }
 
     const int sourceCount = sources.size();
     files = sources;
@@ -1396,9 +1355,6 @@ void CppModelManager::parse(QFutureInterface<void> &future,
         if (future.isCanceled())
             break;
 
-        // Change the priority of the background parser thread to idle.
-        QThread::currentThread()->setPriority(QThread::IdlePriority);
-
         const QString fileName = files.at(i);
 
         const bool isSourceFile = i < sourceCount;
@@ -1417,9 +1373,6 @@ void CppModelManager::parse(QFutureInterface<void> &future,
 
         if (isSourceFile)
             preproc->resetEnvironment();
-
-        // Restore the previous thread priority.
-        QThread::currentThread()->setPriority(QThread::NormalPriority);
     }
 
     future.setProgressValue(files.size());
index ac35ef0..1ba6d71 100644 (file)
@@ -237,7 +237,6 @@ private:
 };
 #endif
 
-using namespace CPlusPlus;
 class CppPreprocessor: public CPlusPlus::Client
 {
 public:
@@ -264,25 +263,26 @@ public:
     { return m_todo; }
 
 public: // attributes
-    Snapshot snapshot;
+    CPlusPlus::Snapshot snapshot;
 
 protected:
     CPlusPlus::Document::Ptr switchDocument(CPlusPlus::Document::Ptr doc);
 
     bool includeFile(const QString &absoluteFilePath, QString *result, unsigned *revision);
     QString tryIncludeFile(QString &fileName, IncludeType type, unsigned *revision);
+    QString tryIncludeFile_helper(QString &fileName, IncludeType type, unsigned *revision);
 
     void mergeEnvironment(CPlusPlus::Document::Ptr doc);
 
-    virtual void macroAdded(const Macro &macro);
-    virtual void passedMacroDefinitionCheck(unsigned offset, const Macro &macro);
+    virtual void macroAdded(const CPlusPlus::Macro &macro);
+    virtual void passedMacroDefinitionCheck(unsigned offset, const CPlusPlus::Macro &macro);
     virtual void failedMacroDefinitionCheck(unsigned offset, const QByteArray &name);
     virtual void startExpandingMacro(unsigned offset,
-                                     const Macro &macro,
+                                     const CPlusPlus::Macro &macro,
                                      const QByteArray &originalText,
                                      bool inCondition,
-                                     const QVector<MacroArgumentReference> &actuals);
-    virtual void stopExpandingMacro(unsigned offset, const Macro &macro);
+                                     const QVector<CPlusPlus::MacroArgumentReference> &actuals);
+    virtual void stopExpandingMacro(unsigned offset, const CPlusPlus::Macro &macro);
     virtual void startSkippingBlocks(unsigned offset);
     virtual void stopSkippingBlocks(unsigned offset);
     virtual void sourceNeeded(QString &fileName, IncludeType type,
@@ -292,18 +292,19 @@ private:
 #ifndef ICHECK_BUILD
     QPointer<CppModelManager> m_modelManager;
 #endif
-    Environment env;
-    Preprocessor preprocess;
+    CPlusPlus::Environment env;
+    CPlusPlus::Preprocessor preprocess;
     QStringList m_includePaths;
     QStringList m_systemIncludePaths;
     CppModelManagerInterface::WorkingCopy m_workingCopy;
     QStringList m_projectFiles;
     QStringList m_frameworkPaths;
     QSet<QString> m_included;
-    Document::Ptr m_currentDoc;
+    CPlusPlus::Document::Ptr m_currentDoc;
     QSet<QString> m_todo;
     QSet<QString> m_processed;
     unsigned m_revision;
+    QHash<QString, QString> m_fileNameCache;
 };
 
 } // namespace Internal
index 4390279..5a72984 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="CVS" version="1.3.84" compatVersion="1.3.84">
+<plugin name="CVS" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,9 +14,9 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>CVS integration.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="TextEditor" version="1.3.84"/>
-        <dependency name="ProjectExplorer" version="1.3.84"/>
-        <dependency name="Core" version="1.3.84"/>
-        <dependency name="VCSBase" version="1.3.84"/>
+        <dependency name="TextEditor" version="2.0.80"/>
+        <dependency name="ProjectExplorer" version="2.0.80"/>
+        <dependency name="Core" version="2.0.80"/>
+        <dependency name="VCSBase" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 33e08c0..dbf8adf 100644 (file)
@@ -54,6 +54,7 @@ bool CVSControl::supportsOperation(Operation operation) const
     case DeleteOperation:
     case AnnotateOperation:
         break;
+    case MoveOperation:
     case OpenOperation:
     case CreateRepositoryOperation:
     case SnapshotOperations:
@@ -81,6 +82,13 @@ bool CVSControl::vcsDelete(const QString &fileName)
     return m_plugin->vcsDelete(fi.absolutePath(), fi.fileName());
 }
 
+bool CVSControl::vcsMove(const QString &from, const QString &to)
+{
+    Q_UNUSED(from);
+    Q_UNUSED(to);
+    return false;
+}
+
 bool CVSControl::vcsCreateRepository(const QString &)
 {
     return false;
@@ -112,14 +120,9 @@ bool CVSControl::vcsAnnotate(const QString &file, int line)
     return true;
 }
 
-bool CVSControl::managesDirectory(const QString &directory) const
-{
-    return m_plugin->managesDirectory(directory);
-}
-
-QString CVSControl::findTopLevelForDirectory(const QString &directory) const
+bool CVSControl::managesDirectory(const QString &directory, QString *topLevel) const
 {
-    return m_plugin->findTopLevelForDirectory(directory);
+    return m_plugin->managesDirectory(directory, topLevel);
 }
 
 void CVSControl::emitRepositoryChanged(const QString &s)
index 24483af..4fd06c2 100644 (file)
@@ -45,13 +45,13 @@ public:
     explicit CVSControl(CVSPlugin *plugin);
     virtual QString displayName() const;
 
-    virtual bool managesDirectory(const QString &directory) const;
-    virtual QString findTopLevelForDirectory(const QString &directory) const;
+    virtual bool managesDirectory(const QString &directory, QString *topLevel = 0) const;
 
     virtual bool supportsOperation(Operation operation) const;
     virtual bool vcsOpen(const QString &fileName);
     virtual bool vcsAdd(const QString &fileName);
     virtual bool vcsDelete(const QString &filename);
+    virtual bool vcsMove(const QString &from, const QString &to);
     virtual bool vcsCreateRepository(const QString &directory);
     virtual QString vcsCreateSnapshot(const QString &topLevel);
     virtual QStringList vcsSnapshots(const QString &topLevel);
index 147c522..b7f0f46 100644 (file)
@@ -827,8 +827,10 @@ void CVSPlugin::slotDescribe(const QString &source, const QString &changeNr)
 
 bool CVSPlugin::describe(const QString &file, const QString &changeNr, QString *errorMessage)
 {
-    const QString toplevel = findTopLevelForDirectory(QFileInfo(file).absolutePath());
-    if (toplevel.isEmpty()) {
+
+    QString toplevel;
+    const bool manages = managesDirectory(QFileInfo(file).absolutePath(), &toplevel);
+    if (!manages || toplevel.isEmpty()) {
         *errorMessage = msgCannotFindTopLevel(file);
         return false;
     }
@@ -1122,45 +1124,44 @@ bool CVSPlugin::vcsDelete(const QString &workingDir, const QString &rawFileName)
 
 /* CVS has a "CVS" directory in each directory it manages. The top level
  * is the first directory under the directory that does not have it. */
-bool CVSPlugin::managesDirectory(const QString &directory) const
+bool CVSPlugin::managesDirectory(const QString &directory, QString *topLevel /* = 0 */) const
 {
+    if (topLevel)
+        topLevel->clear();
+    bool manages = false;
     const QDir dir(directory);
-    const bool rc = dir.exists() && managesDirectory(dir);
-    if (CVS::Constants::debug)
-        qDebug() << "CVSPlugin::managesDirectory" << directory << rc;
-    return rc;
+    do {
+        if (!dir.exists() || !checkCVSDirectory(dir))
+            break;
+        manages = true;
+        if (!topLevel)
+            break;
+        /* Recursing up, the top level is a child of the first directory that does
+         * not have a  "CVS" directory. The starting directory must be a managed
+         * one. Go up and try to find the first unmanaged parent dir. */
+        QDir lastDirectory = dir;
+        for (QDir parentDir = lastDirectory; parentDir.cdUp() ; lastDirectory = parentDir) {
+            if (!checkCVSDirectory(parentDir)) {
+                *topLevel = lastDirectory.absolutePath();
+                break;
+            }
+        }
+    } while (false);
+    if (CVS::Constants::debug) {
+        QDebug nsp = qDebug().nospace();
+        nsp << "CVSPlugin::managesDirectory" << directory << manages;
+        if (topLevel)
+            nsp << *topLevel;
+    }
+    return manages;
 }
 
-bool CVSPlugin::managesDirectory(const QDir &directory) const
+bool CVSPlugin::checkCVSDirectory(const QDir &directory) const
 {
     const QString cvsDir = directory.absoluteFilePath(QLatin1String("CVS"));
     return QFileInfo(cvsDir).isDir();
 }
 
-QString CVSPlugin::findTopLevelForDirectory(const QString &directory) const
-{
-    // Debug wrapper
-    const QString rc = findTopLevelForDirectoryI(directory);
-    if (CVS::Constants::debug)
-        qDebug() << "CVSPlugin::findTopLevelForDirectory" << directory << rc;
-    return rc;
-}
-
-QString CVSPlugin::findTopLevelForDirectoryI(const QString &directory) const
-{
-    /* Recursing up, the top level is a child of the first directory that does
-     * not have a  "CVS" directory. The starting directory must be a managed
-     * one. Go up and try to find the first unmanaged parent dir. */
-    QDir lastDirectory = QDir(directory);
-    if (!lastDirectory.exists() || !managesDirectory(lastDirectory))
-        return QString();
-    for (QDir parentDir = lastDirectory; parentDir.cdUp() ; lastDirectory = parentDir) {
-        if (!managesDirectory(parentDir))
-            return lastDirectory.absolutePath();
-    }
-    return QString();
-}
-
 CVSControl *CVSPlugin::cvsVersionControl() const
 {
     return static_cast<CVSControl *>(versionControl());
index 1548729..c95cb83 100644 (file)
@@ -95,8 +95,7 @@ public:
     // IVersionControl
     bool vcsAdd(const QString &workingDir, const QString &fileName);
     bool vcsDelete(const QString &workingDir, const QString &fileName);
-    bool managesDirectory(const QString &directory) const;
-    QString findTopLevelForDirectory(const QString &directory) const;
+    bool managesDirectory(const QString &directory, QString *topLevel = 0) const;
 
     static CVSPlugin *cvsPluginInstance();
 
@@ -145,7 +144,7 @@ private:
     void filelog(const QString &workingDir,
                  const QStringList &files = QStringList(),
                  bool enableAnnotationContextMenu = false);
-    bool managesDirectory(const QDir &directory) const;
+    bool checkCVSDirectory(const QDir &directory) const;
     QString findTopLevelForDirectoryI(const QString &directory) const;
     void startCommit(const QString &workingDir, const QStringList &files = QStringList());
     bool commit(const QString &messageFile, const QStringList &subVersionFileList);
index 2290a20..a396d75 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="Debugger" version="1.3.84" compatVersion="1.3.84">
+<plugin name="Debugger" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,15 +14,16 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Debugger integration.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="CppEditor" version="1.3.84"/><!-- Debugger plugin adds items to the editor's context menu -->
-        <dependency name="ProjectExplorer" version="1.3.84"/>
-        <dependency name="Core" version="1.3.84"/>
-        <dependency name="Find" version="1.3.84"/>
+        <dependency name="CppEditor" version="2.0.80"/><!-- Debugger plugin adds items to the editor's context menu -->
+        <dependency name="ProjectExplorer" version="2.0.80"/>
+        <dependency name="Core" version="2.0.80"/>
+        <dependency name="Find" version="2.0.80"/>
     </dependencyList>
     <argumentList>
         <argument name="-disable-cdb">Disable Cdb debugger engine</argument>
         <argument name="-disable-gdb">Disable Gdb debugger engine</argument>
         <argument name="-disable-sdb">Disable Qt Script debugger engine</argument>
+        <argument name="-disable-tcf">Disable Tcf debugger engine</argument>
         <argument name="-debug" parameter="pid-or-corefile">Attach to Process-Id or Core file</argument>
         <argument name="-wincrashevent" parameter="event-handle">Event handle used for attaching to crashed processes</argument>
     </argumentList>
diff --git a/src/plugins/debugger/attachtcfdialog.ui b/src/plugins/debugger/attachtcfdialog.ui
new file mode 100644 (file)
index 0000000..c890f11
--- /dev/null
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AttachTcfDialog</class>
+ <widget class="QDialog" name="AttachTcfDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>310</width>
+    <height>224</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Start Debugger</string>
+  </property>
+  <layout class="QVBoxLayout">
+   <property name="spacing">
+    <number>6</number>
+   </property>
+   <property name="margin">
+    <number>9</number>
+   </property>
+   <item>
+    <layout class="QFormLayout" name="formLayout">
+     <property name="fieldGrowthPolicy">
+      <enum>QFormLayout::ExpandingFieldsGrow</enum>
+     </property>
+     <item row="0" column="0">
+      <widget class="QLabel" name="channelLabel">
+       <property name="text">
+        <string>Host and port:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QLineEdit" name="channelLineEdit">
+       <property name="text">
+        <string notr="true">localhost:5115</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="0">
+      <widget class="QLabel" name="architectureLabel">
+       <property name="text">
+        <string>Architecture:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QComboBox" name="architectureComboBox"/>
+     </item>
+     <item row="2" column="1">
+      <widget class="QCheckBox" name="useServerStartScriptCheckBox"/>
+     </item>
+     <item row="2" column="0">
+      <widget class="QLabel" name="useServerStartScriptLabel">
+       <property name="text">
+        <string>Use server start script:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="1">
+      <widget class="Utils::PathChooser" name="serverStartScript" native="true"/>
+     </item>
+     <item row="3" column="0">
+      <widget class="QLabel" name="serverStartScriptLabel">
+       <property name="text">
+        <string>Server start script:</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>Utils::PathChooser</class>
+   <extends>QWidget</extends>
+   <header location="global">utils/pathchooser.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
index f5b5b08..73aaa8a 100644 (file)
    <item>
     <layout class="QGridLayout" name="gridLayout">
      <item row="0" column="0">
+      <widget class="QLabel" name="labelFileName">
+       <property name="text">
+        <string>File name:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QLineEdit" name="lineEditFileName"/>
+     </item>
+     <item row="1" column="0">
+      <widget class="QLabel" name="labelLineNumber">
+       <property name="text">
+        <string>Line number:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QLineEdit" name="lineEditLineNumber"/>
+     </item>
+     <item row="2" column="0">
+      <widget class="QLabel" name="labelFunction">
+       <property name="text">
+        <string>Function:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="1">
+      <widget class="QLineEdit" name="lineEditFunction"/>
+     </item>
+     <item row="3" column="0">
       <widget class="QLabel" name="labelCondition">
        <property name="text">
         <string>Condition:</string>
        </property>
       </widget>
      </item>
-     <item row="0" column="1">
+     <item row="3" column="1">
       <widget class="QLineEdit" name="lineEditCondition"/>
      </item>
-     <item row="1" column="0">
+     <item row="4" column="0">
       <widget class="QLabel" name="labelIgnoreCount">
        <property name="text">
         <string>Ignore count:</string>
        </property>
       </widget>
      </item>
-     <item row="1" column="1">
-      <widget class="QSpinBox" name="spinBoxIgnoreCount">
-       <property name="layoutDirection">
-        <enum>Qt::LeftToRight</enum>
-       </property>
-       <property name="maximum">
-        <number>999999999</number>
+     <item row="4" column="1">
+      <widget class="QLineEdit" name="lineEditIgnoreCount"/>
+     </item>
+     <item row="5" column="0">
+      <widget class="QLabel" name="labelThreadSpec">
+       <property name="text">
+        <string>Thread specification:</string>
        </property>
       </widget>
      </item>
+     <item row="5" column="1">
+      <widget class="QLineEdit" name="lineEditThreadSpec"/>
+     </item>
     </layout>
    </item>
    <item>
index 6ed2830..007544e 100644 (file)
 
 #include "debuggeractions.h"
 #include "debuggermanager.h"
+#include "debuggerstringutils.h"
 #include "stackframe.h"
 
 #include <texteditor/basetextmark.h>
 #include <utils/qtcassert.h>
 
+#include <QtCore/QByteArray>
 #include <QtCore/QDebug>
 #include <QtCore/QTextStream>
 #include <QtCore/QFileInfo>
@@ -53,13 +55,11 @@ using namespace Debugger::Internal;
 // Compare file names case insensitively on Windows.
 static inline bool fileNameMatch(const QString &f1, const QString &f2)
 {
-    return f1.compare(f2,
 #ifdef Q_OS_WIN
-                      Qt::CaseInsensitive
+    return f1.compare(f2, Qt::CaseInsensitive) == 0;
 #else
-                      Qt::CaseSensitive
+    return f1 == f2;
 #endif
-                      ) == 0;
 }
 
 namespace Debugger {
@@ -87,7 +87,7 @@ public:
 
     QIcon icon() const
     {
-        const BreakHandler *handler = DebuggerManager::instance()->breakHandler();
+        const BreakHandler *handler = m_data->handler();
         if (!m_enabled)
             return handler->disabledBreakpointIcon();
         return m_pending ? handler->pendingBreakPointIcon() : handler->breakpointIcon();
@@ -113,7 +113,7 @@ public:
             return;
 
         BreakHandler *handler = m_data->handler();
-        handler->removeBreakpoint(handler->indexOf(m_data));
+        handler->removeBreakpoint(m_data);
         handler->saveBreakpoints();
         handler->updateMarkers();
     }
@@ -162,28 +162,21 @@ private:
 //
 //////////////////////////////////////////////////////////////////
 
-BreakpointData::BreakpointData(BreakHandler *handler)
+BreakpointData::BreakpointData()
 {
-    //qDebug() << "CREATE BREAKPOINTDATA" << this;
-    m_handler = handler;
+    m_handler = 0;
     enabled = true;
     pending = true;
+    type = BreakpointType;
     marker = 0;
     m_markerLineNumber = 0;
     bpMultiple = false;
-//#if defined(Q_OS_MAC)
-//    // full names do not work on Mac/MI
     useFullPath = false;
-//#else
-//    //where = m_manager->shortName(data->fileName);
-//    useFullPath = true;
-//#endif
 }
 
 BreakpointData::~BreakpointData()
 {
     removeMarker();
-    //qDebug() << "DESTROY BREAKPOINTDATA" << this;
 }
 
 void BreakpointData::removeMarker()
@@ -227,8 +220,12 @@ QString BreakpointData::toToolTip() const
         << "</td><td>" << m_markerLineNumber << "</td></tr>"
         << "<tr><td>" << BreakHandler::tr("Breakpoint Number:")
         << "</td><td>" << bpNumber << "</td></tr>"
-        << "<tr><td>" << BreakHandler::tr("Breakpoint Address:")
-        << "</td><td>" << bpAddress << "</td></tr>"
+        << "<tr><td>" << BreakHandler::tr("Breakpoint Type:")
+        << "</td><td>"
+        << (type == BreakpointType ? BreakHandler::tr("Breakpoint") 
+            : type == WatchpointType ? BreakHandler::tr("Watchpoint")
+            : BreakHandler::tr("Unknown breakpoint type"))
+        << "</td></tr>"
         << "</table><br><hr><table>"
         << "<tr><th>" << BreakHandler::tr("Property")
         << "</th><th>" << BreakHandler::tr("Requested")
@@ -241,12 +238,16 @@ QString BreakpointData::toToolTip() const
         << "</td><td>" << funcName << "</td><td>" << bpFuncName << "</td></tr>"
         << "<tr><td>" << BreakHandler::tr("Line Number:")
         << "</td><td>" << lineNumber << "</td><td>" << bpLineNumber << "</td></tr>"
+        << "<tr><td>" << BreakHandler::tr("Breakpoint Address:")
+        << "</td><td>" << address << "</td><td>" << bpAddress << "</td></tr>"
         << "<tr><td>" << BreakHandler::tr("Corrected Line Number:")
         << "</td><td>-</td><td>" << bpCorrectedLineNumber << "</td></tr>"
         << "<tr><td>" << BreakHandler::tr("Condition:")
         << "</td><td>" << condition << "</td><td>" << bpCondition << "</td></tr>"
         << "<tr><td>" << BreakHandler::tr("Ignore Count:")
         << "</td><td>" << ignoreCount << "</td><td>" << bpIgnoreCount << "</td></tr>"
+        << "<tr><td>" << BreakHandler::tr("Thread Specification:")
+        << "</td><td>" << threadSpec << "</td><td>" << bpThreadSpec << "</td></tr>"
         << "</table></body></html>";
     return rc;
 }
@@ -255,20 +256,27 @@ QString BreakpointData::toString() const
 {
     QString rc;
     QTextStream str(&rc);
-    str << BreakHandler::tr("Marker File:") << m_markerFileName << ' '
-        << BreakHandler::tr("Marker Line:") << m_markerLineNumber << ' '
-        << BreakHandler::tr("Breakpoint Number:") << bpNumber << ' '
-        << BreakHandler::tr("Breakpoint Address:") << bpAddress << '\n'
-        << BreakHandler::tr("File Name:")
+    str << BreakHandler::tr("Marker File:") << ' ' <<  m_markerFileName << '\n'
+        << BreakHandler::tr("Marker Line:") <<  ' ' << m_markerLineNumber << '\n'
+        << BreakHandler::tr("Breakpoint Number:") <<  ' ' << bpNumber << '\n'
+        << BreakHandler::tr("Breakpoint Type:") << ' '
+        << (type == BreakpointType ? BreakHandler::tr("Breakpoint") 
+            : type == WatchpointType ? BreakHandler::tr("Watchpoint")
+            : BreakHandler::tr("Unknown breakpoint type")) << '\n'
+        << BreakHandler::tr("File Name:") << ' '
         << fileName << " -- " << bpFileName << '\n'
-        << BreakHandler::tr("Function Name:")
+        << BreakHandler::tr("Function Name:") << ' '
         << funcName << " -- " << bpFuncName << '\n'
-        << BreakHandler::tr("Line Number:")
+        << BreakHandler::tr("Line Number:") << ' '
         << lineNumber << " -- " << bpLineNumber << '\n'
-        << BreakHandler::tr("Condition:")
+        << BreakHandler::tr("Breakpoint Address:") << ' '
+        << address << " -- " << bpAddress << '\n'
+        << BreakHandler::tr("Condition:") << ' '
         << condition << " -- " << bpCondition << '\n'
-        << BreakHandler::tr("Ignore Count:")
-        << ignoreCount << " -- " << bpIgnoreCount << '\n';
+        << BreakHandler::tr("Ignore Count:") << ' '
+        << ignoreCount << " -- " << bpIgnoreCount << '\n'
+        << BreakHandler::tr("Thread Specification:") << ' '
+        << threadSpec << " -- " << bpThreadSpec << '\n';
     return rc;
 }
 
@@ -306,9 +314,10 @@ bool BreakpointData::conditionsMatch() const
 
 BreakHandler::BreakHandler(DebuggerManager *manager, QObject *parent) :
     QAbstractTableModel(parent),
-    m_breakpointIcon(QLatin1String(":/debugger/images/breakpoint_16.png")),
-    m_disabledBreakpointIcon(QLatin1String(":/debugger/images/breakpoint_disabled_16.png")),
-    m_pendingBreakPointIcon(QLatin1String(":/debugger/images/breakpoint_pending_16.png")),
+    m_breakpointIcon(_(":/debugger/images/breakpoint_16.png")),
+    m_disabledBreakpointIcon(_(":/debugger/images/breakpoint_disabled_16.png")),
+    m_pendingBreakPointIcon(_(":/debugger/images/breakpoint_pending_16.png")),
+    m_watchpointIcon(_(":/debugger/images/watchpoint.png")),
     m_manager(manager)
 {
 }
@@ -320,7 +329,7 @@ BreakHandler::~BreakHandler()
 
 int BreakHandler::columnCount(const QModelIndex &parent) const
 {
-    return parent.isValid() ? 0 : 7;
+    return parent.isValid() ? 0 : 8;
 }
 
 int BreakHandler::rowCount(const QModelIndex &parent) const
@@ -359,39 +368,35 @@ void BreakHandler::clear()
     m_inserted.clear();
 }
 
-int BreakHandler::findBreakpoint(const BreakpointData &needle) const
+BreakpointData *BreakHandler::findSimilarBreakpoint(const BreakpointData &needle) const
 {
     // Search a breakpoint we might refer to.
     for (int index = 0; index != size(); ++index) {
-        const BreakpointData *data = at(index);
+        BreakpointData *data = m_bp[index];
         // Clear hit.
-        if (data->bpNumber == needle.bpNumber)
-            return index;
+        if (data->bpNumber == needle.bpNumber
+                && !data->bpNumber.isEmpty()
+                && data->bpNumber.toInt() != 0)
+            return data;
+        // Clear miss.
+        if (data->type != needle.type)
+            continue;
+        // We have numbers, but they are different.
+        if (!data->bpNumber.isEmpty() && !needle.bpNumber.isEmpty()
+                && !data->bpNumber.startsWith(needle.bpNumber)
+                && !needle.bpNumber.startsWith(data->bpNumber))
+            continue;
         // At least at a position we were looking for.
         // FIXME: breaks multiple breakpoints at the same location
-        if (fileNameMatch(data->fileName, needle.bpFileName)
+        if (!data->fileName.isEmpty()
+                && fileNameMatch(data->fileName, needle.bpFileName)
                 && data->lineNumber == needle.bpLineNumber)
-            return index;
+            return data;
     }
-    return -1;
-}
-
-int BreakHandler::findBreakpoint(const QString &fileName, int lineNumber) const
-{
-    if (lineNumber <= 0) {
-        QByteArray address = fileName.toLatin1();
-        for (int index = 0; index != size(); ++index)
-            if (at(index)->bpAddress == address)
-                return index;
-    } else {
-        for (int index = 0; index != size(); ++index)
-            if (at(index)->isLocatedAt(fileName, lineNumber))
-                return index;
-    }
-    return -1;
+    return 0;
 }
 
-BreakpointData *BreakHandler::findBreakpoint(int bpNumber) const
+BreakpointData *BreakHandler::findBreakpointByNumber(int bpNumber) const
 {
     if (!size())
         return 0;
@@ -402,26 +407,51 @@ BreakpointData *BreakHandler::findBreakpoint(int bpNumber) const
     return 0;
 }
 
+int BreakHandler::findWatchPointIndexByAddress(const QByteArray &a) const
+{
+    for (int index = size() - 1; index >= 0; --index) {
+        BreakpointData *bd = at(index);
+        if (bd->type == BreakpointData::WatchpointType && bd->address == a)
+            return index;
+    }
+    return -1;
+}
+
+bool BreakHandler::watchPointAt(quint64 address) const
+{
+    const QByteArray addressBA = QByteArray("0x") + QByteArray::number(address, 16);
+    return findWatchPointIndexByAddress(addressBA) != -1;
+}
+
 void BreakHandler::saveBreakpoints()
 {
     QList<QVariant> list;
     for (int index = 0; index != size(); ++index) {
         const BreakpointData *data = at(index);
         QMap<QString, QVariant> map;
+        // Do not persist Watchpoints.
+        //if (data->type == BreakpointData::WatchpointType)
+        //    continue;
+        if (data->type != BreakpointData::BreakpointType)
+            map.insert(_("type"), data->type);
         if (!data->fileName.isEmpty())
-            map.insert(QLatin1String("filename"), data->fileName);
+            map.insert(_("filename"), data->fileName);
         if (!data->lineNumber.isEmpty())
-            map.insert(QLatin1String("linenumber"), data->lineNumber);
+            map.insert(_("linenumber"), data->lineNumber);
         if (!data->funcName.isEmpty())
-            map.insert(QLatin1String("funcname"), data->funcName);
+            map.insert(_("funcname"), data->funcName);
+        if (!data->address.isEmpty())
+            map.insert(_("address"), data->address);
         if (!data->condition.isEmpty())
-            map.insert(QLatin1String("condition"), data->condition);
+            map.insert(_("condition"), data->condition);
         if (!data->ignoreCount.isEmpty())
-            map.insert(QLatin1String("ignorecount"), data->ignoreCount);
+            map.insert(_("ignorecount"), data->ignoreCount);
+        if (!data->threadSpec.isEmpty())
+            map.insert(_("threadspec"), data->threadSpec);
         if (!data->enabled)
-            map.insert(QLatin1String("disabled"), QLatin1String("1"));
+            map.insert(_("disabled"), _("1"));
         if (data->useFullPath)
-            map.insert(QLatin1String("usefullpath"), QLatin1String("1"));
+            map.insert(_("usefullpath"), _("1"));
         list.append(map);
     }
     m_manager->setSessionValue("Breakpoints", list);
@@ -434,28 +464,37 @@ void BreakHandler::loadBreakpoints()
     clear();
     foreach (const QVariant &var, list) {
         const QMap<QString, QVariant> map = var.toMap();
-        BreakpointData *data = new BreakpointData(this);
-        QVariant v = map.value(QLatin1String("filename"));
+        BreakpointData *data = new BreakpointData;
+        QVariant v = map.value(_("filename"));
         if (v.isValid())
             data->fileName = v.toString();
-        v = map.value(QLatin1String("linenumber"));
+        v = map.value(_("linenumber"));
         if (v.isValid())
             data->lineNumber = v.toString().toLatin1();
-        v = map.value(QLatin1String("condition"));
+        v = map.value(_("condition"));
         if (v.isValid())
             data->condition = v.toString().toLatin1();
-        v = map.value(QLatin1String("ignorecount"));
+        v = map.value(_("address"));
+        if (v.isValid())
+            data->address = v.toString().toLatin1();
+        v = map.value(_("ignorecount"));
         if (v.isValid())
             data->ignoreCount = v.toString().toLatin1();
-        v = map.value(QLatin1String("funcname"));
+        v = map.value(_("threadspec"));
+        if (v.isValid())
+            data->threadSpec = v.toString().toLatin1();
+        v = map.value(_("funcname"));
         if (v.isValid())
             data->funcName = v.toString();
-        v = map.value(QLatin1String("disabled"));
+        v = map.value(_("disabled"));
         if (v.isValid())
             data->enabled = !v.toInt();
-        v = map.value(QLatin1String("usefullpath"));
+        v = map.value(_("usefullpath"));
         if (v.isValid())
             data->useFullPath = bool(v.toInt());
+        v = map.value(_("type"));
+        if (v.isValid())
+            data->type = BreakpointData::Type(v.toInt());
         data->setMarkerFileName(data->fileName);
         data->setMarkerLineNumber(data->lineNumber.toInt());
         append(data);
@@ -476,6 +515,7 @@ void BreakHandler::resetBreakpoints()
         data->bpCorrectedLineNumber.clear();
         data->bpCondition.clear();
         data->bpIgnoreCount.clear();
+        data->bpThreadSpec.clear();
         data->bpAddress.clear();
         // Keep marker data if it was primary.
         if (data->markerFileName() != data->fileName)
@@ -502,7 +542,7 @@ QVariant BreakHandler::headerData(int section,
     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
         static QString headers[] = {
             tr("Number"),  tr("Function"), tr("File"), tr("Line"),
-            tr("Condition"), tr("Ignore"), tr("Address")
+            tr("Condition"), tr("Ignore"), tr("Threads"), tr("Address")
         };
         return headers[section];
     }
@@ -528,6 +568,8 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
             if (role == Qt::UserRole)
                 return data->enabled;
             if (role == Qt::DecorationRole) {
+                if (data->type == BreakpointData::WatchpointType)
+                    return m_watchpointIcon;
                 if (!data->enabled)
                     return m_disabledBreakpointIcon;
                 return data->pending ? m_pendingBreakPointIcon : m_breakpointIcon;
@@ -538,6 +580,8 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
                 const QString str = data->pending ? data->funcName : data->bpFuncName;
                 return str.isEmpty() ? empty : str;
             }
+            if (role == Qt::UserRole + 1)
+                return data->funcName;
             break;
         case 2:
             if (role == Qt::DisplayRole) {
@@ -553,6 +597,8 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
             }
             if (role == Qt::UserRole)
                 return data->useFullPath;
+            if (role == Qt::UserRole + 1)
+                return data->fileName;
             break;
         case 3:
             if (role == Qt::DisplayRole) {
@@ -562,21 +608,41 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
                 const QString str = data->pending ? data->lineNumber : data->bpLineNumber;
                 return str.isEmpty() ? empty : str;
             }
+            if (role == Qt::UserRole + 1)
+                return data->lineNumber;
             break;
         case 4:
             if (role == Qt::DisplayRole)
                 return data->pending ? data->condition : data->bpCondition;
             if (role == Qt::ToolTipRole)
                 return tr("Breakpoint will only be hit if this condition is met.");
+            if (role == Qt::UserRole + 1)
+                return data->condition;
             break;
         case 5:
             if (role == Qt::DisplayRole)
                 return data->pending ? data->ignoreCount : data->bpIgnoreCount;
             if (role == Qt::ToolTipRole)
                 return tr("Breakpoint will only be hit after being ignored so many times.");
+            if (role == Qt::UserRole + 1)
+                return data->ignoreCount;
         case 6:
-            if (role == Qt::DisplayRole)
+            if (role == Qt::DisplayRole) {
+                if (data->pending)
+                    return !data->threadSpec.isEmpty() ? data->threadSpec : tr("(all)");
+                else
+                    return !data->bpThreadSpec.isEmpty() ? data->bpThreadSpec : tr("(all)");
+            }
+            if (role == Qt::ToolTipRole)
+                return tr("Breakpoint will only be hit in the specified thread(s).");
+            if (role == Qt::UserRole + 1)
+                return data->threadSpec;
+        case 7:
+            if (role == Qt::DisplayRole) {
+                if (data->type == BreakpointData::WatchpointType)
+                    return data->address;
                 return data->bpAddress;
+            } 
             break;
     }
     if (role == Qt::ToolTipRole)
@@ -597,38 +663,73 @@ Qt::ItemFlags BreakHandler::flags(const QModelIndex &mi) const
 
 bool BreakHandler::setData(const QModelIndex &mi, const QVariant &value, int role)
 {
-    if (role != Qt::EditRole)
-        return false;
-
     BreakpointData *data = at(mi.row());
+
+    if (role == Qt::UserRole + 1) {
+        if (data->enabled != value.toBool()) {
+            toggleBreakpointEnabled(data);
+            layoutChanged();
+        }
+        return true;
+    }
+
+    if (role == Qt::UserRole + 2) {
+        if (data->useFullPath != value.toBool()) {
+            data->useFullPath = value.toBool();
+            layoutChanged();
+        }
+        return true;
+    }
+
+    //if (role != Qt::EditRole)
+    //    return false;
+
     switch (mi.column()) {
-        case 0: {
-            if (data->enabled != value.toBool()) {
-                toggleBreakpointEnabled(data);
-                dataChanged(mi, mi);
+        case 1: {
+            QString val = value.toString();
+            if (data->funcName != val) {
+                data->funcName = val;
+                layoutChanged();
             }
             return true;
         }
         case 2: {
-            if (data->useFullPath != value.toBool()) {
-                data->useFullPath = value.toBool();
-                dataChanged(mi, mi);
+            QString val = value.toString();
+            if (data->fileName != val) {
+                data->fileName = val;
+                layoutChanged();
+            }
+            return true;
+        }
+        case 3: {
+            QByteArray val = value.toString().toLatin1();
+            if (data->lineNumber != val) {
+                data->lineNumber = val;
+                layoutChanged();
             }
             return true;
         }
         case 4: {
-            QString val = value.toString();
+            QByteArray val = value.toString().toLatin1();
             if (val != data->condition) {
-                data->condition = val.toLatin1();
-                dataChanged(mi, mi);
+                data->condition = val;
+                layoutChanged();
             }
             return true;
         }
         case 5: {
-            QString val = value.toString();
+            QByteArray val = value.toString().toLatin1();
             if (val != data->ignoreCount) {
-                data->ignoreCount = val.toLatin1();
-                dataChanged(mi, mi);
+                data->ignoreCount = val;
+                layoutChanged();
+            }
+            return true;
+        }
+        case 6: {
+            QByteArray val = value.toString().toLatin1();
+            if (val != data->threadSpec) {
+                data->threadSpec = val;
+                layoutChanged();
             }
             return true;
         }
@@ -640,6 +741,7 @@ bool BreakHandler::setData(const QModelIndex &mi, const QVariant &value, int rol
 
 void BreakHandler::append(BreakpointData *data)
 {
+    data->m_handler = this;
     m_bp.append(data);
     m_inserted.append(data);
 }
@@ -692,6 +794,13 @@ void BreakHandler::removeBreakpoint(int index)
     saveBreakpoints();
 }
 
+void BreakHandler::removeBreakpoint(BreakpointData *data)
+{
+    removeBreakpointHelper(m_bp.indexOf(data));
+    emit layoutChanged();
+    saveBreakpoints();
+}
+
 void BreakHandler::toggleBreakpointEnabled(BreakpointData *data)
 {
     QTC_ASSERT(data, return);
@@ -757,7 +866,7 @@ void BreakHandler::breakByFunction(const QString &functionName)
                 && data->ignoreCount.isEmpty())
             return;
     }
-    BreakpointData *data = new BreakpointData(this);
+    BreakpointData *data = new BreakpointData;
     data->funcName = functionName;
     append(data);
     saveBreakpoints();
index c0aaadc..7c9297d 100644 (file)
 #ifndef DEBUGGER_BREAKHANDLER_H
 #define DEBUGGER_BREAKHANDLER_H
 
+#include "breakpoint.h"
+
 #include <QtCore/QObject>
 #include <QtCore/QAbstractTableModel>
 #include <QtGui/QIcon>
 
 namespace Debugger {
-class DebuggerManager;
 namespace Internal {
 
-class BreakpointMarker;
-class BreakHandler;
-
-//////////////////////////////////////////////////////////////////
-//
-// BreakpointData
-//
-//////////////////////////////////////////////////////////////////
-
-class BreakpointData
-{
-public:
-    explicit BreakpointData(BreakHandler *handler);
-    ~BreakpointData();
-
-    void removeMarker();
-    void updateMarker();
-    QString toToolTip() const;
-    QString toString() const;
-    BreakHandler *handler() { return m_handler; }
-
-    bool isLocatedAt(const QString &fileName, int lineNumber) const;
-    bool conditionsMatch() const;
-
-private:
-    // Intentionally unimplemented.
-    // Making it copyable is tricky because of the markers.
-    void operator=(const BreakpointData &);
-    BreakpointData(const BreakpointData &);
-
-    // Our owner
-    BreakHandler *m_handler; // Not owned.
-
-public:
-    bool enabled;            // Should we talk to the debugger engine?
-    bool pending;            // Does the debugger engine know about us already?
-
-    // This "user requested information" will get stored in the session.
-    QString fileName;        // Short name of source file.
-    QByteArray condition;    // Condition associated with breakpoint.
-    QByteArray ignoreCount;  // Ignore count associated with breakpoint.
-    QByteArray lineNumber;   // Line in source file.
-    QString funcName;        // Name of containing function.
-    bool useFullPath;        // Should we use the full path when setting the bp?
-
-    // This is what gdb produced in response.
-    QByteArray bpNumber;     // Breakpoint number assigned by the debugger engine.
-    QByteArray bpCondition;  // Condition acknowledged by the debugger engine.
-    QByteArray bpIgnoreCount;// Ignore count acknowledged by the debugger engine.
-    QString bpFileName;      // File name acknowledged by the debugger engine.
-    QString bpFullName;      // Full file name acknowledged by the debugger engine.
-    QByteArray bpLineNumber; // Line number acknowledged by the debugger engine.
-    QByteArray bpCorrectedLineNumber; // Acknowledged by the debugger engine.
-    QString bpFuncName;      // Function name acknowledged by the debugger engine.
-    QByteArray bpAddress;    // Address acknowledged by the debugger engine.
-    bool bpMultiple;         // Happens in constructors/gdb.
-    bool bpEnabled;          // Enable/disable command sent.
-
-    void setMarkerFileName(const QString &fileName);
-    QString markerFileName() const { return m_markerFileName; }
-
-    void setMarkerLineNumber(int lineNumber);
-    int markerLineNumber() const { return m_markerLineNumber; }
-
-private:
-    // Taken from either user input or gdb responses.
-    QString m_markerFileName; // Used to locate the marker.
-    int m_markerLineNumber;
-
-    // Our red blob in the editor.
-    BreakpointMarker *marker;
-};
-
-
 //////////////////////////////////////////////////////////////////
 //
 // BreakHandler
@@ -140,10 +67,11 @@ public:
     void removeAt(int index); // This also deletes the marker.
     void clear(); // This also deletes all the marker.
     int indexOf(BreakpointData *data) { return m_bp.indexOf(data); }
-    // If lineNumber < 0, interpret fileName as address.
-    int findBreakpoint(const QString &fileName, int lineNumber) const;
-    int findBreakpoint(const BreakpointData &data) const; // Returns index.
-    BreakpointData *findBreakpoint(int bpNumber) const;
+    // Find a breakpoint matching approximately the data in needle.bp*,
+    BreakpointData *findSimilarBreakpoint(const BreakpointData &needle) const;
+    BreakpointData *findBreakpointByNumber(int bpNumber) const;
+    int findWatchPointIndexByAddress(const QByteArray &a) const;
+    bool watchPointAt(quint64 address) const;
     void updateMarkers();
 
     QList<BreakpointData *> insertedBreakpoints() const;
@@ -161,6 +89,7 @@ public slots:
     void toggleBreakpointEnabled(BreakpointData *data);
     void breakByFunction(const QString &functionName);
     void removeBreakpoint(int index);
+    void removeBreakpoint(BreakpointData *data);
 
 private:
     friend class BreakpointMarker;
@@ -182,6 +111,7 @@ private:
     const QIcon m_breakpointIcon;
     const QIcon m_disabledBreakpointIcon;
     const QIcon m_pendingBreakPointIcon;
+    const QIcon m_watchpointIcon;
 
     DebuggerManager *m_manager; // Not owned.
     QList<BreakpointData *> m_bp;
diff --git a/src/plugins/debugger/breakpoint.h b/src/plugins/debugger/breakpoint.h
new file mode 100644 (file)
index 0000000..5a9eef7
--- /dev/null
@@ -0,0 +1,123 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DEBUGGER_BREAKPOINT_H
+#define DEBUGGER_BREAKPOINT_H
+
+#include <QtCore/QString>
+
+namespace Debugger {
+class DebuggerManager;
+namespace Internal {
+
+class BreakpointMarker;
+class BreakHandler;
+
+//////////////////////////////////////////////////////////////////
+//
+// BreakpointData
+//
+//////////////////////////////////////////////////////////////////
+
+class BreakpointData
+{
+public:
+    BreakpointData();
+    ~BreakpointData();
+
+    void removeMarker();
+    void updateMarker();
+    QString toToolTip() const;
+    QString toString() const;
+    BreakHandler *handler() { return m_handler; }
+
+    bool isLocatedAt(const QString &fileName, int lineNumber) const;
+    bool conditionsMatch() const;
+
+private:
+    // Intentionally unimplemented.
+    // Making it copyable is tricky because of the markers.
+    void operator=(const BreakpointData &);
+    BreakpointData(const BreakpointData &);
+
+    // Our owner
+    BreakHandler *m_handler; // Not owned.
+    friend class BreakHandler;
+
+public:
+    enum Type { BreakpointType, WatchpointType };
+
+    bool enabled;            // Should we talk to the debugger engine?
+    bool pending;            // Does the debugger engine know about us already?
+    Type type;               // Type of breakpoint.
+
+    // This "user requested information" will get stored in the session.
+    QString fileName;        // Short name of source file.
+    QByteArray condition;    // Condition associated with breakpoint.
+    QByteArray ignoreCount;  // Ignore count associated with breakpoint.
+    QByteArray lineNumber;   // Line in source file.
+    QByteArray address;      // Address for watchpoints.
+    QByteArray threadSpec;   // Thread specification.
+    QString funcName;        // Name of containing function.
+    bool useFullPath;        // Should we use the full path when setting the bp?
+
+    // This is what gdb produced in response.
+    QByteArray bpNumber;     // Breakpoint number assigned by the debugger engine.
+    QByteArray bpCondition;  // Condition acknowledged by the debugger engine.
+    QByteArray bpIgnoreCount;// Ignore count acknowledged by the debugger engine.
+    QString bpFileName;      // File name acknowledged by the debugger engine.
+    QString bpFullName;      // Full file name acknowledged by the debugger engine.
+    QByteArray bpLineNumber; // Line number acknowledged by the debugger engine.
+    QByteArray bpCorrectedLineNumber; // Acknowledged by the debugger engine.
+    QByteArray bpThreadSpec; // Thread spec acknowledged by the debugger engine.
+    QString bpFuncName;      // Function name acknowledged by the debugger engine.
+    QByteArray bpAddress;    // Address acknowledged by the debugger engine.
+    bool bpMultiple;         // Happens in constructors/gdb.
+    bool bpEnabled;          // Enable/disable command sent.
+
+    void setMarkerFileName(const QString &fileName);
+    QString markerFileName() const { return m_markerFileName; }
+
+    void setMarkerLineNumber(int lineNumber);
+    int markerLineNumber() const { return m_markerLineNumber; }
+
+private:
+    // Taken from either user input or gdb responses.
+    QString m_markerFileName; // Used to locate the marker.
+    int m_markerLineNumber;
+
+    // Our red blob in the editor.
+    BreakpointMarker *marker;
+};
+
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_BREAKPOINT_H
index 34ddcd5..b2174ba 100644 (file)
 
 #include "breakwindow.h"
 
+#include "breakhandler.h"
+#include "threadshandler.h"
 #include "debuggeractions.h"
 #include "debuggermanager.h"
+#include "stackhandler.h"
 #include "ui_breakcondition.h"
 #include "ui_breakbyfunction.h"
 
@@ -103,7 +106,7 @@ BreakWindow::BreakWindow(Debugger::DebuggerManager *manager)
 
 void BreakWindow::showAddressColumn(bool on)
 {
-    setColumnHidden(6, !on);
+    setColumnHidden(7, !on);
 }
 
 static QModelIndexList normalizeIndexes(const QModelIndexList &list)
@@ -133,6 +136,14 @@ void BreakWindow::resizeEvent(QResizeEvent *ev)
     QTreeView::resizeEvent(ev);
 }
 
+void BreakWindow::mouseDoubleClickEvent(QMouseEvent *ev)
+{
+    QModelIndex indexUnderMouse = indexAt(ev->pos());
+    if (indexUnderMouse.isValid() && indexUnderMouse.column() >= 4)
+        editBreakpoint(QModelIndexList() << indexUnderMouse);
+    QTreeView::mouseDoubleClickEvent(ev);
+}
+
 void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
 {
     QMenu menu;
@@ -185,9 +196,16 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
     alwaysAdjustAction->setCheckable(true);
     alwaysAdjustAction->setChecked(m_alwaysResizeColumnsToContents);
 
-    QAction *editConditionAction =
-        new QAction(tr("Edit Condition..."), &menu);
-    editConditionAction->setEnabled(si.size() > 0);
+    QAction *editBreakpointAction =
+        new QAction(tr("Edit Breakpoint..."), &menu);
+    editBreakpointAction->setEnabled(si.size() > 0);
+
+    int threadId = m_manager->threadsHandler()->currentThreadId();
+    QString associateTitle = threadId == -1
+        ?  tr("Associate Breakpoint With All Threads")
+        :  tr("Associate Breakpoint With Thread %1").arg(threadId);
+    QAction *associateBreakpointAction = new QAction(associateTitle, &menu);
+    associateBreakpointAction->setEnabled(si.size() > 0);
 
     QAction *synchronizeAction =
         new QAction(tr("Synchronize Breakpoints"), &menu);
@@ -223,7 +241,8 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
         new QAction(tr("Set Breakpoint at \"catch\""), this);
 
     menu.addAction(deleteAction);
-    menu.addAction(editConditionAction);
+    menu.addAction(editBreakpointAction);
+    menu.addAction(associateBreakpointAction);
     menu.addAction(toggleEnabledAction);
     menu.addAction(pathAction);
     menu.addSeparator();
@@ -261,8 +280,10 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
         resizeColumnsToContents();
     else if (act == alwaysAdjustAction)
         setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
-    else if (act == editConditionAction)
-        editConditions(si);
+    else if (act == editBreakpointAction)
+        editBreakpoint(si);
+    else if (act == associateBreakpointAction)
+        associateBreakpoint(si, threadId);
     else if (act == synchronizeAction)
         emit breakpointSynchronizationRequested();
     else if (act == toggleEnabledAction)
@@ -284,7 +305,7 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
 void BreakWindow::setBreakpointsEnabled(const QModelIndexList &list, bool enabled)
 {
     foreach (const QModelIndex &idx, list)
-        model()->setData(idx, enabled);
+        model()->setData(idx, enabled, Qt::UserRole + 1);
     emit breakpointSynchronizationRequested();
 }
 
@@ -292,7 +313,7 @@ void BreakWindow::setBreakpointsFullPath(const QModelIndexList &list, bool fullp
 {
     foreach (const QModelIndex &idx, list) {
         QModelIndex idx2 = idx.sibling(idx.row(), 2);
-        model()->setData(idx2, fullpath);
+        model()->setData(idx2, fullpath, Qt::UserRole + 2);
     }
     emit breakpointSynchronizationRequested();
 }
@@ -318,9 +339,10 @@ void BreakWindow::deleteBreakpoints(QList<int> list)
     const int row = qMin(firstRow, model()->rowCount() - 1);
     if (row >= 0)
         setCurrentIndex(model()->index(row, 0));
+    emit breakpointSynchronizationRequested();
 }
 
-void BreakWindow::editConditions(const QModelIndexList &list)
+void BreakWindow::editBreakpoint(const QModelIndexList &list)
 {
     QDialog dlg(this);
     Ui::BreakCondition ui;
@@ -330,19 +352,51 @@ void BreakWindow::editConditions(const QModelIndexList &list)
     QModelIndex idx = list.front();
     int row = idx.row();
     dlg.setWindowTitle(tr("Conditions on Breakpoint %1").arg(row));
-    ui.lineEditCondition->setText(model()->data(idx.sibling(row, 4)).toString());
-    ui.spinBoxIgnoreCount->setValue(model()->data(idx.sibling(row, 5)).toInt());
+    int role = Qt::UserRole + 1;
+    ui.lineEditFunction->hide();
+    ui.labelFunction->hide();
+    ui.lineEditFileName->hide();
+    ui.labelFileName->hide();
+    ui.lineEditLineNumber->hide();
+    ui.labelLineNumber->hide();
+    QAbstractItemModel *m = model();
+    //ui.lineEditFunction->setText(
+    //    m->data(idx.sibling(row, 1), role).toString());
+    //ui.lineEditFileName->setText(
+    //    m->data(idx.sibling(row, 2), role).toString());
+    //ui.lineEditLineNumber->setText(
+    //    m->data(idx.sibling(row, 3), role).toString());
+    ui.lineEditCondition->setText(
+        m->data(idx.sibling(row, 4), role).toString());
+    ui.lineEditIgnoreCount->setText(
+        m->data(idx.sibling(row, 5), role).toString());
+    ui.lineEditThreadSpec->setText(
+        m->data(idx.sibling(row, 6), role).toString());
 
     if (dlg.exec() == QDialog::Rejected)
         return;
 
     foreach (const QModelIndex &idx, list) {
-        model()->setData(idx.sibling(idx.row(), 4), ui.lineEditCondition->text());
-        model()->setData(idx.sibling(idx.row(), 5), ui.spinBoxIgnoreCount->value());
+        //m->setData(idx.sibling(idx.row(), 1), ui.lineEditFunction->text());
+        //m->setData(idx.sibling(idx.row(), 2), ui.lineEditFileName->text());
+        //m->setData(idx.sibling(idx.row(), 3), ui.lineEditLineNumber->text());
+        m->setData(idx.sibling(idx.row(), 4), ui.lineEditCondition->text());
+        m->setData(idx.sibling(idx.row(), 5), ui.lineEditIgnoreCount->text());
+        m->setData(idx.sibling(idx.row(), 6), ui.lineEditThreadSpec->text());
     }
     emit breakpointSynchronizationRequested();
 }
 
+void BreakWindow::associateBreakpoint(const QModelIndexList &list, int threadId)
+{
+    QString str;
+    if (threadId != -1)
+        str = QString::number(threadId);
+    foreach (const QModelIndex &idx, list)
+        model()->setData(idx.sibling(idx.row(), 6), str);
+    emit breakpointSynchronizationRequested();
+}
+
 void BreakWindow::resizeColumnsToContents()
 {
     for (int i = model()->columnCount(); --i >= 0; )
index 3429d7a..b3828ca 100644 (file)
@@ -1,4 +1,5 @@
 /**************************************************************************
+QT_END_NAMESPACE
 **
 ** This file is part of Qt Creator
 **
@@ -65,11 +66,13 @@ protected:
     void resizeEvent(QResizeEvent *ev);
     void contextMenuEvent(QContextMenuEvent *ev);
     void keyPressEvent(QKeyEvent *ev);
+    void mouseDoubleClickEvent(QMouseEvent *ev);
 
 private:
     void deleteBreakpoints(const QModelIndexList &list);
     void deleteBreakpoints(QList<int> rows);
-    void editConditions(const QModelIndexList &list);
+    void editBreakpoint(const QModelIndexList &list);
+    void associateBreakpoint(const QModelIndexList &list, int thread);
     void setBreakpointsEnabled(const QModelIndexList &list, bool enabled);
     void setBreakpointsFullPath(const QModelIndexList &list, bool fullpath);
 
index 469d39e..13aacaf 100644 (file)
@@ -50,48 +50,21 @@ namespace CdbCore {
 static const char sourceFileQuoteC = '`';
 
 BreakPoint::BreakPoint() :
+    type(Code),
     lineNumber(-1),
     address(0),
+    threadId(-1),
     ignoreCount(0),
     oneShot(false),
     enabled(true)
 {
 }
 
-int BreakPoint::compare(const BreakPoint& rhs) const
-{
-    if (lineNumber > rhs.lineNumber)
-        return 1;
-    if (lineNumber < rhs.lineNumber)
-        return -1;
-    if (address > rhs.address)
-        return 1;
-    if (address < rhs.address)
-        return -1;
-    if (ignoreCount > rhs.ignoreCount)
-        return 1;
-    if (ignoreCount < rhs.ignoreCount)
-        return -1;
-    if (oneShot && !rhs.oneShot)
-        return 1;
-    if (!oneShot && rhs.oneShot)
-        return -1;
-    if (enabled && !rhs.enabled)
-        return 1;
-    if (!enabled && rhs.enabled)
-        return -1;
-    if (const int fileCmp = fileName.compare(rhs.fileName))
-        return fileCmp;
-    if (const int  funcCmp = funcName.compare(rhs.funcName))
-        return funcCmp;
-    if (const int condCmp = condition.compare(rhs.condition))
-        return condCmp;
-    return 0;
-}
-
 void BreakPoint::clear()
 {
+     type = Code;
      ignoreCount = 0;
+     threadId = -1;
      oneShot = false;
      enabled = true;
      clearExpressionData();
@@ -108,23 +81,35 @@ void BreakPoint::clearExpressionData()
 
 QDebug operator<<(QDebug dbg, const BreakPoint &bp)
 {
-    QDebug nsp = dbg.nospace();
-    if (bp.address)
-        nsp << "0x" << QString::number(bp.address, 16) << ' ';
-    if (!bp.fileName.isEmpty()) {
-        nsp << "fileName='" << bp.fileName << ':' << bp.lineNumber << '\'';
+    dbg.nospace() << bp.toString();
+    return dbg;
+}
+
+QString BreakPoint::toString() const
+{
+    QString rc;
+    QTextStream str(&rc);
+    str << (type == BreakPoint::Code ?  "Code " : "Data ");
+    if (address) {
+        str.setIntegerBase(16);
+        str << "0x" << address << ' ';
+        str.setIntegerBase(10);
+    }
+    if (!fileName.isEmpty()) {
+        str << "fileName='" << fileName << ':' << lineNumber << '\'';
     } else {
-        nsp << "funcName='" << bp.funcName << '\'';
+        str << "funcName='" << funcName << '\'';
     }
-    if (!bp.condition.isEmpty())
-        nsp << " condition='" << bp.condition << '\'';
-    if (bp.ignoreCount)
-        nsp << " ignoreCount=" << bp.ignoreCount;
-    if (bp.enabled)
-        nsp << " enabled";
-    if (bp.oneShot)
-        nsp << " oneShot";
-    return dbg;
+    if (threadId >= 0)
+        str << " thread=" << threadId;
+    if (!condition.isEmpty())
+        str << " condition='" << condition << '\'';
+    if (ignoreCount)
+        str << " ignoreCount=" << ignoreCount;
+    str << (enabled ? " enabled" : " disabled");
+    if (oneShot)
+        str << " oneShot";
+    return rc;
 }
 
 QString BreakPoint::expression() const
@@ -155,25 +140,59 @@ QString BreakPoint::expression() const
     return rc;
 }
 
+static inline QString msgCannotSetBreakpoint(const QString &exp, const QString &why)
+{
+    return QString::fromLatin1("Unable to set breakpoint '%1' : %2").arg(exp, why);
+}
+
 bool BreakPoint::apply(CIDebugBreakpoint *ibp, QString *errorMessage) const
 {
     const QString expr = expression();
     if (debugBP)
         qDebug() << Q_FUNC_INFO << *this << expr;
-    const HRESULT hr = ibp->SetOffsetExpressionWide(reinterpret_cast<PCWSTR>(expr.utf16()));
+    HRESULT hr = ibp->SetOffsetExpressionWide(reinterpret_cast<PCWSTR>(expr.utf16()));
     if (FAILED(hr)) {
-        *errorMessage = QString::fromLatin1("Unable to set breakpoint '%1' : %2").
-                        arg(expr, CdbCore::msgComFailed("SetOffsetExpressionWide", hr));
+        *errorMessage = msgCannotSetBreakpoint(expr, CdbCore::msgComFailed("SetOffsetExpressionWide", hr));
         return false;
     }
     // Pass Count is ignoreCount + 1
-    ibp->SetPassCount(ignoreCount + 1u);
+    hr = ibp->SetPassCount(ignoreCount + 1u);
+    if (FAILED(hr))
+        qWarning("Error setting passcount %d %s ", ignoreCount, qPrintable(expr));
+    // Set up size for data breakpoints
+    if (type == Data) {
+        const ULONG size = 1u;
+        hr = ibp->SetDataParameters(size, DEBUG_BREAK_READ | DEBUG_BREAK_WRITE);
+        if (FAILED(hr)) {
+            const QString msg = QString::fromLatin1("Cannot set watch size to %1: %2").
+                                arg(size).arg(CdbCore::msgComFailed("SetDataParameters", hr));
+            *errorMessage = msgCannotSetBreakpoint(expr, msg);
+            return false;
+        }
+    }
+    // Thread
+    if (threadId >= 0) {
+        hr = ibp->SetMatchThreadId(threadId);
+        if (FAILED(hr)) {
+            const QString msg = QString::fromLatin1("Cannot set thread id to %1: %2").
+                                arg(threadId).arg(CdbCore::msgComFailed("SetMatchThreadId", hr));
+            *errorMessage = msgCannotSetBreakpoint(expr, msg);
+            return false;
+        }
+    }
+    // Flags
     ULONG flags = 0;
     if (enabled)
         flags |= DEBUG_BREAKPOINT_ENABLED;
     if (oneShot)
         flags |= DEBUG_BREAKPOINT_ONE_SHOT;
-    ibp->AddFlags(flags);
+    hr = ibp->AddFlags(flags);
+    if (FAILED(hr)) {
+        const QString msg = QString::fromLatin1("Cannot set flags to 0x%1: %2").
+                            arg(flags, 0 ,16).arg(CdbCore::msgComFailed("AddFlags", hr));
+        *errorMessage = msgCannotSetBreakpoint(expr, msg);
+        return false;
+    }
     return true;
 }
 
@@ -192,7 +211,8 @@ bool BreakPoint::add(CIDebugControl* debugControl,
         *address = 0;
     if (id)
         *id = 0;
-    HRESULT hr = debugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &ibp);
+    const ULONG iType = type == Code ? DEBUG_BREAKPOINT_CODE : DEBUG_BREAKPOINT_DATA;
+    HRESULT hr = debugControl->AddBreakpoint2(iType, DEBUG_ANY_ID, &ibp);
     if (FAILED(hr)) {
         *errorMessage = msgCannotAddBreakPoint(CdbCore::msgComFailed("AddBreakpoint2", hr));
         return false;
@@ -321,16 +341,41 @@ void BreakPoint::clearNormalizeFileNameCache()
     normalizedFileNameCache()->clear();
 }
 
+static inline QString msgCannotRetrieveBreakpoint(const QString &why)
+{
+    return QString::fromLatin1("Cannot retrieve breakpoint: %1").arg(why);
+}
+
+static inline int threadIdOfBreakpoint(CIDebugBreakpoint *ibp)
+{
+    // Thread: E_NOINTERFACE indicates no thread has been set.
+    int threadId = -1;
+    ULONG iThreadId;
+    if (S_OK == ibp->GetMatchThreadId(&iThreadId))
+        threadId = iThreadId;
+    return threadId;
+}
+
 bool BreakPoint::retrieve(CIDebugBreakpoint *ibp, QString *errorMessage)
 {
     clear();
+    // Get type
+    ULONG iType;
+    ULONG processorType;
+    HRESULT hr = ibp->GetType(&iType, &processorType);
+    if (FAILED(hr)) {
+        *errorMessage = msgCannotRetrieveBreakpoint(CdbCore::msgComFailed("GetType", hr));
+        return false;
+    }
+    type = iType == DEBUG_BREAKPOINT_CODE ? Code : Data;
+    // Get & parse expression
     WCHAR wszBuf[MAX_PATH];
-    const HRESULT hr =ibp->GetOffsetExpressionWide(wszBuf, MAX_PATH, 0);
+    hr =ibp->GetOffsetExpressionWide(wszBuf, MAX_PATH, 0);
     if (FAILED(hr)) {
-        *errorMessage = QString::fromLatin1("Cannot retrieve breakpoint: %1").
-                        arg(CdbCore::msgComFailed("GetOffsetExpressionWide", hr));
+        *errorMessage = msgCannotRetrieveBreakpoint(CdbCore::msgComFailed("GetOffsetExpressionWide", hr));
         return false;
     }
+    threadId = threadIdOfBreakpoint(ibp);
     // Pass Count is ignoreCount + 1
     ibp->GetPassCount(&ignoreCount);
     if (ignoreCount)
@@ -523,4 +568,34 @@ bool BreakPoint::setBreakPointEnabledById(CIDebugControl *ctl, unsigned long id,
     return true;
 }
 
+// Change thread-id of a breakpoint
+static inline QString msgCannotSetBreakPointThread(unsigned long id, int tid, const QString &why)
+{
+    return QString::fromLatin1("Cannot set breakpoint %1 thread to %2: %3").arg(id).arg(tid).arg(why);
+}
+
+bool BreakPoint::setBreakPointThreadById(CIDebugControl *ctl, unsigned long id, int threadId, QString *errorMessage)
+{
+    if (debugBP)
+        qDebug() << Q_FUNC_INFO << id << threadId;
+    CIDebugBreakpoint *ibp = breakPointById(ctl, id, errorMessage);
+    if (!ibp) {
+        *errorMessage = msgCannotSetBreakPointThread(id, threadId, *errorMessage);
+        return false;
+    }
+    // Compare thread ids
+    const int oldThreadId = threadIdOfBreakpoint(ibp);
+    if (oldThreadId == threadId)
+        return true;
+    const ULONG newIThreadId = threadId == -1 ? DEBUG_ANY_ID : static_cast<ULONG>(threadId);
+    if (debugBP)
+        qDebug() << "Changing thread id of " << id << " from " << oldThreadId << " to " << threadId
+                << '(' << newIThreadId << ')';
+    const HRESULT hr = ibp->SetMatchThreadId(newIThreadId);
+    if (FAILED(hr)) {
+        *errorMessage = msgCannotSetBreakPointThread(id, threadId, *errorMessage);
+        return false;
+    }
+    return true;
 }
+} // namespace CdbCore
index 94d3b52..515243c 100644 (file)
@@ -49,18 +49,21 @@ namespace CdbCore {
 
 struct BreakPoint
 {
-    BreakPoint();
+    enum Type { Code, // Stop in code.
+                Data  // Stop when accessing address.
+              };
 
-    int compare(const BreakPoint& rhs) const;
+    BreakPoint();
 
     void clear();
     void clearExpressionData();
 
     QString expression() const;
 
-    // Apply parameters
+    // Apply parameters (with the exception of type, which is
+    // passed as a parameter to IDebugControl within add().
     bool apply(IDebugBreakpoint2 *ibp, QString *errorMessage) const;
-    // Convenience to add to a IDebugControl4
+    // Convenience to add to a IDebugControl4.
     bool add(CIDebugControl* debugControl,
              QString *errorMessage,
              unsigned long *id = 0,
@@ -76,16 +79,20 @@ struct BreakPoint
     static IDebugBreakpoint2 *breakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage);
     static bool removeBreakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage);
     static bool setBreakPointEnabledById(CIDebugControl *ctl, unsigned long id, bool enabled, QString *errorMessage);
+    static bool setBreakPointThreadById(CIDebugControl *ctl, unsigned long id, int threadId, QString *errorMessage);
 
     // Return a 'canonical' file (using '/' and capitalized drive letter)
     static QString normalizeFileName(const QString &f);
     static void clearNormalizeFileNameCache();
+    QString toString() const;
 
+    Type type;
     QString fileName;       // short name of source file
     int lineNumber;     // line in source file
     QString funcName;       // name of containing function
     quint64 address;
 
+    int threadId;
     QString condition;      // condition associated with breakpoint
     unsigned long ignoreCount;    // ignore count associated with breakpoint
     bool oneShot;
@@ -94,10 +101,6 @@ struct BreakPoint
 
 QDebug operator<<(QDebug, const BreakPoint &bp);
 
-inline bool operator==(const BreakPoint& b1, const BreakPoint& b2)
-    { return b1.compare(b2) == 0; }
-inline bool operator!=(const BreakPoint& b1, const BreakPoint& b2)
-    { return b1.compare(b2) != 0; }
-}
+} // namespace CdbCore
 
 #endif // CDBCOREBREAKPOINTS_H
index 79e7012..6c4898e 100644 (file)
@@ -37,6 +37,37 @@ namespace Internal {
 
 enum { debugBP = 0 };
 
+// Convert breakpoint structs
+CdbCore::BreakPoint breakPointFromBreakPointData(const Debugger::Internal::BreakpointData &bpd)
+{
+    CdbCore::BreakPoint rc;
+    rc.type = bpd.type == Debugger::Internal::BreakpointData::BreakpointType ?
+              CdbCore::BreakPoint::Code : CdbCore::BreakPoint::Data;
+
+    if (rc.type == CdbCore::BreakPoint::Data) {
+        QByteArray addressBA = bpd.address;
+        if (addressBA.startsWith("0x"))
+            addressBA.remove(0, 2);
+        bool ok;
+        rc.address = addressBA.toULongLong(&ok, 16);
+        if (!ok)
+            qWarning("Cdb: Cannot convert watchpoint address '%s'", bpd.address.constData());
+    }
+    if (!bpd.threadSpec.isEmpty()) {
+        bool ok;
+        rc.threadId = bpd.threadSpec.toInt(&ok);
+        if (!ok)
+            qWarning("Cdb: Cannot convert breakpoint thread specification '%s'", bpd.address.constData());
+    }
+    rc.fileName = QDir::toNativeSeparators(bpd.fileName);
+    rc.condition = bpd.condition;
+    rc.funcName = bpd.funcName;
+    rc.ignoreCount = bpd.ignoreCount.isEmpty() ? 0  : bpd.ignoreCount.toInt();
+    rc.lineNumber  = bpd.lineNumber.isEmpty()  ? -1 : bpd.lineNumber.toInt();
+    rc.oneShot = false;
+    rc.enabled = bpd.enabled;
+    return rc;
+}
 
 static inline QString msgCannotSetBreakAtFunction(const QString &func, const QString &why)
 {
@@ -93,7 +124,7 @@ bool synchronizeBreakPoints(CIDebugControl* debugControl,
             breakPointOk = ncdbbp.add(debugControl, &warning, &id, &address);
             if (breakPointOk) {
                 if (debugBP)
-                    qDebug() << "Added " << id << " at " << address << ncdbbp;
+                    qDebug("Added %lu at 0x%lx %s", id, address, qPrintable(ncdbbp.toString()));
                 handler->takeInsertedBreakPoint(nbd);
                 updateMarkers = true;
                 nbd->pending = false;
@@ -102,6 +133,7 @@ bool synchronizeBreakPoints(CIDebugControl* debugControl,
                 // Take over rest as is
                 nbd->bpCondition = nbd->condition;
                 nbd->bpIgnoreCount = nbd->ignoreCount;
+                nbd->bpThreadSpec = nbd->threadSpec;
                 nbd->bpFileName = nbd->fileName;
                 nbd->bpLineNumber = nbd->lineNumber;
                 nbd->bpFuncName = nbd->funcName;
@@ -122,6 +154,18 @@ bool synchronizeBreakPoints(CIDebugControl* debugControl,
     foreach (BreakpointData *dbd, handler->takeDisabledBreakpoints())
         if (!CdbCore::BreakPoint::setBreakPointEnabledById(debugControl, dbd->bpNumber.toUInt(), false, &warning))
             warnings->push_back(warning);
+    // Check for modified thread ids.
+    for (int i = handler->size() - 1; i >= 0; i--) {
+        BreakpointData *bpd = handler->at(i);
+        if (bpd->threadSpec != bpd->bpThreadSpec) {
+            const int newThreadSpec = bpd->threadSpec.isEmpty() ? -1 : bpd->threadSpec.toInt();
+            if (CdbCore::BreakPoint::setBreakPointThreadById(debugControl, bpd->bpNumber.toUInt(), newThreadSpec, errorMessage)) {
+                bpd->bpThreadSpec = bpd->threadSpec;
+            } else {
+                qWarning("%s", qPrintable(*errorMessage));
+            }
+        }
+    }
 
     if (updateMarkers)
         handler->updateMarkers();
@@ -129,7 +173,11 @@ bool synchronizeBreakPoints(CIDebugControl* debugControl,
     if (debugBP > 1) {
         QList<CdbCore::BreakPoint> bps;
         CdbCore::BreakPoint::getBreakPoints(debugControl, &bps, errorMessage);
-        qDebug().nospace() << "### Breakpoints in engine: " << bps;
+        QDebug nsp = qDebug().nospace();
+        const int count = bps.size();
+        nsp <<"### Breakpoints in engine: " << count << '\n';
+        for (int i = 0; i < count; i++)
+            nsp << "  #" << i << ' ' << bps.at(i) << '\n';
     }
     return true;
 }
index ecee377..3079ac6 100644 (file)
@@ -42,23 +42,12 @@ QT_BEGIN_NAMESPACE
 class QDebug;
 QT_END_NAMESPACE
 
-// Convert breakpoint structs
-inline CdbCore::BreakPoint breakPointFromBreakPointData(const Debugger::Internal::BreakpointData &bpd)
-{
-    CdbCore::BreakPoint rc;
-    rc.fileName = QDir::toNativeSeparators(bpd.fileName);
-    rc.condition = bpd.condition;
-    rc.funcName = bpd.funcName;
-    rc.ignoreCount = bpd.ignoreCount.isEmpty() ? 0  : bpd.ignoreCount.toInt();
-    rc.lineNumber  = bpd.lineNumber.isEmpty()  ? -1 : bpd.lineNumber.toInt();
-    rc.oneShot = false;
-    rc.enabled = bpd.enabled;
-    return rc;
-}
-
 namespace Debugger {
 namespace Internal {
 
+// Convert breakpoint structs
+CdbCore::BreakPoint breakPointFromBreakPointData(const Debugger::Internal::BreakpointData &bpd);
+
 // Synchronize (halted) engine with BreakHandler.
 bool synchronizeBreakPoints(CIDebugControl* ctl, CIDebugSymbols *syms,
                             BreakHandler *bh,
index 30b8514..8f71847 100644 (file)
@@ -39,6 +39,7 @@
 #include "cdboptionspage.h"
 #include "cdboptions.h"
 #include "cdbexceptionutils.h"
+#include "cdbsymbolpathlisteditor.h"
 #include "debuggeragents.h"
 #include "debuggeruiswitcher.h"
 #include "debuggermainwindow.h"
@@ -48,6 +49,7 @@
 #include "breakhandler.h"
 #include "stackhandler.h"
 #include "watchhandler.h"
+#include "threadshandler.h"
 #include "registerhandler.h"
 #include "moduleshandler.h"
 #include "watchutils.h"
@@ -59,6 +61,7 @@
 #include <utils/fancymainwindow.h>
 #include <texteditor/itexteditor.h>
 #include <utils/savedaction.h>
+#include <utils/checkablemessagebox.h>
 
 #include <QtCore/QDebug>
 #include <QtCore/QTimer>
@@ -347,11 +350,48 @@ void CdbDebugEnginePrivate::checkVersion()
     }
 }
 
+void CdbDebugEngine::startupChecks()
+{
+    // Check symbol server unless the user has an external/internal setup
+    if (!qgetenv("_NT_SYMBOL_PATH").isEmpty()
+        || CdbOptions::indexOfSymbolServerPath(m_d->m_options->symbolPaths) != -1)
+        return;
+    // Prompt to use Symbol server unless the user checked "No nagging".
+    Core::ICore *core = Core::ICore::instance();
+    const QString nagSymbolServerKey = CdbOptions::settingsGroup() + QLatin1String("/NoPromptSymbolServer");
+    bool noFurtherNagging = core->settings()->value(nagSymbolServerKey, false).toBool();
+    if (noFurtherNagging)
+        return;
+
+    const QString symServUrl = QLatin1String("http://support.microsoft.com/kb/311503");
+    const QString msg = tr("<html><head/><body><p>The debugger is not configured to use the public "
+                           "<a href=\"%1\">Microsoft Symbol Server</a>. This is recommended "
+                           "for retrieval of the symbols of the operating system libraries.</p>"
+                           "<p><i>Note:</i> A fast internet connection is required for this to work smoothly. Also, a delay "
+                           "might occur when connecting for the first time.</p>"
+                           "<p>Would you like to set it up?</p></br>"
+                           "</body></html>").arg(symServUrl);
+    const QDialogButtonBox::StandardButton answer =
+            Utils::CheckableMessageBox::question(core->mainWindow(), tr("Symbol Server"), msg,
+                                                 tr("Do not ask again"), &noFurtherNagging);
+    core->settings()->setValue(nagSymbolServerKey, noFurtherNagging);
+    if (answer == QDialogButtonBox::No)
+        return;
+    // Prompt for path and add it. Synchronize QSetting and debugger.
+    const QString cacheDir = CdbSymbolPathListEditor::promptCacheDirectory(core->mainWindow());
+    if (cacheDir.isEmpty())
+        return;
+    m_d->m_options->symbolPaths.push_back(CdbOptions::symbolServerPath(cacheDir));
+    m_d->m_options->toSettings(core->settings());
+    syncDebuggerPaths();
+}
+
 void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp)
 {
     if (debugCDBExecution)
         qDebug() << "startDebugger" << *sp;
     CdbCore::BreakPoint::clearNormalizeFileNameCache();
+    startupChecks();
     setState(AdapterStarting, Q_FUNC_INFO, __LINE__);
     m_d->checkVersion();
     if (m_d->m_hDebuggeeProcess) {
@@ -362,7 +402,7 @@ void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters>
     }
     switch (sp->startMode) {
     case AttachCore:
-    case StartRemote:
+    case AttachToRemote:
         warning(QLatin1String("Internal error: Mode not supported."));
         setState(AdapterStartFailed, Q_FUNC_INFO, __LINE__);
         emit startFailed();
@@ -374,7 +414,10 @@ void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters>
     m_d->clearDisplay();
     m_d->m_inferiorStartupComplete = false;
     setState(AdapterStarted, Q_FUNC_INFO, __LINE__);
-
+    // Options
+    QString errorMessage;
+    if (!m_d->setBreakOnThrow(theDebuggerBoolSetting(BreakOnThrow), &errorMessage))
+      manager()->showDebuggerOutput(LogWarning, errorMessage);
     m_d->setVerboseSymbolLoading(m_d->m_options->verboseSymbolLoading);
     // Figure out dumper. @TODO: same in gdb...
     const QString dumperLibName = QDir::toNativeSeparators(manager()->qtDumperLibraryName());
@@ -396,7 +439,6 @@ void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters>
     setState(InferiorStarting, Q_FUNC_INFO, __LINE__);
     manager()->showStatusMessage("Starting Debugger", messageTimeOut);
 
-    QString errorMessage;
     bool rc = false;
     bool needWatchTimer = false;
     m_d->clearForRun();
@@ -415,7 +457,7 @@ void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters>
             m_d->m_ignoreInitialBreakPoint = true;
             // Launch console stub and wait for its startup
             m_d->m_consoleStubProc.stop(); // We leave the console open, so recycle it now.
-            m_d->m_consoleStubProc.setWorkingDirectory(sp->workingDir);
+            m_d->m_consoleStubProc.setWorkingDirectory(sp->workingDirectory);
             m_d->m_consoleStubProc.setEnvironment(sp->environment);
             rc = m_d->m_consoleStubProc.start(sp->executable, sp->processArgs);
             if (!rc)
@@ -423,7 +465,7 @@ void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters>
             // continues in slotConsoleStubStarted()...
         } else {
             needWatchTimer = true;
-            rc = m_d->startDebuggerWithExecutable(sp->workingDir,
+            rc = m_d->startDebuggerWithExecutable(sp->workingDirectory,
                                                   sp->executable,
                                                   sp->processArgs,
                                                   sp->environment,
@@ -1183,7 +1225,7 @@ void CdbDebugEngine::loadAllSymbols()
         qDebug() << Q_FUNC_INFO;
 }
 
-QList<Symbol> CdbDebugEngine::moduleSymbols(const QString &moduleName)
+void CdbDebugEngine::requestModuleSymbols(const QString &moduleName)
 {
     QList<Symbol> rc;
     QString errorMessage;
@@ -1199,7 +1241,7 @@ QList<Symbol> CdbDebugEngine::moduleSymbols(const QString &moduleName)
     } while (false);
     if (!success)
         warning(errorMessage);
-    return rc;
+    manager()->showModuleSymbols(moduleName, rc);
 }
 
 void CdbDebugEngine::reloadRegisters()
@@ -1553,7 +1595,9 @@ void CdbDebugEnginePrivate::handleBreakpointEvent(PDEBUG_BREAKPOINT2 pBP)
         expression.clear();
     }
     if (!expression.isEmpty())
-        m_stoppedMessage = CdbDebugEngine::tr("Breakpoint: %1").arg(expression);
+        m_stoppedMessage = breakpoint.type == CdbCore::BreakPoint::Code ?
+                           CdbDebugEngine::tr("Breakpoint: %1").arg(expression) :
+                           CdbDebugEngine::tr("Watchpoint: %1").arg(expression);
 }
 
 void CdbDebugEngine::reloadSourceFiles()
@@ -1574,7 +1618,9 @@ void CdbDebugEngine::syncDebuggerPaths()
 
 unsigned CdbDebugEngine::debuggerCapabilities() const
 {
-    return DisassemblerCapability | RegisterCapability | ShowMemoryCapability;
+    return DisassemblerCapability | RegisterCapability | ShowMemoryCapability
+           |WatchpointCapability
+           |BreakOnThrowAndCatchCapability; // Sort-of: Can break on throw().
 }
 
 // Accessed by DebuggerManager
index e15d5e9..16d928a 100644 (file)
@@ -95,7 +95,7 @@ public:
     virtual void reloadModules();
     virtual void loadSymbols(const QString &moduleName);
     virtual void loadAllSymbols();
-    virtual QList<Symbol> moduleSymbols(const QString &moduleName);
+    virtual void requestModuleSymbols(const QString &moduleName);
 
     virtual void reloadRegisters();
     virtual void reloadSourceFiles();
@@ -112,6 +112,7 @@ private slots:
     void warning(const QString &w);
 
 private:
+    void startupChecks();
     void setState(DebuggerState state, const char *func, int line);
     inline bool startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage);
     void processTerminated(unsigned long exitCode);
index fda335b..0c3e00b 100644 (file)
@@ -50,6 +50,11 @@ CdbOptions::CdbOptions() :
 {
 }
 
+QString CdbOptions::settingsGroup()
+{
+    return QLatin1String(settingsGroupC);
+}
+
 void CdbOptions::clear()
 {
     enabled = false;
@@ -99,5 +104,37 @@ unsigned CdbOptions::compare(const CdbOptions &rhs) const
     return rc;
 }
 
+static const char symbolServerPrefixC[] = "symsrv*symsrv.dll*";
+static const char symbolServerPostfixC[] = "*http://msdl.microsoft.com/download/symbols";
+
+QString CdbOptions::symbolServerPath(const QString &cacheDir)
+{
+    QString s = QLatin1String(symbolServerPrefixC);
+    s +=  QDir::toNativeSeparators(cacheDir);
+    s += QLatin1String(symbolServerPostfixC);
+    return s;
+}
+
+bool CdbOptions::isSymbolServerPath(const QString &path, QString *cacheDir /*  = 0 */)
+{
+    // Split apart symbol server post/prefixes
+    if (!path.startsWith(QLatin1String(symbolServerPrefixC)) || !path.endsWith(QLatin1String(symbolServerPostfixC)))
+        return false;
+    if (cacheDir) {
+        const unsigned prefixLength = qstrlen(symbolServerPrefixC);
+        *cacheDir = path.mid(prefixLength, path.size() - prefixLength - qstrlen(symbolServerPostfixC));
+    }
+    return true;
+}
+
+int CdbOptions::indexOfSymbolServerPath(const QStringList &paths, QString *cacheDir /*  = 0 */)
+{
+    const int count = paths.size();
+    for (int i = 0; i < count; i++)
+        if (CdbOptions::isSymbolServerPath(paths.at(i), cacheDir))
+            return i;
+    return -1;
+}
+
 } // namespace Internal
 } // namespace Debugger
index cb7bd07..97f08d1 100644 (file)
@@ -54,6 +54,14 @@ public:
                        SymbolOptionsChanged = 0x4 };
     unsigned compare(const CdbOptions &s) const;
 
+    // Format a symbol server specification with a cache directory
+    static QString symbolServerPath(const QString &cacheDir);
+    // Check whether the path is a symbol server specification and return the cache directory
+    static bool isSymbolServerPath(const QString &symbolPath, QString *cacheDir = 0);
+    static int indexOfSymbolServerPath(const QStringList &symbolPaths, QString *cacheDir = 0);
+
+    static QString settingsGroup();
+
     bool enabled;
     QString path;
     QStringList symbolPaths;
index 94ae7df..23a5543 100644 (file)
@@ -33,6 +33,7 @@
 #include "cdbdebugengine_p.h"
 #include "debuggeractions.h"
 #include "watchutils.h"
+#include "threadshandler.h"
 
 #include <utils/savedaction.h>
 
@@ -129,10 +130,10 @@ bool CdbStackTraceContext::getThreads(const CdbCore::ComInterfaces &cif,
         const CdbCore::StackFrame &coreFrame = it.value();
         data.address = coreFrame.address;
         data.function = coreFrame.function;
-        data.line = coreFrame.line;
+        data.lineNumber = coreFrame.line;
         // Basename only for brevity
         const int slashPos = coreFrame.fileName.lastIndexOf(slash);
-        data.file = slashPos == -1 ? coreFrame.fileName : coreFrame.fileName.mid(slashPos + 1);
+        data.fileName = slashPos == -1 ? coreFrame.fileName : coreFrame.fileName.mid(slashPos + 1);
         threads->push_back(data);
     }
     return true;
index 4bd5e2c..a3fc689 100644 (file)
 **************************************************************************/
 
 #include "cdbsymbolpathlisteditor.h"
+#include "cdboptions.h"
 
+#include <utils/pathchooser.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
 #include <QtGui/QFileDialog>
 #include <QtGui/QAction>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QFormLayout>
+#include <QtGui/QMessageBox>
 
 namespace Debugger {
 namespace Internal {
 
+CacheDirectoryDialog::CacheDirectoryDialog(QWidget *parent) :
+    QDialog(parent), m_chooser(new Utils::PathChooser),
+    m_buttonBox(new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel))
+{
+    setWindowTitle(tr("Select Local Cache Folder"));
+    setModal(true);
+    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+    QFormLayout *formLayout = new QFormLayout;
+    m_chooser->setExpectedKind(Utils::PathChooser::Directory);
+    m_chooser->setMinimumWidth(400);
+    formLayout->addRow(tr("Path:"), m_chooser);
+
+    QVBoxLayout *mainLayout = new QVBoxLayout;
+    mainLayout->addLayout(formLayout);
+    mainLayout->addWidget(m_buttonBox);
+
+    setLayout(mainLayout);
+
+    connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+    connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+}
+
+void CacheDirectoryDialog::setPath(const QString &p)
+{
+    m_chooser->setPath(p);
+}
+
+QString CacheDirectoryDialog::path() const
+{
+    return m_chooser->path();
+}
+
+void CacheDirectoryDialog::accept()
+{
+    // Ensure path exists
+    QString cache = path();
+    if (cache.isEmpty())
+        return;
+    QFileInfo fi(cache);
+    // Folder exists - all happy.
+    if (fi.isDir()) {
+        QDialog::accept();
+        return;
+    }
+    // Does a file of the same name exist?
+    if (fi.exists()) {
+        QMessageBox::warning(this, tr("Already Exists"),
+                             tr("A file named '%1' already exists.").arg(cache));
+        return;
+    }
+    // Create
+    QDir root(QDir::root());
+    if (!root.mkpath(cache)) {
+        QMessageBox::warning(this, tr("Cannot Create"),
+                             tr("The folder '%1' could not be created.").arg(cache));
+        return;
+    }
+    QDialog::accept();
+}
+
 CdbSymbolPathListEditor::CdbSymbolPathListEditor(QWidget *parent) :
     Utils::PathListEditor(parent)
 {
@@ -44,15 +114,20 @@ CdbSymbolPathListEditor::CdbSymbolPathListEditor(QWidget *parent) :
                       "Requires specifying a local cache directory."));
 }
 
+QString CdbSymbolPathListEditor::promptCacheDirectory(QWidget *parent)
+{
+    CacheDirectoryDialog dialog(parent);
+    dialog.setPath(QDir::tempPath() + QDir::separator() + QLatin1String("symbolcache"));
+    if (dialog.exec() != QDialog::Accepted)
+        return QString();
+    return dialog.path();
+}
+
 void CdbSymbolPathListEditor::addSymbolServer()
 {
-    const QString title = tr("Pick a local cache directory");
-    const QString cacheDir = QFileDialog::getExistingDirectory(this, title);
-    if (!cacheDir.isEmpty()) {
-        const QString path = QString::fromLatin1("symsrv*symsrv.dll*%1*http://msdl.microsoft.com/download/symbols").
-                             arg(QDir::toNativeSeparators(cacheDir));
-        insertPathAtCursor(path);
-    }
+    const QString cacheDir = promptCacheDirectory(this);
+    if (!cacheDir.isEmpty())
+        insertPathAtCursor(CdbOptions::symbolServerPath(cacheDir));
 }
 
 } // namespace Internal
index 9959c00..9152762 100644 (file)
 
 #include <utils/pathlisteditor.h>
 
+#include <QtGui/QDialog>
+
+namespace Utils {
+    class PathChooser;
+}
+
+QT_BEGIN_NAMESPACE
+class QDialogButtonBox;
+QT_END_NAMESPACE
+
 namespace Debugger {
 namespace Internal {
 
+// Internal helper dialog prompting for a cache directory
+// using a PathChooser.
+// Note that QFileDialog does not offer a way of suggesting
+// a non-existent folder, which is in turn automatically
+// created. This is done here (suggest $TEMP\symbolcache
+// regardless of its existence).
+
+class CacheDirectoryDialog    : public QDialog {
+    Q_OBJECT
+public:
+   explicit CacheDirectoryDialog(QWidget *parent = 0);
+
+   void setPath(const QString &p);
+   QString path() const;
+
+   virtual void accept();
+
+private:
+   Utils::PathChooser *m_chooser;
+   QDialogButtonBox *m_buttonBox;
+};
+
 class CdbSymbolPathListEditor : public Utils::PathListEditor
 {
     Q_OBJECT
 public:
     explicit CdbSymbolPathListEditor(QWidget *parent = 0);
 
+    static QString promptCacheDirectory(QWidget *parent);
+
 private slots:
     void addSymbolServer();
 };
index 152e9de..324d470 100644 (file)
@@ -904,6 +904,127 @@ void CoreEngine::setModuleCount(unsigned m)
         m_debugEventCallback->setModuleCount(m);
 }
 
+static inline const char *debugFilterDescription(ULONG in)
+{
+    switch (in) {
+    case DEBUG_FILTER_BREAK:
+        return "break";
+    case DEBUG_FILTER_SECOND_CHANCE_BREAK:
+        return "2nd-chance-break";
+    case DEBUG_FILTER_OUTPUT:
+        return "output";
+    case DEBUG_FILTER_IGNORE:
+        return "ignore";
+    default:
+        break;
+    }
+    return "unknown";
+}
+
+static inline QString msgCannotChangeExceptionCommands(unsigned long code, const QString &why)
+{
+    return QString::fromLatin1("Cannot change exception commands for 0x%1: %2").
+            arg(code, 0, 16).arg(why);
+}
+
+bool CoreEngine::setBreakOnThrow(bool b, QString *errorMessage)
+{
+    // See eventFilterStatus() for defaults
+    const unsigned long code = 0xe06d7363;
+    const unsigned long executionCommand = b ? DEBUG_FILTER_BREAK : DEBUG_FILTER_SECOND_CHANCE_BREAK;
+    const unsigned long continueCommand  = b ? DEBUG_FILTER_BREAK : DEBUG_FILTER_SECOND_CHANCE_BREAK;
+    return setExceptionCommands(code, executionCommand, continueCommand, errorMessage);
+}
+
+bool CoreEngine::setExceptionCommands(ULONG code,
+                                      ULONG executionCommand,
+                                      ULONG continueCommand,
+                                      QString *errorMessage)
+{
+    DEBUG_EXCEPTION_FILTER_PARAMETERS exceptionParameters;
+    HRESULT hr = m_cif.debugControl->GetExceptionFilterParameters(1, &code, 0, &exceptionParameters);
+    if (FAILED(hr)) {
+        *errorMessage = msgCannotChangeExceptionCommands(code, msgComFailed("GetExceptionFilterParameters", hr));
+        return false;
+    }
+    if (exceptionParameters.ExecutionOption == executionCommand
+        && exceptionParameters.ContinueOption == continueCommand)
+        return true;
+    if (debug)
+        qDebug("Changing exception commands of 0x%x from %s/%s to %s/%s",
+               code,
+               debugFilterDescription(exceptionParameters.ExecutionOption),
+               debugFilterDescription(exceptionParameters.ContinueOption),
+               debugFilterDescription(executionCommand),
+               debugFilterDescription(continueCommand));
+
+    exceptionParameters.ExecutionOption = executionCommand;
+    exceptionParameters.ContinueOption = continueCommand;
+    hr = m_cif.debugControl->SetExceptionFilterParameters(1, &exceptionParameters);
+    if (FAILED(hr)) {
+        *errorMessage = msgCannotChangeExceptionCommands(code, msgComFailed("SetExceptionFilterParameters", hr));
+        return false;
+    }
+    return true;
+}
+
+static void formatEventFilter(CIDebugControl *ctl, unsigned long start, unsigned long end,
+                              bool isException,
+                              QTextStream &str)
+{
+    enum { bufSize =2048 };
+    WCHAR buffer[bufSize];
+    for (unsigned long i = start; i < end; i++) {
+        HRESULT hr = ctl->GetEventFilterTextWide(i, buffer, bufSize, 0);
+        if (SUCCEEDED(hr)) {
+            ULONG size;
+            str << "- #" << i << " \"" << QString::fromUtf16(buffer) << '"';
+            hr = ctl->GetEventFilterCommandWide(i, buffer, bufSize, &size);
+            if (SUCCEEDED(hr) && size > 1)
+                str << " command: '" << QString::fromUtf16(buffer) << '\'';
+            if (isException) {
+                DEBUG_EXCEPTION_FILTER_PARAMETERS exceptionParameters;
+                hr = ctl->GetExceptionFilterParameters(1, 0, i, &exceptionParameters);
+                if (SUCCEEDED(hr)) {
+                    str.setIntegerBase(16);
+                    str << " code: 0x" <<  exceptionParameters.ExceptionCode;
+                    str.setIntegerBase(10);
+                    str << " execute: '"
+                            << debugFilterDescription(exceptionParameters.ExecutionOption)
+                            << "' continue: '" << debugFilterDescription(exceptionParameters.ContinueOption)
+                            << '\'';
+                    if (exceptionParameters.SecondCommandSize) {
+                        hr = ctl->GetExceptionFilterSecondCommandWide(i, buffer, bufSize, 0);
+                        if (SUCCEEDED(hr))
+                            str << " 2nd-command '" << QString::fromUtf16(buffer) << '\'';
+                    }
+                }
+            } // isException
+            str << '\n';
+        }
+    }
+}
+
+QString CoreEngine::eventFilterStatus() const
+{
+    ULONG specificEvents, specificExceptions, arbitraryExceptions;
+    QString rc;
+    QTextStream str(&rc);
+
+    HRESULT hr = m_cif.debugControl->GetNumberEventFilters(&specificEvents, &specificExceptions, &arbitraryExceptions);
+    if (FAILED(hr))
+        return QString();
+    str << "Specific events\n";
+    formatEventFilter(m_cif.debugControl, 0, specificEvents, false, str);
+    const ULONG arbitraryExceptionsStart = specificEvents + specificExceptions;
+    str << "Specific exceptions\n";
+    formatEventFilter(m_cif.debugControl, specificEvents, arbitraryExceptionsStart, true, str);
+    str << "Arbitrary exceptions\n";
+    const ULONG arbitraryExceptionsEnd = arbitraryExceptionsStart + arbitraryExceptions;
+    formatEventFilter(m_cif.debugControl, arbitraryExceptionsStart, arbitraryExceptionsEnd, true, str);
+    return rc;
+}
+
 // ------------- DEBUG_VALUE formatting helpers
 
 // format an array of integers as "0x323, 0x2322, ..."
index eff1318..c73fc7e 100644 (file)
@@ -151,6 +151,14 @@ public:
 
     unsigned moduleCount() const;
 
+    bool setBreakOnThrow(bool b, QString *errorMessage);
+    bool setExceptionCommands(ULONG code,
+                              ULONG executionCommand,
+                              ULONG continueCommand,
+                              QString *errorMessage);
+
+    QString eventFilterStatus() const;
+
 signals:
     void watchTimerDebugEvent();
 
index 6bbfe49..57b53ea 100644 (file)
@@ -16,6 +16,7 @@ QT += gui \
     script
 HEADERS += breakhandler.h \
     breakwindow.h \
+    breakpoint.h \
     debuggeragents.h \
     debuggeractions.h \
     debuggerconstants.h \
@@ -34,6 +35,7 @@ HEADERS += breakhandler.h \
     procinterrupt.h \
     registerhandler.h \
     registerwindow.h \
+    stackframe.h \
     stackhandler.h \
     stackwindow.h \
     snapshothandler.h \
@@ -45,7 +47,8 @@ HEADERS += breakhandler.h \
     watchwindow.h \
     name_demangler.h \
     debuggeruiswitcher.h \
-    debuggermainwindow.h
+    debuggermainwindow.h \
+    threadshandler.h
 SOURCES += breakhandler.cpp \
     breakwindow.cpp \
     breakwindow.h \
@@ -76,10 +79,13 @@ SOURCES += breakhandler.cpp \
     watchutils.cpp \
     name_demangler.cpp \
     debuggeruiswitcher.cpp \
-    debuggermainwindow.cpp
+    debuggermainwindow.cpp \
+    threadshandler.cpp \
+    stackframe.cpp
 
 FORMS += attachexternaldialog.ui \
     attachcoredialog.ui \
+    attachtcfdialog.ui \
     breakbyfunction.ui \
     breakcondition.ui \
     dumperoptionpage.ui \
@@ -103,6 +109,7 @@ include(cdb/cdb.pri)
 include(gdb/gdb.pri)
 include(script/script.pri)
 include(pdb/pdb.pri)
+include(tcf/tcf.pri)
 include(shared/shared.pri)
 
 OTHER_FILES += Debugger.pluginspec
index a542bdf..7688ef3 100644 (file)
@@ -18,6 +18,7 @@
         <file>images/debugger_stepoverproc_small.png</file>
         <file>images/debugger_stop.png</file>
         <file>images/debugger_stop_small.png</file>
+        <file>images/watchpoint.png</file>
         <file>images/breakpoint_16.png</file>
         <file>images/breakpoint_24.png</file>
         <file>images/breakpoint_disabled_16.png</file>
index d958246..020f94f 100644 (file)
@@ -112,8 +112,10 @@ enum DebuggerStartMode
     StartExternal,         // Start binary found in file system
     AttachExternal,        // Attach to running process by process id
     AttachCrashedExternal, // Attach to crashed process by process id
+    AttachTcf,             // Attach to a running Target Communication Framework agent
     AttachCore,            // Attach to a core file
-    StartRemote            // Start and attach to a remote process
+    AttachToRemote,        // Start and attach to a remote process
+    StartRemoteGdb         // Start gdb itself remotely
 };
 
 enum DebuggerCapabilities
@@ -130,7 +132,8 @@ enum DebuggerCapabilities
     BreakOnThrowAndCatchCapability = 0x200,
     ReturnFromFunctionCapability = 0x400,
     CreateFullBacktraceCapability = 0x800,
-    AddWatcherCapability = 0x1000
+    AddWatcherCapability = 0x1000,
+    WatchpointCapability = 0x2000
 };
 
 enum LogChannel
index dc36ee5..f4677bb 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "ui_attachcoredialog.h"
 #include "ui_attachexternaldialog.h"
+#include "ui_attachtcfdialog.h"
 #include "ui_startexternaldialog.h"
 #include "ui_startremotedialog.h"
 
@@ -415,6 +416,95 @@ void AttachExternalDialog::pidChanged(const QString &pid)
 
 ///////////////////////////////////////////////////////////////////////
 //
+// AttachTcfDialog
+//
+///////////////////////////////////////////////////////////////////////
+
+AttachTcfDialog::AttachTcfDialog(QWidget *parent)
+  : QDialog(parent),
+    m_ui(new Ui::AttachTcfDialog)
+{
+    m_ui->setupUi(this);
+    m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+    m_ui->serverStartScript->setExpectedKind(Utils::PathChooser::File);
+    m_ui->serverStartScript->setPromptDialogTitle(tr("Select Executable"));
+
+    connect(m_ui->useServerStartScriptCheckBox, SIGNAL(toggled(bool)), 
+        this, SLOT(updateState()));
+    
+    connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+    connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+    updateState();
+}
+
+AttachTcfDialog::~AttachTcfDialog()
+{
+    delete m_ui;
+}
+
+void AttachTcfDialog::setRemoteChannel(const QString &channel)
+{
+    m_ui->channelLineEdit->setText(channel);
+}
+
+QString AttachTcfDialog::remoteChannel() const
+{
+    return m_ui->channelLineEdit->text();
+}
+
+void AttachTcfDialog::setRemoteArchitectures(const QStringList &list)
+{
+    m_ui->architectureComboBox->clear();
+    if (!list.isEmpty()) {
+        m_ui->architectureComboBox->insertItems(0, list);
+        m_ui->architectureComboBox->setCurrentIndex(0);
+    }
+}
+
+void AttachTcfDialog::setRemoteArchitecture(const QString &arch)
+{
+    int index = m_ui->architectureComboBox->findText(arch);
+    if (index != -1)
+        m_ui->architectureComboBox->setCurrentIndex(index);
+}
+
+QString AttachTcfDialog::remoteArchitecture() const
+{
+    int index = m_ui->architectureComboBox->currentIndex();
+    return m_ui->architectureComboBox->itemText(index);
+}
+
+void AttachTcfDialog::setServerStartScript(const QString &scriptName)
+{
+    m_ui->serverStartScript->setPath(scriptName);
+}
+
+QString AttachTcfDialog::serverStartScript() const
+{
+    return m_ui->serverStartScript->path();
+}
+
+void AttachTcfDialog::setUseServerStartScript(bool on)
+{
+    m_ui->useServerStartScriptCheckBox->setChecked(on);
+}
+
+bool AttachTcfDialog::useServerStartScript() const
+{
+    return m_ui->useServerStartScriptCheckBox->isChecked();
+}
+
+void AttachTcfDialog::updateState()
+{
+    bool enabled = m_ui->useServerStartScriptCheckBox->isChecked();
+    m_ui->serverStartScriptLabel->setEnabled(enabled);
+    m_ui->serverStartScript->setEnabled(enabled);
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//
 // StartExternalDialog
 //
 ///////////////////////////////////////////////////////////////////////
@@ -426,6 +516,8 @@ StartExternalDialog::StartExternalDialog(QWidget *parent)
     m_ui->execFile->setExpectedKind(Utils::PathChooser::File);
     m_ui->execFile->setPromptDialogTitle(tr("Select Executable"));
     m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+    m_ui->workingDirectory->setExpectedKind(Utils::PathChooser::Directory);
+    m_ui->workingDirectory->setPromptDialogTitle(tr("Select Working Directory"));
 
     //execLabel->setHidden(false);
     //execEdit->setHidden(false);
@@ -453,6 +545,16 @@ QString StartExternalDialog::executableFile() const
     return m_ui->execFile->path();
 }
 
+void StartExternalDialog::setWorkingDirectory(const QString &str)
+{
+    m_ui->workingDirectory->setPath(str);
+}
+
+QString StartExternalDialog::workingDirectory() const
+{
+    return m_ui->workingDirectory->path();
+}
+
 void StartExternalDialog::setExecutableArguments(const QString &str)
 {
     m_ui->argsEdit->setText(str);
index 7b9fedc..1cc868a 100644 (file)
@@ -42,6 +42,7 @@ class QDialogButtonBox;
 namespace Ui {
 class AttachCoreDialog;
 class AttachExternalDialog;
+class AttachTcfDialog;
 class StartExternalDialog;
 class StartRemoteDialog;
 } // namespace Ui
@@ -107,6 +108,33 @@ private:
     ProcessListFilterModel *m_model;
 };
 
+class AttachTcfDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit AttachTcfDialog(QWidget *parent);
+    ~AttachTcfDialog();
+
+    QString remoteChannel() const;
+    void setRemoteChannel(const QString &host);
+
+    QString remoteArchitecture() const;
+    void setRemoteArchitecture(const QString &arch);
+    void setRemoteArchitectures(const QStringList &arches);
+
+    QString serverStartScript() const;
+    bool useServerStartScript() const;
+    void setUseServerStartScript(bool on);
+    void setServerStartScript(const QString &scriptName);
+
+private slots:
+    void updateState();
+
+private:
+    Ui::AttachTcfDialog *m_ui;
+};
+
 class StartExternalDialog : public QDialog
 {
     Q_OBJECT
@@ -115,11 +143,15 @@ public:
     explicit StartExternalDialog(QWidget *parent);
     ~StartExternalDialog();
 
+    QString executableFile() const;
     void setExecutableFile(const QString &executable);
-    void setExecutableArguments(const QString &args);
 
-    QString executableFile() const;
     QString executableArguments() const;
+    void setExecutableArguments(const QString &args);
+
+    QString workingDirectory() const;
+    void setWorkingDirectory(const QString &str);
+
     bool breakAtMain() const;
 
 private:
@@ -134,21 +166,26 @@ public:
     explicit StartRemoteDialog(QWidget *parent);
     ~StartRemoteDialog();
 
-    void setRemoteChannel(const QString &host);
-    void setRemoteArchitecture(const QString &arch);
-    void setRemoteArchitectures(const QStringList &arches);
-    void setLocalExecutable(const QString &executable);
-    void setDebugger(const QString &debugger);
     QString localExecutable() const;
+    void setLocalExecutable(const QString &executable);
+
     QString remoteChannel() const;
+    void setRemoteChannel(const QString &host);
+
     QString remoteArchitecture() const;
-    void setServerStartScript(const QString &scriptName);
-    QString serverStartScript() const;
-    void setUseServerStartScript(bool on);
+    void setRemoteArchitecture(const QString &arch);
+    void setRemoteArchitectures(const QStringList &arches);
+
     bool useServerStartScript() const;
-    void setSysRoot(const QString &sysRoot);
+    void setUseServerStartScript(bool on);
+    QString serverStartScript() const;
+    void setServerStartScript(const QString &scriptName);
+
     QString sysRoot() const;
+    void setSysRoot(const QString &sysRoot);
+
     QString debugger() const;
+    void setDebugger(const QString &debugger);
 
 private slots:
     void updateState();
index c6bf049..8a3f2e1 100644 (file)
 
 #include "debuggermanager.h"
 
-#include "debuggerplugin.h"
 #include "debuggeractions.h"
 #include "debuggeragents.h"
-#include "debuggerrunner.h"
 #include "debuggerconstants.h"
-#include "idebuggerengine.h"
+#include "debuggermainwindow.h"
+#include "debuggerplugin.h"
+#include "debuggerrunner.h"
 #include "debuggerstringutils.h"
-#include "watchutils.h"
+#include "debuggertooltip.h"
 #include "debuggeruiswitcher.h"
-#include "debuggermainwindow.h"
+#include "idebuggerengine.h"
+#include "watchutils.h"
 
 #include "breakwindow.h"
 #include "debuggeroutputwindow.h"
@@ -56,6 +57,7 @@
 #include "snapshothandler.h"
 #include "stackhandler.h"
 #include "stackframe.h"
+#include "threadshandler.h"
 #include "watchhandler.h"
 
 #include "debuggerdialogs.h"
 #include <QtGui/QTextCursor>
 #include <QtGui/QToolButton>
 #include <QtGui/QToolTip>
+#include <QtGui/QTreeWidget>
 
 #define DEBUG_STATE 1
 #ifdef DEBUG_STATE
@@ -156,6 +159,7 @@ namespace Internal {
 IDebuggerEngine *createGdbEngine(DebuggerManager *parent);
 IDebuggerEngine *createScriptEngine(DebuggerManager *parent);
 IDebuggerEngine *createPdbEngine(DebuggerManager *parent);
+IDebuggerEngine *createTcfEngine(DebuggerManager *parent);
 
 // The createCdbEngine function takes a list of options pages it can add to.
 // This allows for having a "enabled" toggle on the page independently
@@ -178,7 +182,7 @@ DEBUGGER_EXPORT QDebug operator<<(QDebug str, const DebuggerStartParameters &p)
     nospace << "executable=" << p.executable << " coreFile=" << p.coreFile
             << " processArgs=" << p.processArgs.join(sep)
             << " environment=<" << p.environment.size() << " variables>"
-            << " workingDir=" << p.workingDir << " buildDir=" << p.buildDir
+            << " workingDir=" << p.workingDirectory << " buildDir=" << p.buildDirectory
             << " attachPID=" << p.attachPID << " useTerminal=" << p.useTerminal
             << " remoteChannel=" << p.remoteChannel
             << " remoteArchitecture=" << p.remoteArchitecture
@@ -250,6 +254,7 @@ static Debugger::Internal::IDebuggerEngine *gdbEngine = 0;
 static Debugger::Internal::IDebuggerEngine *scriptEngine = 0;
 static Debugger::Internal::IDebuggerEngine *cdbEngine = 0;
 static Debugger::Internal::IDebuggerEngine *pdbEngine = 0;
+static Debugger::Internal::IDebuggerEngine *tcfEngine = 0;
 
 struct DebuggerManagerPrivate
 {
@@ -292,14 +297,15 @@ struct DebuggerManagerPrivate
     DebuggerManagerActions m_actions;
 
     QWidget *m_breakWindow;
+    QWidget *m_returnWindow;
     QWidget *m_localsWindow;
+    QWidget *m_watchersWindow;
     QWidget *m_registerWindow;
     QWidget *m_modulesWindow;
     QWidget *m_snapshotWindow;
     SourceFilesWindow *m_sourceFilesWindow;
     QWidget *m_stackWindow;
     QWidget *m_threadsWindow;
-    QWidget *m_watchersWindow;
     DebuggerOutputWindow *m_outputWindow;
 
     bool m_busy;
@@ -344,6 +350,7 @@ DebuggerManager::~DebuggerManager()
     doDelete(pdbEngine);
     doDelete(gdbEngine);
     doDelete(cdbEngine);
+    doDelete(tcfEngine);
 
     doDelete(d->m_breakHandler);
     doDelete(d->m_threadsHandler);
@@ -356,6 +363,7 @@ DebuggerManager::~DebuggerManager()
     doDelete(gdbEngine);
     doDelete(scriptEngine);
     doDelete(cdbEngine);
+    doDelete(tcfEngine);
     #undef doDelete
     DebuggerManagerPrivate::instance = 0;
     delete d;
@@ -394,6 +402,8 @@ void DebuggerManager::init()
     d->m_sourceFilesWindow->setObjectName(QLatin1String("CppDebugSources"));
     d->m_threadsWindow = new ThreadsWindow;
     d->m_threadsWindow->setObjectName(QLatin1String("CppDebugThreads"));
+    d->m_returnWindow = new WatchWindow(WatchWindow::ReturnType, this);
+    d->m_returnWindow->setObjectName(QLatin1String("CppDebugReturn"));
     d->m_localsWindow = new WatchWindow(WatchWindow::LocalsType, this);
     d->m_localsWindow->setObjectName(QLatin1String("CppDebugLocals"));
     d->m_watchersWindow = new WatchWindow(WatchWindow::WatchersType, this);
@@ -460,8 +470,6 @@ void DebuggerManager::init()
         this, SLOT(loadAllSymbols()));
     connect(modulesView, SIGNAL(fileOpenRequested(QString)),
         this, SLOT(fileOpen(QString)));
-    connect(modulesView, SIGNAL(newDockRequested(QWidget*)),
-        this, SLOT(createNewDock(QWidget*)));
 
     // Source Files
     //d->m_sourceFilesHandler = new SourceFilesHandler;
@@ -479,8 +487,13 @@ void DebuggerManager::init()
     d->m_registerHandler = new RegisterHandler;
     registerView->setModel(d->m_registerHandler->model());
 
-    // Locals
+
+    // Return Value
     d->m_watchHandler = new WatchHandler(this);
+    QTreeView *returnView = qobject_cast<QTreeView *>(d->m_returnWindow);
+    returnView->setModel(d->m_watchHandler->model(ReturnWatch));
+
+    // Locals
     QTreeView *localsView = qobject_cast<QTreeView *>(d->m_localsWindow);
     localsView->setModel(d->m_watchHandler->model(LocalsWatch));
 
@@ -501,8 +514,6 @@ void DebuggerManager::init()
             d->m_outputWindow, SLOT(showOutput(int, QString)), Qt::QueuedConnection);
 
     // Tooltip
-    //QTreeView *tooltipView = qobject_cast<QTreeView *>(d->m_tooltipWindow);
-    //tooltipView->setModel(d->m_watchHandler->model(TooltipsWatch));
     qRegisterMetaType<WatchData>("WatchData");
     qRegisterMetaType<StackCookie>("StackCookie");
 
@@ -630,6 +641,7 @@ void DebuggerManager::init()
     localsAndWatchers->setObjectName(QLatin1String("CppDebugLocalsAndWatchers"));
     localsAndWatchers->setWindowTitle(d->m_localsWindow->windowTitle());
     localsAndWatchers->addWidget(d->m_localsWindow);
+    localsAndWatchers->addWidget(d->m_returnWindow);
     localsAndWatchers->addWidget(d->m_watchersWindow);
     //localsAndWatchers->addWidget(d->m_tooltipWindow);
     localsAndWatchers->setStretchFactor(0, 3);
@@ -665,6 +677,11 @@ QList<Core::IOptionsPage*> DebuggerManager::initializeEngines(unsigned enabledTy
         //pdbEngine->addOptionPages(&rc);
     }
 
+    if (enabledTypeFlags & TcfEngineType) {
+        tcfEngine = createTcfEngine(this);
+        tcfEngine->addOptionPages(&rc);
+    }
+
     d->m_engine = 0;
     STATE_DEBUG(gdbEngine << cdbEngine << scriptEngine
         << pdbEngine << rc.size());
@@ -878,61 +895,6 @@ void DebuggerManager::removeSnapshot(int index)
     d->m_snapshotHandler->removeSnapshot(index);
 }
 
-BreakpointData *DebuggerManager::findBreakpoint(const QString &fileName, int lineNumber)
-{
-    if (!d->m_breakHandler)
-        return 0;
-    int index = d->m_breakHandler->findBreakpoint(fileName, lineNumber);
-    return index == -1 ? 0 : d->m_breakHandler->at(index);
-}
-
-// FIXME: move further up the plugin where there's more specific context
-// information available.
-static BreakpointData *createBreakpointByFileAndLine
-    (const QString &fileName, int lineNumber, BreakHandler *handler)
-{
-    BreakpointData *data = new BreakpointData(handler);
-    if (lineNumber > 0) {
-        data->fileName = fileName;
-        data->lineNumber = QByteArray::number(lineNumber);
-        data->pending = true;
-        data->setMarkerFileName(fileName);
-        data->setMarkerLineNumber(lineNumber);
-    } else {
-        data->funcName = fileName;
-        data->lineNumber = 0;
-        data->pending = true;
-        // FIXME: Figure out in which disassembler view the Marker sits.
-        // Might be better to let the user code create the BreakpointData
-        // structure and insert it here.
-        data->setMarkerFileName(QString());
-        data->setMarkerLineNumber(0);
-    }
-    return data;
-}
-
-void DebuggerManager::toggleBreakpoint(const QString &fileName, int lineNumber)
-{
-    STATE_DEBUG(fileName << lineNumber);
-    QTC_ASSERT(d->m_breakHandler, return);
-    if (state() != InferiorRunning
-         && state() != InferiorStopped
-         && state() != DebuggerNotReady) {
-        showStatusMessage(tr("Changing breakpoint state requires either a "
-            "fully running or fully stopped application."));
-        return;
-    }
-
-    int index = d->m_breakHandler->findBreakpoint(fileName, lineNumber);
-    if (index == -1)
-        d->m_breakHandler->appendBreakpoint(
-            createBreakpointByFileAndLine(fileName, lineNumber, d->m_breakHandler));
-    else
-        d->m_breakHandler->removeBreakpoint(index);
-
-    attemptBreakpointSynchronization();
-}
-
 void DebuggerManager::attemptBreakpointSynchronization()
 {
     if (d->m_engine)
@@ -1039,9 +1001,12 @@ static IDebuggerEngine *debuggerEngineForExecutable(const QString &executable,
 // Debugger type for mode
 static IDebuggerEngine *debuggerEngineForMode(DebuggerStartMode startMode, QString *errorMessage)
 {
+    if (startMode == AttachTcf)
+        return tcfEngine;
+
 #ifdef Q_OS_WIN
     // Preferably Windows debugger for attaching locally.
-    if (startMode != StartRemote && cdbEngine)
+    if (startMode != AttachToRemote && cdbEngine)
         return cdbEngine;
     if (gdbEngine)
         return gdbEngine;
@@ -1086,7 +1051,7 @@ void DebuggerManager::startNewDebugger(const DebuggerStartParametersPtr &sp)
         d->m_engine = debuggerEngineForToolChain(sp->toolChainType);
 
     if (d->m_engine == 0
-            && startMode != StartRemote
+            && startMode != AttachToRemote
             && !sp->executable.isEmpty())
         d->m_engine = debuggerEngineForExecutable(
             sp->executable, &errorMessage, &settingsIdHint);
@@ -1136,6 +1101,7 @@ void DebuggerManager::cleanupViews()
     d->m_sourceFilesWindow->removeAll();
     d->m_disassemblerViewAgent.cleanup();
     d->m_actions.reverseDirectionAction->setChecked(false);
+    hideDebuggerToolTip();
 
     // FIXME: Move to plugin?
     using namespace Core;
@@ -1214,10 +1180,31 @@ void DebuggerManager::loadSymbols(const QString &module)
     d->m_engine->loadSymbols(module);
 }
 
-QList<Symbol> DebuggerManager::moduleSymbols(const QString &moduleName)
+void DebuggerManager::requestModuleSymbols(const QString &moduleName)
 {
-    QTC_ASSERT(d->m_engine, return QList<Symbol>());
-    return d->m_engine->moduleSymbols(moduleName);
+    QTC_ASSERT(d->m_engine, return);
+    d->m_engine->requestModuleSymbols(moduleName);
+}
+
+void DebuggerManager::showModuleSymbols(const QString &moduleName,
+    const QList<Symbol> &symbols)
+{ 
+    QTC_ASSERT(d->m_engine, return);
+    QTreeWidget *w = new QTreeWidget;
+    w->setColumnCount(3);
+    w->setRootIsDecorated(false);
+    w->setAlternatingRowColors(true);
+    w->setSortingEnabled(true);
+    w->setHeaderLabels(QStringList() << tr("Symbol") << tr("Address") << tr("Code"));
+    w->setWindowTitle(tr("Symbols in \"%1\"").arg(moduleName));
+    foreach (const Symbol &s, symbols) {
+        QTreeWidgetItem *it = new QTreeWidgetItem;
+        it->setData(0, Qt::DisplayRole, s.name);
+        it->setData(1, Qt::DisplayRole, s.address);
+        it->setData(2, Qt::DisplayRole, s.state);
+        w->addTopLevelItem(it);
+    }
+    createNewDock(w);
 }
 
 void DebuggerManager::executeStep()
@@ -1387,6 +1374,7 @@ void DebuggerManager::setBusyCursor(bool busy)
 
     QCursor cursor(busy ? Qt::BusyCursor : Qt::ArrowCursor);
     d->m_breakWindow->setCursor(cursor);
+    d->m_returnWindow->setCursor(cursor);
     d->m_localsWindow->setCursor(cursor);
     d->m_modulesWindow->setCursor(cursor);
     d->m_outputWindow->setCursor(cursor);
@@ -1656,10 +1644,12 @@ void DebuggerManager::showQtDumperLibraryWarning(const QString &details)
         dialog.setDetailedText(details);
     dialog.exec();
     if (dialog.clickedButton() == qtPref) {
-        Core::ICore::instance()->showOptionsDialog(_(Qt4ProjectManager::Constants::QT_SETTINGS_CATEGORY),
-                                                   _(Qt4ProjectManager::Constants::QTVERSION_SETTINGS_PAGE_ID));
+        Core::ICore::instance()->showOptionsDialog(
+            _(Qt4ProjectManager::Constants::QT_SETTINGS_CATEGORY),
+            _(Qt4ProjectManager::Constants::QTVERSION_SETTINGS_PAGE_ID));
     } else if (dialog.clickedButton() == helperOff) {
-        theDebuggerAction(UseDebuggingHelpers)->setValue(qVariantFromValue(false), false);
+        theDebuggerAction(UseDebuggingHelpers)
+            ->setValue(qVariantFromValue(false), false);
     }
 }
 
@@ -1967,6 +1957,7 @@ static void changeFontSize(QWidget *widget, int size)
 void DebuggerManager::fontSettingsChanged(const TextEditor::FontSettings &settings)
 {
     int size = settings.fontZoom() * settings.fontSize() / 100;
+    changeFontSize(d->m_returnWindow, size);
     changeFontSize(d->m_localsWindow, size);
     changeFontSize(d->m_watchersWindow, size);
     changeFontSize(d->m_breakWindow, size);
@@ -1988,6 +1979,8 @@ void DebuggerManager::updateWatchersWindow()
 {
     d->m_watchersWindow->setVisible(
         d->m_watchHandler->model(WatchersWatch)->rowCount(QModelIndex()) > 0);
+    d->m_returnWindow->setVisible(
+        d->m_watchHandler->model(ReturnWatch)->rowCount(QModelIndex()) > 0);
 }
 
 void DebuggerManager::openTextEditor(const QString &titlePattern,
@@ -2027,7 +2020,7 @@ void DebuggerManager::runTest(const QString &fileName)
 {
     d->m_startParameters->executable = fileName;
     d->m_startParameters->processArgs = QStringList() << "--run-debuggee";
-    d->m_startParameters->workingDir.clear();
+    d->m_startParameters->workingDirectory.clear();
     //startNewDebugger(StartInternal);
 }
 
index 67480dd..2ce5c17 100644 (file)
@@ -33,6 +33,8 @@
 #include "debugger_global.h"
 #include "debuggerconstants.h"
 
+#include <coreplugin/ssh/sshconnection.h>
+
 #include <QtCore/QObject>
 #include <QtCore/QSharedPointer>
 #include <QtCore/QStringList>
@@ -92,6 +94,7 @@ class CdbDumperHelper;
 class CdbDumperInitThread;
 class CdbExceptionLoggerEventCallback;
 class GdbEngine;
+class TcfEngine;
 class CdbDebugEngine;
 class CdbDebugEnginePrivate;
 class TrkGdbAdapter;
@@ -108,8 +111,8 @@ public:
     QString coreFile;
     QStringList processArgs;
     QStringList environment;
-    QString workingDir;
-    QString buildDir;
+    QString workingDirectory;
+    QString buildDirectory;
     qint64 attachPID;
     bool useTerminal;
     QString crashParameter; // for AttachCrashedExternal
@@ -121,11 +124,12 @@ public:
     QString sysRoot;
     QString debuggerCommand;
     int toolChainType;
-    QString remoteDumperLib;
+    QByteArray remoteDumperLib;
     QString qtInstallPath;
 
     QString dumperLibrary;
     QStringList dumperLibraryLocations;
+    Core::SshServerInfo sshserver;
     DebuggerStartMode startMode;
 };
 
@@ -140,10 +144,12 @@ enum DebuggerEngineTypeFlags
     ScriptEngineType  = 0x02,
     CdbEngineType     = 0x04,
     PdbEngineType     = 0x08,
+    TcfEngineType     = 0x10,
     AllEngineTypes = GdbEngineType
         | ScriptEngineType
         | CdbEngineType
         | PdbEngineType
+        | TcfEngineType
 };
 
 QDebug operator<<(QDebug d, DebuggerState state);
@@ -171,6 +177,7 @@ public:
     friend class Internal::GdbEngine;
     friend class Internal::ScriptEngine;
     friend class Internal::PdbEngine;
+    friend class Internal::TcfEngine;
     friend class Internal::CdbDebugEngine;
     friend class Internal::CdbDebugEnginePrivate;
     friend class Internal::TrkGdbAdapter;
@@ -287,7 +294,7 @@ public slots: // FIXME
     void operateByInstructionTriggered();
     void startFailed();
 
-private:
+public:
     Internal::ModulesHandler *modulesHandler() const;
     Internal::BreakHandler *breakHandler() const;
     Internal::RegisterHandler *registerHandler() const;
@@ -295,6 +302,8 @@ private:
     Internal::ThreadsHandler *threadsHandler() const;
     Internal::WatchHandler *watchHandler() const;
     Internal::SnapshotHandler *snapshotHandler() const;
+
+private:
     Internal::SourceFilesWindow *sourceFileWindow() const;
     QWidget *threadsWindow() const;
 
@@ -327,7 +336,9 @@ private:
 public:
     // stuff in this block should be made private by moving it to
     // one of the interfaces
-    QList<Internal::Symbol> moduleSymbols(const QString &moduleName);
+    void requestModuleSymbols(const QString &moduleName);
+    void showModuleSymbols(const QString &moduleName,
+        const QList<Internal::Symbol> &symbols);
 
 signals:
     void debuggingFinished();
@@ -346,8 +357,7 @@ private:
 
     void aboutToShutdown();
 
-    void toggleBreakpoint(const QString &fileName, int lineNumber);
-    Internal::BreakpointData *findBreakpoint(const QString &fileName, int lineNumber);
+    //void toggleBreakpoint(const QString &fileName, int lineNumber);
     void setToolTipExpression(const QPoint &mousePos,
         TextEditor::ITextEditor *editor, int cursorPos);
     void openTextEditor(const QString &titlePattern,
index 530eca5..4a90ebf 100644 (file)
@@ -122,6 +122,7 @@ const char * const M_DEBUG_START_DEBUGGING = "QtCreator.Menu.Debug.StartDebuggin
 const char * const STARTEXTERNAL        = "Debugger.StartExternal";
 const char * const ATTACHEXTERNAL       = "Debugger.AttachExternal";
 const char * const ATTACHCORE           = "Debugger.AttachCore";
+const char * const ATTACHTCF            = "Debugger.AttachTcf";
 const char * const ATTACHREMOTE         = "Debugger.AttachRemote";
 const char * const DETACH               = "Debugger.Detach";
 
@@ -625,7 +626,7 @@ static bool parseArgument(QStringList::const_iterator &it,
         }
         return true;
     }
-    // engine disabling
+    // Engine disabling.
     if (option == _("-disable-cdb")) {
         *enabledEngines &= ~Debugger::CdbEngineType;
         return true;
@@ -638,14 +639,18 @@ static bool parseArgument(QStringList::const_iterator &it,
         *enabledEngines &= ~Debugger::ScriptEngineType;
         return true;
     }
+    if (option == QLatin1String("-disable-tcf")) {
+        *enabledEngines &= ~TcfEngineType;
+        return true;
+    }
 
     *errorMessage = DebuggerPlugin::tr("Invalid debugger option: %1").arg(option);
     return false;
 }
 
 static bool parseArguments(const QStringList &args,
-                           DebuggerPlugin::AttachRemoteParameters *attachRemoteParameters,
-                           unsigned *enabledEngines, QString *errorMessage)
+   DebuggerPlugin::AttachRemoteParameters *attachRemoteParameters,
+   unsigned *enabledEngines, QString *errorMessage)
 {
     const QStringList::const_iterator cend = args.constEnd();
     for (QStringList::const_iterator it = args.constBegin(); it != cend; ++it)
@@ -747,6 +752,13 @@ bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMess
     m_attachCoreAction->setText(tr("Attach to Core..."));
     connect(m_attachCoreAction, SIGNAL(triggered()), this, SLOT(attachCore()));
 
+    m_attachTcfAction = new QAction(this);
+    m_attachTcfAction->setText(tr("Attach to Running Tcf Agent..."));
+    m_attachTcfAction->setToolTip(tr("This attaches to a running "
+        "'Target Communication Framework' agent."));
+    connect(m_attachTcfAction, SIGNAL(triggered()),
+        this, SLOT(attachRemoteTcf()));
+
     m_startRemoteAction = new QAction(this);
     m_startRemoteAction->setText(tr("Start and Attach to Remote Application..."));
     connect(m_startRemoteAction, SIGNAL(triggered()),
@@ -779,9 +791,14 @@ bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMess
 
     cmd = am->registerAction(m_attachCoreAction,
         Constants::ATTACHCORE, globalcontext);
+
     cmd->setAttribute(Command::CA_Hide);
     mstart->addAction(cmd, CC::G_DEFAULT_ONE);
 
+    cmd = am->registerAction(m_attachTcfAction,
+        Constants::ATTACHTCF, globalcontext);
+    mstart->addAction(cmd, Core::Constants::G_DEFAULT_ONE);
+
     cmd = am->registerAction(m_startRemoteAction,
         Constants::ATTACHREMOTE, globalcontext);
     cmd->setAttribute(Command::CA_Hide);
@@ -1129,19 +1146,28 @@ void DebuggerPlugin::requestContextMenu(TextEditor::ITextEditor *editor,
     if (!isDebuggable(editor))
         return;
 
-    QString fileName, position;
+    BreakHandler *handler = m_manager->breakHandler();
+    QTC_ASSERT(handler, return);
+
+    BreakpointData *data = 0;
+    QString position;
     if (editor->property("DisassemblerView").toBool()) {
         QString fileName = editor->file()->fileName();
         QString line = editor->contents()
             .section('\n', lineNumber - 1, lineNumber - 1);
-        fileName = line.left(line.indexOf(QLatin1Char(' ')));
-        lineNumber = -1;
         position = _("*") + fileName;
+        BreakpointData needle;
+        needle.bpAddress = line.left(line.indexOf(QLatin1Char(' '))).toLatin1();
+        needle.bpLineNumber = "-1";
+        data = handler->findSimilarBreakpoint(needle);
     } else {
-        fileName = editor->file()->fileName();
+        QString fileName = editor->file()->fileName();
         position = fileName + QString(":%1").arg(lineNumber);
+        BreakpointData needle;
+        needle.bpFileName = fileName;
+        needle.bpLineNumber = QByteArray::number(lineNumber);
+        data = handler->findSimilarBreakpoint(needle);
     }
-    BreakpointData *data = m_manager->findBreakpoint(fileName, lineNumber);
 
     if (data) {
         // existing breakpoint
@@ -1174,9 +1200,11 @@ void DebuggerPlugin::breakpointSetRemoveMarginActionTriggered()
 {
     QAction *act = qobject_cast<QAction *>(sender());
     QTC_ASSERT(act, return);
+    BreakHandler *handler = m_manager->breakHandler();
+    QTC_ASSERT(handler, return);
     QString str = act->data().toString();
     int pos = str.lastIndexOf(':');
-    m_manager->toggleBreakpoint(str.left(pos), str.mid(pos + 1).toInt());
+    toggleBreakpoint(str, pos);
 }
 
 void DebuggerPlugin::breakpointEnableDisableMarginActionTriggered()
@@ -1188,12 +1216,12 @@ void DebuggerPlugin::breakpointEnableDisableMarginActionTriggered()
 
     QString str = act->data().toString();
     int pos = str.lastIndexOf(':');
-    QString fileName = str.left(pos);
-    int lineNumber = str.mid(pos + 1).toInt();
-
-    BreakpointData *data = handler->at(handler->findBreakpoint(fileName, lineNumber));
+    BreakpointData needle;
+    needle.bpFileName = str.left(pos);
+    needle.bpLineNumber = str.mid(pos + 1).toLatin1();
+    BreakpointData *data = handler->findSimilarBreakpoint(needle);
+    QTC_ASSERT(data, return);
     handler->toggleBreakpointEnabled(data);
-
     m_manager->attemptBreakpointSynchronization();
 }
 
@@ -1201,7 +1229,7 @@ void DebuggerPlugin::requestMark(ITextEditor *editor, int lineNumber)
 {
     if (!isDebuggable(editor))
         return;
-    m_manager->toggleBreakpoint(editor->file()->fileName(), lineNumber);
+    toggleBreakpoint(editor->file()->fileName(), lineNumber);
 }
 
 void DebuggerPlugin::showToolTip(ITextEditor *editor, const QPoint &point, int pos)
@@ -1384,6 +1412,8 @@ void DebuggerPlugin::startExternalApplication()
             configValue(_("LastExternalExecutableFile")).toString());
     dlg.setExecutableArguments(
             configValue(_("LastExternalExecutableArguments")).toString());
+    dlg.setWorkingDirectory(
+            configValue(_("LastExternalWorkingDirectory")).toString());
     if (dlg.exec() != QDialog::Accepted)
         return;
 
@@ -1391,8 +1421,11 @@ void DebuggerPlugin::startExternalApplication()
                    dlg.executableFile());
     setConfigValue(_("LastExternalExecutableArguments"),
                    dlg.executableArguments());
+    setConfigValue(_("LastExternalWorkingDirectory"),
+                   dlg.workingDirectory());
     sp->executable = dlg.executableFile();
     sp->startMode = StartExternal;
+    sp->workingDirectory = dlg.workingDirectory();
     if (!dlg.executableArguments().isEmpty())
         sp->processArgs = dlg.executableArguments().split(QLatin1Char(' '));
 
@@ -1492,7 +1525,7 @@ void DebuggerPlugin::startRemoteApplication()
     sp->debuggerCommand = dlg.debugger(); // Override toolchain-detection.
     if (!sp->debuggerCommand.isEmpty())
         sp->toolChainType = ProjectExplorer::ToolChain::INVALID;
-    sp->startMode = StartRemote;
+    sp->startMode = AttachToRemote;
     if (dlg.useServerStartScript())
         sp->serverStartScript = dlg.serverStartScript();
     sp->sysRoot = dlg.sysRoot();
@@ -1510,14 +1543,91 @@ void DebuggerPlugin::enableReverseDebuggingTriggered(const QVariant &value)
         m_manager->debuggerManagerActions().reverseDirectionAction->setChecked(false);
 }
 
+static BreakpointData *createBreakpointByFileAndLine
+    (const QString &fileName, int lineNumber)
+{
+    BreakpointData *data = new BreakpointData;
+    if (lineNumber > 0) {
+        data->fileName = fileName;
+        data->lineNumber = QByteArray::number(lineNumber);
+        data->pending = true;
+        data->setMarkerFileName(fileName);
+        data->setMarkerLineNumber(lineNumber);
+    } else {
+        data->funcName = fileName;
+        data->lineNumber = 0;
+        data->pending = true;
+        // FIXME: Figure out in which disassembler view the Marker sits.
+        // Might be better to let the user code create the BreakpointData
+        // structure and insert it here.
+        data->setMarkerFileName(QString());
+        data->setMarkerLineNumber(0);
+    }
+    return data;
+}
+
 void DebuggerPlugin::toggleBreakpoint()
 {
     ITextEditor *textEditor = currentTextEditor();
     QTC_ASSERT(textEditor, return);
-    QString fileName = textEditor->file()->fileName();
     int lineNumber = textEditor->currentLine();
     if (lineNumber >= 0)
-        m_manager->toggleBreakpoint(fileName, lineNumber);
+        toggleBreakpoint(textEditor->file()->fileName(), lineNumber);
+}
+
+void DebuggerPlugin::toggleBreakpoint(const QString &fileName, int lineNumber)
+{
+    BreakHandler *handler = m_manager->breakHandler();
+    QTC_ASSERT(handler, return);
+    BreakpointData needle;
+    needle.bpFileName = fileName;
+    needle.bpLineNumber.setNum(lineNumber);
+    BreakpointData *data = handler->findSimilarBreakpoint(needle);
+    if (data) {
+        handler->removeBreakpoint(data);
+    } else {
+        data = new BreakpointData;
+        data->fileName = fileName;
+        data->lineNumber = QByteArray::number(lineNumber);
+        data->pending = true;
+        data->setMarkerFileName(fileName);
+        data->setMarkerLineNumber(lineNumber);
+        handler->appendBreakpoint(data);
+    }
+    m_manager->attemptBreakpointSynchronization();
+}
+
+void DebuggerPlugin::attachRemoteTcf()
+{
+    const DebuggerStartParametersPtr sp(new DebuggerStartParameters);
+    AttachTcfDialog dlg(m_uiSwitcher->mainWindow());
+    QStringList arches;
+    arches.append(_("i386:x86-64:intel"));
+    dlg.setRemoteArchitectures(arches);
+    dlg.setRemoteChannel(
+            configValue(_("LastTcfRemoteChannel")).toString());
+    dlg.setRemoteArchitecture(
+            configValue(_("LastTcfRemoteArchitecture")).toString());
+    dlg.setServerStartScript(
+            configValue(_("LastTcfServerStartScript")).toString());
+    dlg.setUseServerStartScript(
+            configValue(_("LastTcfUseServerStartScript")).toBool());
+    if (dlg.exec() != QDialog::Accepted)
+        return;
+    setConfigValue(_("LastTcfRemoteChannel"), dlg.remoteChannel());
+    setConfigValue(_("LastTcfRemoteArchitecture"), dlg.remoteArchitecture());
+    setConfigValue(_("LastTcfServerStartScript"), dlg.serverStartScript());
+    setConfigValue(_("LastTcfUseServerStartScript"), dlg.useServerStartScript());
+    sp->remoteChannel = dlg.remoteChannel();
+    sp->remoteArchitecture = dlg.remoteArchitecture();
+    sp->serverStartScript = dlg.serverStartScript();
+    sp->startMode = AttachTcf;
+    if (dlg.useServerStartScript())
+        sp->serverStartScript = dlg.serverStartScript();
+
+    if (RunControl *runControl = m_debuggerRunControlFactory->create(sp))
+        ProjectExplorerPlugin::instance()
+            ->startRunControl(runControl, PE::DEBUGMODE);
 }
 
 #include "debuggerplugin.moc"
index bb53708..7d9e7b1 100644 (file)
@@ -82,10 +82,10 @@ public:
     ~DebuggerPlugin();
 
 private:
-    virtual bool initialize(const QStringList &arguments, QString *error_message);
-    virtual void aboutToShutdown();
-    virtual void extensionsInitialized();
-    virtual void remoteCommand(const QStringList &options, const QStringList &arguments);
+    bool initialize(const QStringList &arguments, QString *error_message);
+    void aboutToShutdown();
+    void extensionsInitialized();
+    void remoteCommand(const QStringList &options, const QStringList &arguments);
 
     QVariant configValue(const QString &name) const;
     TextEditor::ITextEditor *currentTextEditor();
@@ -96,8 +96,8 @@ private:
 private slots:
     void activatePreviousMode();
     void activateDebugMode();
-    void editorOpened(Core::IEditor *);
-    void editorAboutToClose(Core::IEditor *);
+    void editorOpened(Core::IEditor *editor);
+    void editorAboutToClose(Core::IEditor *editor);
     void handleStateChanged(int state);
     void requestMark(TextEditor::ITextEditor *editor, int lineNumber);
     void showToolTip(TextEditor::ITextEditor *editor, const QPoint &pnt, int pos);
@@ -105,11 +105,12 @@ private slots:
         int lineNumber, QMenu *menu);
 
     void resetLocation();
-    void gotoLocation(const QString &file, int line, bool setMarker);
+    void gotoLocation(const QString &fileName, int lineNumber, bool setMarker);
 
     void openTextEditor(const QString &titlePattern, const QString &contents);
 
     void toggleBreakpoint();
+    void toggleBreakpoint(const QString &fileName, int lineNumber);
     void breakpointSetRemoveMarginActionTriggered();
     void breakpointEnableDisableMarginActionTriggered();
     void onModeChanged(Core::IMode *mode);
@@ -120,6 +121,7 @@ private slots:
     void attachExternalApplication();
     void attachCore();
     void attachCmdLine();
+    void attachRemoteTcf();
 
     void enableReverseDebuggingTriggered(const QVariant &value);
     void languageChanged(const QString &debuggerLanguage);
@@ -153,6 +155,7 @@ private:
     QAction *m_startRemoteAction;
     QAction *m_attachExternalAction;
     QAction *m_attachCoreAction;
+    QAction *m_attachTcfAction;
     QAction *m_detachAction;
     QComboBox *m_langBox;
     QToolButton *m_reverseToolButton;
index 2b6f368..450c6ce 100644 (file)
@@ -106,7 +106,7 @@ QWidget *DebuggerRunControlFactory::createConfigurationWidget(RunConfiguration *
 
 DebuggerRunControl::DebuggerRunControl(DebuggerManager *manager,
        LocalApplicationRunConfiguration *runConfiguration)
-  : RunControl(runConfiguration),
+  : RunControl(runConfiguration, ProjectExplorer::Constants::DEBUGMODE),
     m_startParameters(new DebuggerStartParameters()),
     m_manager(manager),
     m_running(false)
@@ -118,7 +118,7 @@ DebuggerRunControl::DebuggerRunControl(DebuggerManager *manager,
     m_startParameters->startMode = StartInternal;
     m_startParameters->executable = runConfiguration->executable();
     m_startParameters->environment = runConfiguration->environment().toStringList();
-    m_startParameters->workingDir = runConfiguration->workingDirectory();
+    m_startParameters->workingDirectory = runConfiguration->workingDirectory();
     m_startParameters->processArgs = runConfiguration->commandLineArguments();
 
     switch (m_startParameters->toolChainType) {
@@ -130,7 +130,7 @@ DebuggerRunControl::DebuggerRunControl(DebuggerManager *manager,
         break;
     }
     if (runConfiguration->target()->project()) {
-        m_startParameters->buildDir =
+        m_startParameters->buildDirectory =
             runConfiguration->target()->activeBuildConfiguration()->buildDirectory();
     }
     m_startParameters->useTerminal =
@@ -157,7 +157,7 @@ DebuggerRunControl::DebuggerRunControl(DebuggerManager *manager,
 }
 
 DebuggerRunControl::DebuggerRunControl(DebuggerManager *manager, const DebuggerStartParametersPtr &startParameters)
-    : RunControl(0),
+    : RunControl(0, ProjectExplorer::Constants::DEBUGMODE),
       m_startParameters(startParameters),
       m_manager(manager),
       m_running(false)
index ea15472..9ec60a8 100644 (file)
@@ -29,6 +29,8 @@
 
 #include "abstractgdbadapter.h"
 
+#include "abstractgdbprocess.h"
+
 #include <utils/qtcassert.h>
 
 #include <QtCore/QProcess>
@@ -61,7 +63,7 @@ const char *AbstractGdbAdapter::inferiorShutdownCommand() const
 
 void AbstractGdbAdapter::write(const QByteArray &data)
 {
-    m_engine->m_gdbProc.write(data);
+    gdbProc()->write(data);
 }
 
 bool AbstractGdbAdapter::isTrkAdapter() const
index 69ad840..3d36f24 100644 (file)
@@ -38,6 +38,8 @@
 namespace Debugger {
 namespace Internal {
 
+class AbstractGdbProcess;
+
 // AbstractGdbAdapter is inherited by PlainGdbAdapter used for local
 // debugging and TrkGdbAdapter used for on-device debugging.
 // In the PlainGdbAdapter case it's just a wrapper around a QProcess running
@@ -64,6 +66,7 @@ public:
     virtual void interruptInferior() = 0;
     virtual void shutdown();
     virtual const char *inferiorShutdownCommand() const;
+    virtual AbstractGdbProcess *gdbProc() = 0;
 
     virtual DumperHandling dumperHandling() const = 0;
 
diff --git a/src/plugins/debugger/gdb/abstractgdbprocess.cpp b/src/plugins/debugger/gdb/abstractgdbprocess.cpp
new file mode 100644 (file)
index 0000000..55c6b67
--- /dev/null
@@ -0,0 +1,36 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "abstractgdbprocess.h"
+
+namespace Debugger {
+namespace Internal {
+
+} // namespace Internal
+} // namespace Debugger
diff --git a/src/plugins/debugger/gdb/abstractgdbprocess.h b/src/plugins/debugger/gdb/abstractgdbprocess.h
new file mode 100644 (file)
index 0000000..61fa160
--- /dev/null
@@ -0,0 +1,76 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef GDBPROCESSWRAPPER_H
+#define GDBPROCESSWRAPPER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QProcess>
+
+namespace Debugger {
+namespace Internal {
+
+class AbstractGdbProcess : public QObject
+{
+    Q_OBJECT
+    Q_DISABLE_COPY(AbstractGdbProcess)
+public:
+    virtual QByteArray readAllStandardOutput() = 0;
+    virtual QByteArray readAllStandardError() = 0;
+
+    virtual void start(const QString &cmd, const QStringList &args) = 0;
+    virtual bool waitForStarted() = 0;
+    virtual qint64 write(const QByteArray &data) = 0;
+    virtual void kill() = 0;
+
+    virtual QProcess::ProcessState state() const = 0;
+    virtual QString errorString() const = 0;
+
+    virtual QProcessEnvironment processEnvironment() const = 0;
+    virtual void setProcessEnvironment(const QProcessEnvironment &env) = 0;
+    virtual void setEnvironment(const QStringList &env) = 0;
+    virtual void setWorkingDirectory(const QString &dir) = 0;
+
+    virtual ~AbstractGdbProcess() {}
+
+signals:
+    void error(QProcess::ProcessError);
+    void finished(int exitCode, QProcess::ExitStatus exitStatus);
+    void readyReadStandardError();
+    void readyReadStandardOutput();
+
+protected:
+    explicit AbstractGdbProcess(QObject *parent = 0) : QObject(parent) {}
+
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // GDBPROCESSWRAPPER_H
 **
 **************************************************************************/
 
-#include "plaingdbadapter.h"
+#include "abstractplaingdbadapter.h"
 
-#include "gdbengine.h"
-#include "procinterrupt.h"
-#include "debuggerstringutils.h"
 #include "debuggeractions.h"
+#include "debuggerstringutils.h"
 
 #include <utils/qtcassert.h>
 
-#include <QtCore/QFileInfo>
-
 namespace Debugger {
 namespace Internal {
 
 #define CB(callback) \
-    static_cast<GdbEngine::AdapterCallback>(&PlainGdbAdapter::callback), \
+    static_cast<GdbEngine::AdapterCallback>(&AbstractPlainGdbAdapter::callback), \
     STRINGIFY(callback)
 
-///////////////////////////////////////////////////////////////////////
-//
-// PlainGdbAdapter
-//
-///////////////////////////////////////////////////////////////////////
-
-PlainGdbAdapter::PlainGdbAdapter(GdbEngine *engine, QObject *parent)
+AbstractPlainGdbAdapter::AbstractPlainGdbAdapter(GdbEngine *engine,
+                                                 QObject *parent)
     : AbstractGdbAdapter(engine, parent)
 {
-    // Output
-    connect(&m_outputCollector, SIGNAL(byteDelivery(QByteArray)),
-        engine, SLOT(readDebugeeOutput(QByteArray)));
 }
 
-AbstractGdbAdapter::DumperHandling PlainGdbAdapter::dumperHandling() const
-{
-    // LD_PRELOAD fails for System-Qt on Mac.
-#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
-    return DumperLoadedByGdb;
-#else
-    return DumperLoadedByGdbPreload;
-#endif
-}
-
-void PlainGdbAdapter::startAdapter()
-{
-    QTC_ASSERT(state() == EngineStarting, qDebug() << state());
-    setState(AdapterStarting);
-    debugMessage(_("TRYING TO START ADAPTER"));
-
-    QStringList gdbArgs;
-
-    if (!m_outputCollector.listen()) {
-        emit adapterStartFailed(tr("Cannot set up communication with child process: %1")
-                .arg(m_outputCollector.errorString()), QString());
-        return;
-    }
-    gdbArgs.append(_("--tty=") + m_outputCollector.serverName());
-
-    if (!startParameters().workingDir.isEmpty())
-        m_engine->m_gdbProc.setWorkingDirectory(startParameters().workingDir);
-    if (!startParameters().environment.isEmpty())
-        m_engine->m_gdbProc.setEnvironment(startParameters().environment);
-
-    if (!m_engine->startGdb(gdbArgs)) {
-        m_outputCollector.shutdown();
-        return;
-    }
-
-    emit adapterStarted();
-}
 
-void PlainGdbAdapter::startInferior()
+void AbstractPlainGdbAdapter::startInferior()
 {
     QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
     if (!startParameters().processArgs.isEmpty()) {
         QString args = startParameters().processArgs.join(_(" "));
-        m_engine->postCommand("-exec-arguments " + args.toLocal8Bit());
+        m_engine->postCommand("-exec-arguments " + toLocalEncoding(args));
     }
-    QFileInfo fi(startParameters().executable);
-    QByteArray path = fi.absoluteFilePath().toLocal8Bit();
-    m_engine->postCommand("-file-exec-and-symbols \"" + path + '"',
+    m_engine->postCommand("-file-exec-and-symbols \"" + execFilePath() + '"',
         CB(handleFileExecAndSymbols));
 }
 
-void PlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response)
+void AbstractPlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response)
 {
     QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
     if (response.resultClass == GdbResultDone) {
-#ifdef Q_OS_LINUX
-        // Old gdbs do not announce the PID for programs without pthreads.
-        // Note that successfully preloading the debugging helpers will
-        // automatically load pthreads, so this will be unnecessary.
-        if (m_engine->m_gdbVersion < 70000)
-            m_engine->postCommand("info target", CB(handleInfoTarget));
-#endif
+        if (infoTargetNecessary()) {
+            // Old gdbs do not announce the PID for programs without pthreads.
+            // Note that successfully preloading the debugging helpers will
+            // automatically load pthreads, so this will be unnecessary.
+            if (m_engine->m_gdbVersion < 70000)
+                m_engine->postCommand("info target", CB(handleInfoTarget));
+        }
         emit inferiorPrepared();
     } else {
         QByteArray ba = response.data.findChild("msg").data();
-        QString msg = QString::fromLocal8Bit(ba);
+        QString msg = fromLocalEncoding(ba);
         // Extend the message a bit in unknown cases.
         if (!ba.endsWith("File format not recognized"))
             msg = tr("Starting executable failed:\n") + msg;
@@ -132,36 +81,13 @@ void PlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response)
     }
 }
 
-#ifdef Q_OS_LINUX
-void PlainGdbAdapter::handleInfoTarget(const GdbResponse &response)
-{
-    if (response.resultClass == GdbResultDone) {
-        // [some leading stdout here]
-        // >&"        Entry point: 0x80831f0  0x08048134 - 0x08048147 is .interp\n"
-        // [some trailing stdout here]
-        QString msg = _(response.data.findChild("consolestreamoutput").data());
-        QRegExp needle(_("\\bEntry point: 0x([0-9a-f]+)\\b"));
-        if (needle.indexIn(msg) != -1) {
-            m_engine->m_entryPoint =
-                    "0x" + needle.cap(1).toLatin1().rightJustified(sizeof(void *) * 2, '0');
-            m_engine->postCommand("tbreak *0x" + needle.cap(1).toAscii());
-            // Do nothing here - inferiorPrepared handles the sequencing.
-        } else {
-            emit inferiorStartFailed(_("Parsing start address failed"));
-        }
-    } else if (response.resultClass == GdbResultError) {
-        emit inferiorStartFailed(_("Fetching start address failed"));
-    }
-}
-#endif
-
-void PlainGdbAdapter::startInferiorPhase2()
+void AbstractPlainGdbAdapter::startInferiorPhase2()
 {
     setState(InferiorRunningRequested);
     m_engine->postCommand("-exec-run", GdbEngine::RunRequest, CB(handleExecRun));
 }
 
-void PlainGdbAdapter::handleExecRun(const GdbResponse &response)
+void AbstractPlainGdbAdapter::handleExecRun(const GdbResponse &response)
 {
     if (response.resultClass == GdbResultRunning) {
         QTC_ASSERT(state() == InferiorRunning, qDebug() << state());
@@ -172,30 +98,33 @@ void PlainGdbAdapter::handleExecRun(const GdbResponse &response)
             m_engine->postCommand("target record");
     } else {
         QTC_ASSERT(state() == InferiorRunningRequested, qDebug() << state());
-        QString msg = QString::fromLocal8Bit(response.data.findChild("msg").data());
+        QString msg = fromLocalEncoding(response.data.findChild("msg").data());
         //QTC_ASSERT(status() == InferiorRunning, /**/);
         //interruptInferior();
         emit inferiorStartFailed(msg);
     }
 }
 
-void PlainGdbAdapter::interruptInferior()
+void AbstractPlainGdbAdapter::handleInfoTarget(const GdbResponse &response)
 {
-    const qint64 attachedPID = m_engine->inferiorPid();
-    if (attachedPID <= 0) {
-        debugMessage(_("TRYING TO INTERRUPT INFERIOR BEFORE PID WAS OBTAINED"));
-        return;
+    if (response.resultClass == GdbResultDone) {
+        // [some leading stdout here]
+        // >&"        Entry point: 0x80831f0  0x08048134 - 0x08048147 is .interp\n"
+        // [some trailing stdout here]
+        QString msg = _(response.data.findChild("consolestreamoutput").data());
+        QRegExp needle(_("\\bEntry point: 0x([0-9a-f]+)\\b"));
+        if (needle.indexIn(msg) != -1) {
+            m_engine->m_entryPoint =
+                    "0x" + needle.cap(1).toLatin1().rightJustified(sizeof(void *) * 2, '0');
+            m_engine->postCommand("tbreak *0x" + needle.cap(1).toAscii());
+            // Do nothing here - inferiorPrepared handles the sequencing.
+        } else {
+            emit inferiorStartFailed(_("Parsing start address failed"));
+        }
+    } else if (response.resultClass == GdbResultError) {
+        emit inferiorStartFailed(_("Fetching start address failed"));
     }
-
-    if (!interruptProcess(attachedPID))
-        debugMessage(_("CANNOT INTERRUPT %1").arg(attachedPID));
 }
 
-void PlainGdbAdapter::shutdown()
-{
-    debugMessage(_("PLAIN ADAPTER SHUTDOWN %1").arg(state()));
-    m_outputCollector.shutdown();
-}
-
-} // namespace Internal
 } // namespace Debugger
+} // namespace Internal
diff --git a/src/plugins/debugger/gdb/abstractplaingdbadapter.h b/src/plugins/debugger/gdb/abstractplaingdbadapter.h
new file mode 100644 (file)
index 0000000..9d6fddc
--- /dev/null
@@ -0,0 +1,62 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef ABSTRACTPLAINGDBADAPTER_H
+#define ABSTRACTPLAINGDBADAPTER_H
+
+#include "abstractgdbadapter.h"
+
+namespace Debugger {
+namespace Internal {
+
+class AbstractPlainGdbAdapter : public AbstractGdbAdapter
+{
+public:
+    AbstractPlainGdbAdapter(GdbEngine *engine, QObject *parent = 0);
+
+    virtual void startInferior();
+    virtual void startInferiorPhase2();
+
+protected:
+    void handleInfoTarget(const GdbResponse &response);
+
+private:
+    virtual QByteArray execFilePath() const = 0;
+    virtual bool infoTargetNecessary() const = 0;
+    virtual QByteArray toLocalEncoding(const QString &s) const = 0;
+    virtual QString fromLocalEncoding(const QByteArray &b) const = 0;
+    void handleExecRun(const GdbResponse &response);
+    void handleFileExecAndSymbols(const GdbResponse &response);
+
+};
+
+} // namespace Debugger
+} // namespace Internal
+
+#endif // ABSTRACTPLAINGDBADAPTER_H
index 923231d..50377d7 100644 (file)
@@ -32,6 +32,8 @@
 
 #include "abstractgdbadapter.h"
 
+#include "abstractgdbprocess.h"
+
 namespace Debugger {
 namespace Internal {
 
@@ -54,9 +56,12 @@ public:
     void startInferior();
     void interruptInferior();
     const char *inferiorShutdownCommand() const { return "detach"; }
+    AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
 
 private:
     void handleAttach(const GdbResponse &response);
+
+    LocalGdbProcess m_gdbProc;
 };
 
 } // namespace Internal
index 5bed94c..3c5ddcb 100644 (file)
@@ -41,6 +41,7 @@
 
 #include <QtCore/QFile>
 #include <QtCore/QFileInfo>
+#include <QtGui/QMessageBox>
 
 #if !defined(Q_OS_WIN)
 #include <dlfcn.h>
@@ -513,8 +514,9 @@ void GdbEngine::tryLoadDebuggingHelpersClassic()
 
     m_debuggingHelperState = DebuggingHelperLoadTried;
     QByteArray dlopenLib;
-    if (startParameters().startMode == StartRemote)
-        dlopenLib = startParameters().remoteDumperLib.toLocal8Bit();
+    if (startParameters().startMode == AttachToRemote
+        || startParameters().startMode == StartRemoteGdb)
+        dlopenLib = startParameters().remoteDumperLib;
     else
         dlopenLib = manager()->qtDumperLibraryName().toLocal8Bit();
 
@@ -580,7 +582,7 @@ void GdbEngine::updateAllClassic()
         QVariant::fromValue<StackCookie>(StackCookie(false, true)));
     manager()->stackHandler()->setCurrentIndex(0);
     if (supportsThreads())
-        postCommand("-thread-list-ids", WatchUpdate, CB(handleStackListThreads), 0);
+        postCommand("-thread-list-ids", WatchUpdate, CB(handleThreadListIds), 0);
     manager()->reloadRegisters();
     updateLocals();
 }
@@ -672,6 +674,15 @@ void GdbEngine::handleStackListLocalsClassic(const GdbResponse &response)
         if (data.isValid())
             list.push_back(data);
     }
+
+    if (!m_resultVarName.isEmpty()) {
+        WatchData rd;
+        rd.iname = "return.0";
+        rd.name = "return";
+        rd.exp = m_resultVarName;
+        list.append(rd);
+    }
+
     manager()->watchHandler()->insertBulkData(list);
     manager()->watchHandler()->updateWatchers();
 }
@@ -717,6 +728,12 @@ void GdbEngine::handleQueryDebuggingHelperClassic(const GdbResponse &response)
         const QString successMsg = tr("Dumper version %1, %n custom dumpers found.",
             0, m_dumperHelper.typeCount()).arg(dumperVersion);
         showStatusMessage(successMsg);
+
+        // Sanity check for Qt version of dumpers and debuggee.
+        QByteArray ns = m_dumperHelper.qtNamespace().toLatin1();
+        postCommand("-var-create A@ * '" + ns + "qVersion'()",
+            CB(handleDebuggingHelperVersionCheckClassic));
+        postCommand("-var-delete A@");
     } else {
         // Retry if thread has not terminated yet.
         m_debuggingHelperState = DebuggingHelperUnavailable;
@@ -726,6 +743,28 @@ void GdbEngine::handleQueryDebuggingHelperClassic(const GdbResponse &response)
     //qDebug() << m_availableSimpleDebuggingHelpers << "DATA DUMPERS AVAILABLE";
 }
 
+void GdbEngine::handleDebuggingHelperVersionCheckClassic(const GdbResponse &response)
+{
+    if (response.resultClass == GdbResultDone) {
+        QString value = _(response.data.findChild("value").data());
+        QString debuggeeQtVersion = value.section(QLatin1Char('"'), 1, 1);
+        QString dumperQtVersion = m_dumperHelper.qtVersionString();
+        if (dumperQtVersion != debuggeeQtVersion) {
+            manager()->showMessageBox(QMessageBox::Warning,
+                tr("Debugging helpers: Qt version mismatch"),
+                tr("The Qt version used to build the debugging helpers (%1) "
+                   "does not match the Qt version used to build the debugged "
+                   "application (%2).\nThis might yield incorrect results.")
+                    .arg(dumperQtVersion).arg(debuggeeQtVersion));
+        } else {
+            debugMessage(_("DUMPER VERSION CHECK SUCCESSFUL: ")
+                         + dumperQtVersion);
+        }
+    } else {
+        debugMessage("DUMPER VERSION CHECK NOT COMPLETED");
+    }
+}
+
 void GdbEngine::handleVarListChildrenHelperClassic(const GdbMi &item,
     const WatchData &parent)
 {
index 24d641e..72aa161 100644 (file)
@@ -32,6 +32,8 @@
 
 #include "abstractgdbadapter.h"
 
+#include "abstractgdbprocess.h"
+
 #ifdef Q_OS_LINUX
 # define EXE_FROM_CORE
 #endif
@@ -57,6 +59,7 @@ public:
     void startAdapter();
     void startInferior();
     void interruptInferior();
+    AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
 
 private:
     void loadExeAndSyms();
@@ -68,6 +71,7 @@ private:
     int m_round;
 #endif
     QString m_executable;
+    LocalGdbProcess m_gdbProc;
 };
 
 } // namespace Internal
index 85b9ef9..ffe5861 100644 (file)
@@ -6,11 +6,16 @@ HEADERS += \
     $$PWD/abstractgdbadapter.h \
     $$PWD/attachgdbadapter.h \
     $$PWD/coregdbadapter.h \
-    $$PWD/plaingdbadapter.h \
+    $$PWD/localplaingdbadapter.h \
     $$PWD/termgdbadapter.h \
-    $$PWD/remotegdbadapter.h \
+    $$PWD/remotegdbserveradapter.h \
     $$PWD/trkgdbadapter.h \
-    $$PWD/s60debuggerbluetoothstarter.h
+    $$PWD/s60debuggerbluetoothstarter.h \
+    $$PWD/abstractgdbprocess.h \
+    $$PWD/localgdbprocess.h \
+    $$PWD/remotegdbprocess.h \
+    $$PWD/remoteplaingdbadapter.h \
+    $$PWD/abstractplaingdbadapter.h
 
 SOURCES += \
     $$PWD/gdbmi.cpp \
@@ -22,11 +27,16 @@ SOURCES += \
     $$PWD/abstractgdbadapter.cpp \
     $$PWD/attachgdbadapter.cpp \
     $$PWD/coregdbadapter.cpp \
-    $$PWD/plaingdbadapter.cpp \
+    $$PWD/localplaingdbadapter.cpp \
     $$PWD/termgdbadapter.cpp \
-    $$PWD/remotegdbadapter.cpp \
+    $$PWD/remotegdbserveradapter.cpp \
     $$PWD/trkgdbadapter.cpp \
-    $$PWD/s60debuggerbluetoothstarter.cpp
+    $$PWD/s60debuggerbluetoothstarter.cpp \
+    $$PWD/abstractgdbprocess.cpp \
+    $$PWD/localgdbprocess.cpp \
+    $$PWD/remotegdbprocess.cpp \
+    $$PWD/remoteplaingdbadapter.cpp \
+    $$PWD/abstractplaingdbadapter.cpp
 
 FORMS +=  $$PWD/gdboptionspage.ui
 
index 166e5de..4be4d05 100644 (file)
 
 #include "attachgdbadapter.h"
 #include "coregdbadapter.h"
-#include "plaingdbadapter.h"
+#include "localplaingdbadapter.h"
 #include "termgdbadapter.h"
-#include "remotegdbadapter.h"
+#include "remotegdbserveradapter.h"
+#include "remoteplaingdbadapter.h"
 #include "trkgdbadapter.h"
 
 #include "watchutils.h"
@@ -55,6 +56,7 @@
 #include "registerhandler.h"
 #include "snapshothandler.h"
 #include "stackhandler.h"
+#include "threadshandler.h"
 #include "watchhandler.h"
 
 #include "sourcefileswindow.h"
@@ -218,10 +220,16 @@ QMainWindow *GdbEngine::mainWindow() const
     return DebuggerUISwitcher::instance()->mainWindow();
 }
 
+AbstractGdbProcess *GdbEngine::gdbProc() const
+{
+    return m_gdbAdapter->gdbProc();
+}
+
 GdbEngine::~GdbEngine()
 {
     // Prevent sending error messages afterwards.
-    disconnect(&m_gdbProc, 0, this, 0);
+    if (m_gdbAdapter)
+        disconnect(gdbProc(), 0, this, 0);
     delete m_gdbAdapter;
     m_gdbAdapter = 0;
 }
@@ -266,6 +274,7 @@ void GdbEngine::initializeVariables()
     m_pendingLogStreamOutput.clear();
 
     m_inbuffer.clear();
+    m_resultVarName.clear();
 
     m_commandTimer->stop();
 
@@ -443,7 +452,7 @@ void GdbEngine::handleResponse(const QByteArray &buff)
                 int progress = m_progress->progressValue();
                 m_progress->setProgressValue(qMin(70, progress + 1));
                 QByteArray id = result.findChild("id").data();
-                showStatusMessage(tr("Thread group %1 created.").arg(_(id)), 1000);
+                showStatusMessage(tr("Thread group %1 created").arg(_(id)), 1000);
                 int pid = id.toInt();
                 if (pid != inferiorPid())
                     handleInferiorPidChanged(pid);
@@ -485,8 +494,8 @@ void GdbEngine::handleResponse(const QByteArray &buff)
                 const GdbMi bkpt = result.findChild("bkpt");
                 const int number = bkpt.findChild("number").data().toInt();
                 BreakHandler *handler = manager()->breakHandler();
-                BreakpointData *data = handler->findBreakpoint(number);
-                breakpointDataFromOutput(data, bkpt);
+                BreakpointData *data = handler->findBreakpointByNumber(number);
+                setBreakpointDataFromOutput(data, bkpt);
                 handler->updateMarkers();
             } else {
                 qDebug() << "IGNORED ASYNC OUTPUT"
@@ -614,7 +623,7 @@ void GdbEngine::handleResponse(const QByteArray &buff)
 
 void GdbEngine::readGdbStandardError()
 {
-    QByteArray err = m_gdbProc.readAllStandardError();
+    QByteArray err = gdbProc()->readAllStandardError();
     debugMessage(_("UNEXPECTED GDB STDERR: " + err));
     if (err == "Undefined command: \"bb\".  Try \"help\".\n")
         return;
@@ -631,7 +640,7 @@ void GdbEngine::readGdbStandardOutput()
     int newstart = 0;
     int scan = m_inbuffer.size();
 
-    m_inbuffer.append(m_gdbProc.readAllStandardOutput());
+    m_inbuffer.append(gdbProc()->readAllStandardOutput());
 
     // This can trigger when a dialog starts a nested event loop
     if (m_busy)
@@ -789,7 +798,7 @@ void GdbEngine::postCommandHelper(const GdbCommand &cmd)
             } else if (state() == InferiorRunningRequested_Kill) {
                 debugMessage(_("RUNNING REQUESTED; POSTPONING INTERRUPT (KILL PENDING)"));
             } else if (state() == InferiorRunning) {
-                showStatusMessage(tr("Stopping temporarily."), 1000);
+                showStatusMessage(tr("Stopping temporarily"), 1000);
                 interruptInferiorTemporarily();
             } else {
                 qDebug() << "ATTEMPTING TO QUEUE COMMAND IN INAPPROPRIATE STATE" << state();
@@ -802,7 +811,7 @@ void GdbEngine::postCommandHelper(const GdbCommand &cmd)
 
 void GdbEngine::flushQueuedCommands()
 {
-    showStatusMessage(tr("Processing queued commands."), 1000);
+    showStatusMessage(tr("Processing queued commands"), 1000);
     while (!m_commandsToRunOnTemporaryBreak.isEmpty()) {
         GdbCommand cmd = m_commandsToRunOnTemporaryBreak.takeFirst();
         debugMessage(_("RUNNING QUEUED COMMAND " + cmd.command + ' '
@@ -873,7 +882,7 @@ void GdbEngine::commandTimeout()
             debugMessage(_("KILLING DEBUGGER AS REQUESTED BY USER"));
             // This is an undefined state, so we just pull the emergency brake.
             manager()->watchHandler()->endCycle();
-            m_gdbProc.kill();
+            gdbProc()->kill();
         } else {
             debugMessage(_("CONTINUE DEBUGGER AS REQUESTED BY USER"));
         }
@@ -908,7 +917,7 @@ void GdbEngine::handleResultRecord(GdbResponse *response)
                 debugMessage(_("APPLYING WORKAROUND #1"));
                 showMessageBox(QMessageBox::Critical,
                     tr("Executable failed"), QString::fromLocal8Bit(msg));
-                showStatusMessage(tr("Process failed to start."));
+                showStatusMessage(tr("Process failed to start"));
                 shutdown();
             } else if (msg == "\"finish\" not meaningful in the outermost frame.") {
                 // Handle a case known to appear on gdb 6.4 symbianelf when
@@ -1091,7 +1100,7 @@ void GdbEngine::handleExecJumpToLine(const GdbResponse &response)
     // ~"242\t x *= 2;"
     //109^done"
     setState(InferiorStopped);
-    showStatusMessage(tr("Jumped. Stopped."));
+    showStatusMessage(tr("Jumped. Stopped"));
     QByteArray output = response.data.findChild("logstreamoutput").data();
     if (output.isEmpty())
         return;
@@ -1117,7 +1126,7 @@ void GdbEngine::handleExecJumpToLine(const GdbResponse &response)
 //    // file="main.cpp",fullname="/tmp/g/main.cpp",line="37"}
 //    QTC_ASSERT(state() == InferiorStopping, qDebug() << state())
 //    setState(InferiorStopped);
-//    showStatusMessage(tr("Function reached. Stopped."));
+//    showStatusMessage(tr("Function reached. Stopped"));
 //    GdbMi frame = response.data.findChild("frame");
 //    StackFrame f = parseStackFrame(frame, 0);
 //    gotoLocation(f, true);
@@ -1259,6 +1268,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
     }
 #endif
 
+    // FIXME: Replace the #ifdef by the "target" architecture
 #ifdef Q_OS_LINUX
     if (!m_entryPoint.isEmpty()) {
         GdbMi frameData = data.findChild("frame");
@@ -1281,7 +1291,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
     }
 #endif
 
-    // seen on XP after removing a breakpoint while running
+    // This was seen on XP after removing a breakpoint while running
     //  >945*stopped,reason="signal-received",signal-name="SIGTRAP",
     //  signal-meaning="Trace/breakpoint trap",thread-id="2",
     //  frame={addr="0x7c91120f",func="ntdll!DbgUiConnectToDbg",
@@ -1324,6 +1334,18 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
         }
     }
 
+    // Show return value if possible, usually with reason "function-finished".
+    // *stopped,reason="function-finished",frame={addr="0x080556da",
+    // func="testReturnValue",args=[],file="/../app.cpp",
+    // fullname="/../app.cpp",line="1611"},gdb-result-var="$1",
+    // return-value="{d = 0x808d998}",thread-id="1",stopped-threads="all",
+    // core="1"
+    GdbMi resultVar = data.findChild("gdb-result-var");
+    if (resultVar.isValid())
+        m_resultVarName = resultVar.data();
+    else
+        m_resultVarName.clear();
+
     bool initHelpers = m_debuggingHelperState == DebuggingHelperUninitialized
                        || m_debuggingHelperState == DebuggingHelperLoadTried;
     // Don't load helpers on stops triggered by signals unless it's
@@ -1333,7 +1355,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
             && reason == "signal-received") {
         QByteArray name = data.findChild("signal-name").data();
         if (name != STOP_SIGNAL
-            && (startParameters().startMode != StartRemote
+            && (startParameters().startMode != AttachToRemote
                 || name != CROSS_STOP_SIGNAL))
             initHelpers = false;
     }
@@ -1386,10 +1408,22 @@ void GdbEngine::handleStop1(const GdbMi &data)
             reloadBreakListInternal();
     }
 
-    if (reason == "breakpoint-hit") {
+    if (reason == "watchpoint-trigger") {
+        // *stopped,reason="watchpoint-trigger",wpt={number="2",exp="*0xbfffed40"},
+        // value={old="1",new="0"},frame={addr="0x00451e1b",
+        // func="QScopedPointer",args=[{name="this",value="0xbfffed40"},
+        // {name="p",value="0x0"}],file="x.h",fullname="/home/.../x.h",line="95"},
+        // thread-id="1",stopped-threads="all",core="2" 
+        GdbMi wpt = data.findChild("wpt");
+        QByteArray bpNumber = wpt.findChild("number").data();
+        QByteArray bpAddress = wpt.findChild("exp").data();
+        //QByteArray threadId = data.findChild("thread-id").data();
+        showStatusMessage(tr("Watchpoint %1 at %2 triggered:")
+            .arg(_(bpNumber), _(bpAddress)));
+    } else if (reason == "breakpoint-hit") {
         QByteArray bpNumber = data.findChild("bkptno").data();
         QByteArray threadId = data.findChild("thread-id").data();
-        showStatusMessage(tr("Stopped at breakpoint %1 in thread %2.")
+        showStatusMessage(tr("Stopped at breakpoint %1 in thread %2")
             .arg(_(bpNumber), _(threadId)));
     } else {
         QString reasontr = tr("Stopped: \"%1\"").arg(_(reason));
@@ -1400,7 +1434,7 @@ void GdbEngine::handleStop1(const GdbMi &data)
             // Ignore these as they are showing up regularly when
             // stopping debugging.
             if (name != STOP_SIGNAL
-                && (startParameters().startMode != StartRemote
+                && (startParameters().startMode != AttachToRemote
                     || name != CROSS_STOP_SIGNAL)) {
                 QString msg = tr("<p>The inferior stopped because it received a "
                     "signal from the Operating System.<p>"
@@ -1444,10 +1478,14 @@ void GdbEngine::handleStop1(const GdbMi &data)
 
     if (supportsThreads()) {
         int currentId = data.findChild("thread-id").data().toInt();
-        if (m_gdbAdapter->isTrkAdapter())
+        if (m_gdbAdapter->isTrkAdapter()) {
             m_gdbAdapter->trkReloadThreads();
-        else
-            postCommand("-thread-list-ids", CB(handleStackListThreads), currentId);
+        } else if (m_isMacGdb) {
+            postCommand("-thread-list-ids", CB(handleThreadListIds), currentId);
+        } else {
+            // This is only available in gdb 7.1+.
+            postCommand("-thread-info", CB(handleThreadInfo), currentId);
+        }
     }
 
     //
@@ -1456,7 +1494,6 @@ void GdbEngine::handleStop1(const GdbMi &data)
     manager()->reloadRegisters();
 }
 
-#ifdef Q_OS_LINUX
 void GdbEngine::handleInfoProc(const GdbResponse &response)
 {
     if (response.resultClass == GdbResultDone) {
@@ -1466,7 +1503,6 @@ void GdbEngine::handleInfoProc(const GdbResponse &response)
             maybeHandleInferiorPidChanged(re.cap(1));
     }
 }
-#endif
 
 void GdbEngine::handleShowVersion(const GdbResponse &response)
 {
@@ -1548,7 +1584,9 @@ void GdbEngine::handleHasPython(const GdbResponse &response)
             QByteArray cmd = "set environment ";
             cmd += Debugger::Constants::Internal::LD_PRELOAD_ENV_VAR;
             cmd += ' ';
-            cmd += manager()->qtDumperLibraryName().toLocal8Bit();
+            cmd += startParameters().startMode == StartRemoteGdb
+               ? startParameters().remoteDumperLib
+               : cmd += manager()->qtDumperLibraryName().toLocal8Bit();
             postCommand(cmd);
             m_debuggingHelperState = DebuggingHelperLoadTried;
         }
@@ -1629,7 +1667,7 @@ void GdbEngine::shutdown()
         m_gdbAdapter->shutdown();
         // fall-through
     case AdapterStartFailed: // Adapter "did something", but it did not help
-        if (m_gdbProc.state() == QProcess::Running) {
+        if (gdbProc()->state() == QProcess::Running) {
             m_commandsToRunOnTemporaryBreak.clear();
             postCommand("-gdb-exit", GdbEngine::ExitRequest, CB(handleGdbExit));
         } else {
@@ -1658,7 +1696,7 @@ void GdbEngine::shutdown()
         // fall-through
     case InferiorStopFailed: // Tough luck, I guess. But unreachable as of now anyway.
         setState(EngineShuttingDown);
-        m_gdbProc.kill();
+        gdbProc()->kill();
         break;
     }
 }
@@ -1698,7 +1736,7 @@ void GdbEngine::handleGdbExit(const GdbResponse &response)
         QString msg = m_gdbAdapter->msgGdbStopFailed(
             QString::fromLocal8Bit(response.data.findChild("msg").data()));
         debugMessage(_("GDB WON'T EXIT (%1); KILLING IT").arg(msg));
-        m_gdbProc.kill();
+        gdbProc()->kill();
     }
 }
 
@@ -1722,7 +1760,7 @@ void GdbEngine::abortDebugger() // called from the manager
 {
     disconnectDebuggingHelperActions();
     shutdown();
-    m_gdbProc.kill();
+    gdbProc()->kill();
 }
 
 int GdbEngine::currentFrame() const
@@ -1766,14 +1804,16 @@ AbstractGdbAdapter *GdbEngine::createAdapter(const DebuggerStartParametersPtr &s
     switch (sp->startMode) {
     case AttachCore:
         return new CoreGdbAdapter(this);
-    case StartRemote:
-        return new RemoteGdbAdapter(this, sp->toolChainType);
+    case AttachToRemote:
+        return new RemoteGdbServerAdapter(this, sp->toolChainType);
+    case StartRemoteGdb:
+        return new RemotePlainGdbAdapter(this);
     case AttachExternal:
         return new AttachGdbAdapter(this);
     default:
         if (sp->useTerminal)
             return new TermGdbAdapter(this);
-        return new PlainGdbAdapter(this);
+        return new LocalPlainGdbAdapter(this);
     }
 }
 
@@ -1817,6 +1857,7 @@ unsigned GdbEngine::debuggerCapabilities() const
         | ReloadModuleSymbolsCapability | BreakOnThrowAndCatchCapability
         | ReturnFromFunctionCapability 
         | CreateFullBacktraceCapability
+        | WatchpointCapability
         | AddWatcherCapability;
 }
 
@@ -2067,7 +2108,7 @@ void GdbEngine::setTokenBarrier()
 //
 //////////////////////////////////////////////////////////////////////
 
-void GdbEngine::breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt)
+void GdbEngine::setBreakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt)
 {
     if (!bkpt.isValid())
         return;
@@ -2115,12 +2156,19 @@ void GdbEngine::breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt
             if (ba.startsWith('<') && ba.endsWith('>'))
                 ba = ba.mid(1, ba.size() - 2);
             data->bpFuncName = _(ba);
+        } else if (child.hasName("thread")) {
+            data->bpThreadSpec = child.data();
+        } else if (child.hasName("type")) {
+            if (child.data() == "breakpoint")
+                data->type = BreakpointData::BreakpointType;
+            else // FIXME: Incomplete list of cases.
+                data->type = BreakpointData::WatchpointType;
         }
+        // This field is not present.  Contents needs to be parsed from
+        // the plain "ignore" response.
+        //else if (child.hasName("ignore"))
+        //    data->bpIgnoreCount = child.data();
     }
-    // This field is not present.  Contents needs to be parsed from
-    // the plain "ignore" response.
-    //else if (child.hasName("ignore"))
-    //    data->bpIgnoreCount = child.data();
 
     QString name;
     if (!fullName.isEmpty()) {
@@ -2145,9 +2193,8 @@ QString GdbEngine::breakLocation(const QString &file) const
     return where;
 }
 
-QByteArray GdbEngine::breakpointLocation(int index)
+QByteArray GdbEngine::breakpointLocation(const BreakpointData *data)
 {
-    const BreakpointData *data = manager()->breakHandler()->at(index);
     if (!data->funcName.isEmpty())
         return data->funcName.toLatin1();
     // In this case, data->funcName is something like '*0xdeadbeef'
@@ -2162,39 +2209,69 @@ QByteArray GdbEngine::breakpointLocation(int index)
 
 void GdbEngine::sendInsertBreakpoint(int index)
 {
+    const BreakpointData *data = manager()->breakHandler()->at(index);
     // Set up fallback in case of pending breakpoints which aren't handled
     // by the MI interface.
+    if (data->type == BreakpointData::WatchpointType) {
+        postCommand("watch *" + data->address,
+            NeedsStop | RebuildBreakpointModel,
+            CB(handleWatchInsert), index);
+        return;
+    }
+
     QByteArray cmd;
-    if (m_isMacGdb)
+    if (m_isMacGdb) {
         cmd = "-break-insert -l -1 -f ";
-    else if (m_gdbAdapter->isTrkAdapter())
+    } else if (m_gdbAdapter->isTrkAdapter()) {
         cmd = "-break-insert -h -f ";
-    else if (m_gdbVersion >= 60800)
+    } else if (m_gdbVersion >= 70000) {
+        cmd = "-break-insert ";
+        if (!data->threadSpec.isEmpty())
+            cmd += "-p " + data->threadSpec;
+        cmd += " -f ";
+    } else if (m_gdbVersion >= 60800) {
         // Probably some earlier version would work as well.
         cmd = "-break-insert -f ";
-    else
+    } else {
         cmd = "-break-insert ";
+    }
     //if (!data->condition.isEmpty())
     //    cmd += "-c " + data->condition + ' ';
-    cmd += breakpointLocation(index);
+    cmd += breakpointLocation(data);
     postCommand(cmd, NeedsStop | RebuildBreakpointModel,
         CB(handleBreakInsert1), index);
 }
 
+void GdbEngine::handleWatchInsert(const GdbResponse &response)
+{
+    int index = response.cookie.toInt();
+    if (response.resultClass == GdbResultDone) {
+        // "Hardware watchpoint 2: *0xbfffed40\n"
+        QByteArray ba = response.data.findChild("consolestreamoutput").data();
+        if (ba.startsWith("Hardware watchpoint ")) {
+            const int pos = ba.indexOf(':', 20);
+            BreakpointData *data = manager()->breakHandler()->at(index);
+            data->bpNumber = ba.mid(20, pos - 20);
+            manager()->breakHandler()->updateMarkers();
+        } else {
+            debugMessage(_("CANNOT PARSE WATCHPOINT FROM" + ba));
+        }
+    }
+}
+
 void GdbEngine::handleBreakInsert1(const GdbResponse &response)
 {
     int index = response.cookie.toInt();
-    BreakHandler *handler = manager()->breakHandler();
+    BreakpointData *data = manager()->breakHandler()->at(index);
     if (response.resultClass == GdbResultDone) {
         // Interesting only on Mac?
-        BreakpointData *data = handler->at(index);
         GdbMi bkpt = response.data.findChild("bkpt");
-        breakpointDataFromOutput(data, bkpt);
+        setBreakpointDataFromOutput(data, bkpt);
     } else {
         // Some versions of gdb like "GNU gdb (GDB) SUSE (6.8.91.20090930-2.4)"
         // know how to do pending breakpoints using CLI but not MI. So try 
         // again with MI.
-        QByteArray cmd = "break " + breakpointLocation(index);
+        QByteArray cmd = "break " + breakpointLocation(data);
         postCommand(cmd, NeedsStop | RebuildBreakpointModel,
             CB(handleBreakInsert2), index);
     }
@@ -2241,7 +2318,7 @@ void GdbEngine::handleBreakList(const GdbResponse &response)
 
 void GdbEngine::handleBreakList(const GdbMi &table)
 {
-    GdbMi body = table.findChild("body");
+    const GdbMi body = table.findChild("body");
     QList<GdbMi> bkpts;
     if (body.isValid()) {
         // Non-Mac
@@ -2259,14 +2336,19 @@ void GdbEngine::handleBreakList(const GdbMi &table)
     }
 
     BreakHandler *handler = manager()->breakHandler();
-    for (int index = 0; index != bkpts.size(); ++index) {
-        BreakpointData temp(handler);
-        breakpointDataFromOutput(&temp, bkpts.at(index));
-        int found = handler->findBreakpoint(temp);
-        if (found != -1)
-            breakpointDataFromOutput(handler->at(found), bkpts.at(index));
-        //else
-            //qDebug() << "CANNOT HANDLE RESPONSE" << bkpts.at(index).toString();
+    foreach (const GdbMi &bkpt, bkpts) {
+        BreakpointData temp;
+        setBreakpointDataFromOutput(&temp, bkpt);
+        BreakpointData *data = handler->findSimilarBreakpoint(temp);
+        //qDebug() << "\n\nGOT: " << bkpt.toString() << '\n' << temp.toString();
+        if (data) {
+            //qDebug() << "  FROM: " << data->toString();
+            setBreakpointDataFromOutput(data, bkpt);
+            //qDebug() << "  TO: " << data->toString();
+        } else {
+            //qDebug() << "  NOTHING SUITABLE FOUND";
+            debugMessage(_("CANNOT FIND BP: " + bkpt.toString()));
+        }
     }
 
     m_breakListOutdated = false;
@@ -2294,7 +2376,7 @@ void GdbEngine::handleBreakIgnore(const GdbResponse &response)
     //
     // gdb 6.3 does not produce any console output
     BreakHandler *handler = manager()->breakHandler();
-    BreakpointData *data = handler->findBreakpoint(bpNumber);
+    BreakpointData *data = handler->findBreakpointByNumber(bpNumber);
     if (response.resultClass == GdbResultDone && data) {
         QString msg = _(response.data.findChild("consolestreamoutput").data());
         //if (msg.contains(__("Will stop next time breakpoint"))) {
@@ -2312,7 +2394,7 @@ void GdbEngine::handleBreakCondition(const GdbResponse &response)
 {
     int bpNumber = response.cookie.toInt();
     BreakHandler *handler = manager()->breakHandler();
-    BreakpointData *data = handler->findBreakpoint(bpNumber);
+    BreakpointData *data = handler->findBreakpointByNumber(bpNumber);
     if (response.resultClass == GdbResultDone) {
         // We just assume it was successful. Otherwise we had to parse
         // the output stream data.
@@ -2395,7 +2477,7 @@ void GdbEngine::handleBreakInfo(const GdbResponse &response)
         // constructor.
         const int bpNumber = response.cookie.toInt();
         const BreakHandler *handler = manager()->breakHandler();
-        BreakpointData *data = handler->findBreakpoint(bpNumber);
+        BreakpointData *data = handler->findBreakpointByNumber(bpNumber);
         if (data) {
             QString str = QString::fromLocal8Bit(
                 response.data.findChild("consolestreamoutput").data());
@@ -2412,7 +2494,7 @@ void GdbEngine::handleInfoLine(const GdbResponse &response)
         // <_Z10testQStackv+142>.\n"
         const int bpNumber = response.cookie.toInt();
         const BreakHandler *handler = manager()->breakHandler();
-        BreakpointData *data = handler->findBreakpoint(bpNumber);
+        BreakpointData *data = handler->findBreakpointByNumber(bpNumber);
         if (!data)
             return;
         QByteArray ba = response.data.findChild("consolestreamoutput").data();
@@ -2429,7 +2511,7 @@ void GdbEngine::attemptBreakpointSynchronization()
 {
     QTC_ASSERT(!m_sourcesListUpdating,
         qDebug() << "SOURCES LIST CURRENTLY UPDATING"; return);
-    debugMessage(tr("ATTEMPT BREAKPOINT SYNC"));
+    debugMessage(_("ATTEMPT BREAKPOINT SYNC"));
 
     switch (state()) {
     case InferiorStarting:
@@ -2440,6 +2522,7 @@ void GdbEngine::attemptBreakpointSynchronization()
         break;
     default:
         //qDebug() << "attempted breakpoint sync in state" << state();
+        debugMessage(_("... NOT POSSIBLE IN CURRENT STATE"));
         return;
     }
 
@@ -2495,11 +2578,14 @@ void GdbEngine::attemptBreakpointSynchronization()
 
     foreach (BreakpointData *data, handler->takeRemovedBreakpoints()) {
         QByteArray bpNumber = data->bpNumber;
-        debugMessage(_("DELETING BP " + bpNumber + " IN "
-            + data->markerFileName().toLocal8Bit()));
-        if (!bpNumber.trimmed().isEmpty())
+        if (!bpNumber.trimmed().isEmpty()) {
+            debugMessage(_("DELETING BP " + bpNumber + " IN "
+                + data->markerFileName().toLocal8Bit()));
             postCommand("-break-delete " + bpNumber,
                 NeedsStop | RebuildBreakpointModel);
+        } else {
+            debugMessage(_("QUIETLY REMOVING UNNUMBERED BREAKPOINT"));
+        }
         delete data;
     }
 
@@ -2524,7 +2610,8 @@ void GdbEngine::attemptBreakpointSynchronization()
             else // Because gdb won't do both changes at a time anyway.
             if (data->ignoreCount != data->bpIgnoreCount) {
                 // Update ignorecount if needed.
-                postCommand("ignore " + data->bpNumber + ' ' + data->ignoreCount,
+                QByteArray ic = QByteArray::number(data->ignoreCount.toInt());
+                postCommand("ignore " + data->bpNumber + ' ' + ic,
                     NeedsStop | RebuildBreakpointModel,
                     CB(handleBreakIgnore), data->bpNumber.toInt());
                 continue;
@@ -2532,10 +2619,19 @@ void GdbEngine::attemptBreakpointSynchronization()
             if (!data->enabled && data->bpEnabled) {
                 postCommand("-break-disable " + data->bpNumber,
                     NeedsStop | RebuildBreakpointModel,
-                    CB(handleBreakInfo));
+                    CB(handleBreakDisable), data->bpNumber.toInt());
                 data->bpEnabled = false;
                 continue;
             }
+            if (data->threadSpec != data->bpThreadSpec && !data->bpNumber.isEmpty()) {
+                // The only way to change this seems to be to re-set the bp completely.
+                //qDebug() << "FIXME: THREAD: " << data->threadSpec << data->bpThreadSpec;
+                data->bpThreadSpec.clear();
+                postCommand("-break-delete " + data->bpNumber,
+                    NeedsStop | RebuildBreakpointModel);
+                sendInsertBreakpoint(index);
+                continue;
+            }
             if (data->bpAddress.startsWith("0x")
                     && data->bpCorrectedLineNumber.isEmpty()) {
                 // Prevent endless loop.
@@ -2570,7 +2666,7 @@ void GdbEngine::loadAllSymbols()
     reloadModulesInternal();
 }
 
-QList<Symbol> GdbEngine::moduleSymbols(const QString &moduleName)
+void GdbEngine::requestModuleSymbols(const QString &moduleName)
 {
     QList<Symbol> rc;
     bool success = false;
@@ -2601,7 +2697,7 @@ QList<Symbol> GdbEngine::moduleSymbols(const QString &moduleName)
     } while (false);
     if (!success)
         qWarning("moduleSymbols: %s\n", qPrintable(errorMessage));
-    return rc;
+    manager()->showModuleSymbols(moduleName, rc);
 }
 
 void GdbEngine::reloadModules()
@@ -2888,10 +2984,47 @@ void GdbEngine::handleStackSelectFrame(const GdbResponse &response)
     reloadRegisters();
 }
 
-void GdbEngine::handleStackListThreads(const GdbResponse &response)
+void GdbEngine::handleThreadInfo(const GdbResponse &response)
+{
+    int id = response.cookie.toInt();
+    if (response.resultClass == GdbResultDone) {
+        // ^done,threads=[{id="1",target-id="Thread 0xb7fdc710 (LWP 4264)",
+        // frame={level="0",addr="0x080530bf",func="testQString",args=[],
+        // file="/.../app.cpp",fullname="/../app.cpp",line="1175"},
+        // state="stopped",core="0"}],current-thread-id="1"
+        const QList<GdbMi> items = response.data.findChild("threads").children();
+        QList<ThreadData> threads;
+        for (int index = 0, n = items.size(); index != n; ++index) {
+            bool ok = false;
+            const GdbMi item = items.at(index);
+            const GdbMi frame = item.findChild("frame");
+            ThreadData thread;
+            thread.id = item.findChild("id").data().toInt();
+            thread.targetId = item.findChild("target-id").data().toInt();
+            thread.core = QString::fromLatin1(item.findChild("core").data());
+            thread.state = QString::fromLatin1(item.findChild("state").data());
+            thread.address = frame.findChild("addr").data().toULongLong(&ok, 0);
+            thread.function = QString::fromLatin1(frame.findChild("func").data());
+            thread.fileName = QString::fromLatin1(frame.findChild("fullname").data());
+            thread.lineNumber = frame.findChild("line").data().toInt();
+            threads.append(thread);
+        }
+        ThreadsHandler *threadsHandler = manager()->threadsHandler();
+        threadsHandler->setThreads(threads);
+        int currentIndex = response.data.findChild("current-thread-id").data().toInt();
+        threadsHandler->setCurrentThread(currentIndex);
+    } else {
+        // Fall back for older versions: Try to get at least a list
+        // of running threads.
+        postCommand("-thread-list-ids", CB(handleThreadListIds), id);
+    }
+}
+
+void GdbEngine::handleThreadListIds(const GdbResponse &response)
 {
     int id = response.cookie.toInt();
     // "72^done,{thread-ids={thread-id="2",thread-id="1"},number-of-threads="2"}
+    // In gdb 7.1+ additionally: current-thread-id="1"
     const QList<GdbMi> items = response.data.findChild("thread-ids").children();
     QList<ThreadData> threads;
     int currentIndex = -1;
@@ -3912,7 +4045,7 @@ void GdbEngine::gotoLocation(const StackFrame &frame, bool setMarker)
 
 bool GdbEngine::startGdb(const QStringList &args, const QString &gdb, const QString &settingsIdHint)
 {
-    m_gdbProc.disconnect(); // From any previous runs
+    gdbProc()->disconnect(); // From any previous runs
 
     m_gdb = QString::fromLatin1(qgetenv("QTC_DEBUGGER_PATH"));
     if (m_gdb.isEmpty())
@@ -3938,7 +4071,7 @@ bool GdbEngine::startGdb(const QStringList &args, const QString &gdb, const QStr
         const QString winPythonVersion = QLatin1String(winPythonVersionC);
         const QDir dir = fi.absoluteDir();
         if (dir.exists(winPythonVersion)) {
-            QProcessEnvironment environment = m_gdbProc.processEnvironment();
+            QProcessEnvironment environment = gdbProc()->processEnvironment();
             const QString pythonPathVariable = QLatin1String("PYTHONPATH");
             // Check for existing values.
             if (environment.contains(pythonPathVariable)) {
@@ -3951,31 +4084,31 @@ bool GdbEngine::startGdb(const QStringList &args, const QString &gdb, const QStr
                 environment.insert(pythonPathVariable, pythonPath);
                 manager()->showDebuggerOutput(LogMisc,
                     _("Python path: %1").arg(pythonPath));
-                m_gdbProc.setProcessEnvironment(environment);
+                gdbProc()->setProcessEnvironment(environment);
             }
             foundPython = true;
         }
     }
     if (!foundPython) {
         debugMessage(_("UNSUPPORTED GDB %1 DOES NOT HAVE PYTHON.").arg(m_gdb));
-        showStatusMessage(_("Gdb at %1 does not have python.").arg(m_gdb));
+        showStatusMessage(_("Gdb at %1 does not have python").arg(m_gdb));
     }
 #endif
 
-    connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)),
+    connect(gdbProc(), SIGNAL(error(QProcess::ProcessError)),
         SLOT(handleGdbError(QProcess::ProcessError)));
-    connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)),
+    connect(gdbProc(), SIGNAL(finished(int, QProcess::ExitStatus)),
         SLOT(handleGdbFinished(int, QProcess::ExitStatus)));
-    connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()),
+    connect(gdbProc(), SIGNAL(readyReadStandardOutput()),
         SLOT(readGdbStandardOutput()));
-    connect(&m_gdbProc, SIGNAL(readyReadStandardError()),
+    connect(gdbProc(), SIGNAL(readyReadStandardError()),
         SLOT(readGdbStandardError()));
 
-    m_gdbProc.start(m_gdb, gdbArgs);
+    gdbProc()->start(m_gdb, gdbArgs);
 
-    if (!m_gdbProc.waitForStarted()) {
+    if (!gdbProc()->waitForStarted()) {
         const QString msg = tr("Unable to start gdb '%1': %2")
-            .arg(m_gdb, m_gdbProc.errorString());
+            .arg(m_gdb, gdbProc()->errorString());
         handleAdapterStartFailed(msg, settingsIdHint);
         return false;
     }
@@ -4097,7 +4230,7 @@ void GdbEngine::handleGdbError(QProcess::ProcessError error)
     case QProcess::WriteError:
     case QProcess::Timedout:
     default:
-        m_gdbProc.kill();
+        gdbProc()->kill();
         setState(EngineShuttingDown, true);
         showMessageBox(QMessageBox::Critical, tr("Gdb I/O Error"),
                        errorMessage(error));
@@ -4213,7 +4346,7 @@ void GdbEngine::handleAdapterCrashed(const QString &msg)
     setState(AdapterStartFailed, true);
 
     // No point in being friendly here ...
-    m_gdbProc.kill();
+    gdbProc()->kill();
 
     if (!msg.isEmpty())
         showMessageBox(QMessageBox::Critical, tr("Adapter crashed"), msg);
index 2093e54..eb36648 100644 (file)
@@ -33,6 +33,7 @@
 #include "idebuggerengine.h"
 #include "debuggermanager.h" // only for StartParameters
 #include "gdbmi.h"
+#include "localgdbprocess.h"
 #include "watchutils.h"
 
 #include <QtCore/QByteArray>
@@ -41,7 +42,6 @@
 #include <QtCore/QMap>
 #include <QtCore/QMultiMap>
 #include <QtCore/QObject>
-#include <QtCore/QProcess>
 #include <QtCore/QPoint>
 #include <QtCore/QSet>
 #include <QtCore/QTextCodec>
@@ -60,6 +60,7 @@ class DebuggerManager;
 namespace Internal {
 
 class AbstractGdbAdapter;
+class AbstractGdbProcess;
 class GdbResponse;
 class GdbMi;
 
@@ -69,8 +70,8 @@ class DisassemblerAgentCookie;
 
 class AttachGdbAdapter;
 class CoreGdbAdapter;
-class PlainGdbAdapter;
-class RemoteGdbAdapter;
+class LocalPlainGdbAdapter;
+class RemoteGdbServerAdapter;
 class TrkGdbAdapter;
 
 enum DebuggingHelperState
@@ -95,11 +96,13 @@ public:
 
 private:
     friend class AbstractGdbAdapter;
+    friend class AbstractPlainGdbAdapter;
     friend class AttachGdbAdapter;
     friend class CoreGdbAdapter;
-    friend class PlainGdbAdapter;
+    friend class LocalPlainGdbAdapter;
     friend class TermGdbAdapter;
-    friend class RemoteGdbAdapter;
+    friend class RemoteGdbServerAdapter;
+    friend class RemotePlainGdbAdapter;
     friend class TrkGdbAdapter;
 
 private: ////////// General Interface //////////
@@ -165,9 +168,12 @@ private:
     QByteArray m_inbuffer;
     bool m_busy;
 
-    QProcess m_gdbProc;
     AbstractGdbAdapter *m_gdbAdapter;
 
+    // Name of the convenience variable containing the last
+    // known function return value.
+    QByteArray m_resultVarName;
+
 private: ////////// Gdb Command Management //////////
 
     public: // Otherwise the Qt flag macros are unhappy.
@@ -319,12 +325,9 @@ private: ////////// Inferior Management //////////
     qint64 inferiorPid() const { return m_manager->inferiorPid(); }
     void handleInferiorPidChanged(qint64 pid) { manager()->notifyInferiorPidChanged(pid); }
     void maybeHandleInferiorPidChanged(const QString &pid);
-
-#ifdef Q_OS_LINUX
     void handleInfoProc(const GdbResponse &response);
 
     QByteArray m_entryPoint;
-#endif
     QFutureInterface<void> *m_progress;
 
 private: ////////// View & Data Stuff //////////
@@ -345,10 +348,11 @@ private: ////////// View & Data Stuff //////////
     void handleBreakInsert2(const GdbResponse &response);
     void handleBreakCondition(const GdbResponse &response);
     void handleBreakInfo(const GdbResponse &response);
+    void handleWatchInsert(const GdbResponse &response);
     void handleInfoLine(const GdbResponse &response);
     void extractDataFromInfoBreak(const QString &output, BreakpointData *data);
-    void breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt);
-    QByteArray breakpointLocation(int index);
+    void setBreakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt);
+    QByteArray breakpointLocation(const BreakpointData *data);
     void sendInsertBreakpoint(int index);
     QString breakLocation(const QString &file) const;
     void reloadBreakListInternal();
@@ -358,7 +362,7 @@ private: ////////// View & Data Stuff //////////
     //
     virtual void loadSymbols(const QString &moduleName);
     virtual void loadAllSymbols();
-    virtual QList<Symbol> moduleSymbols(const QString &moduleName);
+    virtual void requestModuleSymbols(const QString &moduleName);
     virtual void reloadModules();
     void reloadModulesInternal();
     void handleModulesList(const GdbResponse &response);
@@ -429,7 +433,8 @@ private: ////////// View & Data Stuff //////////
     void handleStackListFrames(const GdbResponse &response);
     void handleStackSelectThread(const GdbResponse &response);
     void handleStackSelectFrame(const GdbResponse &response);
-    void handleStackListThreads(const GdbResponse &response);
+    void handleThreadListIds(const GdbResponse &response);
+    void handleThreadInfo(const GdbResponse &response);
     Q_SLOT void reloadStack(bool forceGotoLocation);
     Q_SLOT virtual void reloadFullStack();
     int currentFrame() const;
@@ -479,6 +484,7 @@ private: ////////// View & Data Stuff //////////
     void handleDebuggingHelperValue3Classic(const GdbResponse &response);
     void handleDebuggingHelperEditValue(const GdbResponse &response);
     void handleDebuggingHelperSetup(const GdbResponse &response);
+    void handleDebuggingHelperVersionCheckClassic(const GdbResponse &response);
 
     Q_SLOT void createFullBacktrace();
     void handleCreateFullBacktrace(const GdbResponse &response);
@@ -524,6 +530,7 @@ private: ////////// Convenience Functions //////////
         int buttons = 0);
     void debugMessage(const QString &msg);
     QMainWindow *mainWindow() const;
+    AbstractGdbProcess *gdbProc() const;
 
     static QString m_toolTipExpression;
     static QPoint m_toolTipPos;
diff --git a/src/plugins/debugger/gdb/localgdbprocess.cpp b/src/plugins/debugger/gdb/localgdbprocess.cpp
new file mode 100644 (file)
index 0000000..60bb343
--- /dev/null
@@ -0,0 +1,108 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "localgdbprocess.h"
+
+namespace Debugger {
+namespace Internal {
+
+LocalGdbProcess::LocalGdbProcess(QObject *parent) : AbstractGdbProcess(parent)
+{
+    connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)),
+            this, SIGNAL(error(QProcess::ProcessError)));
+    connect(&m_gdbProc, SIGNAL(finished(int,QProcess::ExitStatus)),
+            this, SIGNAL(finished(int,QProcess::ExitStatus)));
+    connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()),
+            this, SIGNAL(readyReadStandardOutput()));
+    connect(&m_gdbProc, SIGNAL(readyReadStandardError()),
+            this, SIGNAL(readyReadStandardError()));
+}
+
+QByteArray LocalGdbProcess::readAllStandardOutput()
+{
+    return m_gdbProc.readAllStandardOutput();
+}
+
+QByteArray LocalGdbProcess::readAllStandardError()
+{
+    return m_gdbProc.readAllStandardError();
+}
+
+void LocalGdbProcess::start(const QString &cmd, const QStringList &args)
+{
+    m_gdbProc.start(cmd, args);
+}
+
+bool LocalGdbProcess::waitForStarted()
+{
+    return m_gdbProc.waitForStarted();
+}
+
+qint64 LocalGdbProcess::write(const QByteArray &data)
+{
+    return m_gdbProc.write(data);
+}
+
+void LocalGdbProcess::kill()
+{
+    m_gdbProc.kill();
+}
+
+QProcess::ProcessState LocalGdbProcess::state() const
+{
+    return m_gdbProc.state();
+}
+
+QString LocalGdbProcess::errorString() const
+{
+    return m_gdbProc.errorString();
+}
+
+QProcessEnvironment LocalGdbProcess::processEnvironment() const
+{
+    return m_gdbProc.processEnvironment();
+}
+
+void LocalGdbProcess::setProcessEnvironment(const QProcessEnvironment &env)
+{
+    m_gdbProc.setProcessEnvironment(env);
+}
+
+void LocalGdbProcess::setEnvironment(const QStringList &env)
+{
+    m_gdbProc.setEnvironment(env);
+}
+
+void LocalGdbProcess::setWorkingDirectory(const QString &dir)
+{
+    m_gdbProc.setWorkingDirectory(dir);
+}
+
+} // namespace Internal
+} // namespace Debugger
diff --git a/src/plugins/debugger/gdb/localgdbprocess.h b/src/plugins/debugger/gdb/localgdbprocess.h
new file mode 100644 (file)
index 0000000..3ab5773
--- /dev/null
@@ -0,0 +1,66 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef LOCALGDBPROCESS_H
+#define LOCALGDBPROCESS_H
+
+#include "abstractgdbprocess.h"
+
+namespace Debugger {
+namespace Internal {
+
+class LocalGdbProcess : public AbstractGdbProcess
+{
+public:
+    explicit LocalGdbProcess(QObject *parent = 0);
+
+    virtual QByteArray readAllStandardOutput();
+    virtual QByteArray readAllStandardError();
+
+    virtual void start(const QString &cmd, const QStringList &args);
+    virtual bool waitForStarted();
+    virtual qint64 write(const QByteArray &data);
+    virtual void kill();
+
+    virtual QProcess::ProcessState state() const;
+    virtual QString errorString() const;
+
+    virtual QProcessEnvironment processEnvironment() const;
+    virtual void setProcessEnvironment(const QProcessEnvironment &env);
+    virtual void setEnvironment(const QStringList &env);
+    virtual void setWorkingDirectory(const QString &dir);
+
+private:
+    QProcess m_gdbProc;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // LOCALGDBPROCESS_H
diff --git a/src/plugins/debugger/gdb/localplaingdbadapter.cpp b/src/plugins/debugger/gdb/localplaingdbadapter.cpp
new file mode 100644 (file)
index 0000000..7589c62
--- /dev/null
@@ -0,0 +1,168 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "localplaingdbadapter.h"
+
+#include "gdbengine.h"
+#include "procinterrupt.h"
+#include "debuggerstringutils.h"
+
+#include <utils/qtcassert.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QProcess>
+#include <QtGui/QMessageBox>
+
+namespace Debugger {
+namespace Internal {
+
+///////////////////////////////////////////////////////////////////////
+//
+// PlainGdbAdapter
+//
+///////////////////////////////////////////////////////////////////////
+
+LocalPlainGdbAdapter::LocalPlainGdbAdapter(GdbEngine *engine, QObject *parent)
+    : AbstractPlainGdbAdapter(engine, parent)
+{
+    // Output
+    connect(&m_outputCollector, SIGNAL(byteDelivery(QByteArray)),
+        engine, SLOT(readDebugeeOutput(QByteArray)));
+}
+
+AbstractGdbAdapter::DumperHandling LocalPlainGdbAdapter::dumperHandling() const
+{
+    // LD_PRELOAD fails for System-Qt on Mac.
+#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
+    return DumperLoadedByGdb;
+#else
+    return DumperLoadedByGdbPreload;
+#endif
+}
+
+void LocalPlainGdbAdapter::startAdapter()
+{
+    QTC_ASSERT(state() == EngineStarting, qDebug() << state());
+    setState(AdapterStarting);
+    debugMessage(_("TRYING TO START ADAPTER"));
+
+    QStringList gdbArgs;
+
+    if (!m_outputCollector.listen()) {
+        emit adapterStartFailed(tr("Cannot set up communication with child process: %1")
+                .arg(m_outputCollector.errorString()), QString());
+        return;
+    }
+    gdbArgs.append(_("--tty=") + m_outputCollector.serverName());
+
+    if (!startParameters().workingDirectory.isEmpty())
+        m_gdbProc.setWorkingDirectory(startParameters().workingDirectory);
+    if (!startParameters().environment.isEmpty())
+        m_gdbProc.setEnvironment(startParameters().environment);
+
+    if (!m_engine->startGdb(gdbArgs)) {
+        m_outputCollector.shutdown();
+        return;
+    }
+
+    emit adapterStarted();
+    checkForReleaseBuild();
+}
+
+void LocalPlainGdbAdapter::checkForReleaseBuild()
+{
+    // Quick check for a "release" build
+    QProcess proc;
+    QStringList args;
+    args.append(_("-h"));
+    args.append(_("-j"));
+    args.append(_(".debug_info"));
+    args.append(startParameters().executable);
+    proc.start(_("objdump"), args);
+    proc.closeWriteChannel();
+    QTC_ASSERT(proc.waitForStarted(), qDebug() << "UNABLE TO RUN OBJDUMP");
+    proc.waitForFinished();
+    QByteArray ba = proc.readAllStandardOutput();
+    // This should yield something like
+    // "debuggertest:     file format elf32-i386\n\n"
+    // "Sections:\nIdx Name          Size      VMA       LMA       File off  Algn\n"
+    // "30 .debug_info   00087d36  00000000  00000000  0006bbd5  2**0\n"
+    // " CONTENTS, READONLY, DEBUGGING"
+    if (ba.contains("Sections:") && !ba.contains(".debug_info")) {
+        m_engine->showMessageBox(QMessageBox::Information, "Warning",
+           tr("This does not seem to be a \"Debug\" build.\n"
+              "Setting breakpoints by file name and line number may fail."));
+    }
+}
+
+void LocalPlainGdbAdapter::interruptInferior()
+{
+    const qint64 attachedPID = m_engine->inferiorPid();
+    if (attachedPID <= 0) {
+        debugMessage(_("TRYING TO INTERRUPT INFERIOR BEFORE PID WAS OBTAINED"));
+        return;
+    }
+
+    if (!interruptProcess(attachedPID))
+        debugMessage(_("CANNOT INTERRUPT %1").arg(attachedPID));
+}
+
+void LocalPlainGdbAdapter::shutdown()
+{
+    debugMessage(_("PLAIN ADAPTER SHUTDOWN %1").arg(state()));
+    m_outputCollector.shutdown();
+}
+
+QByteArray LocalPlainGdbAdapter::execFilePath() const
+{
+    return QFileInfo(startParameters().executable)
+            .absoluteFilePath().toLocal8Bit();
+}
+
+bool LocalPlainGdbAdapter::infoTargetNecessary() const
+{
+#ifdef Q_OS_LINUX
+    return true;
+#else
+    return false;
+#endif
+}
+
+QByteArray LocalPlainGdbAdapter::toLocalEncoding(const QString &s) const
+{
+    return s.toLocal8Bit();
+}
+
+QString LocalPlainGdbAdapter::fromLocalEncoding(const QByteArray &b) const
+{
+    return QString::fromLocal8Bit(b);
+}
+
+} // namespace Internal
+} // namespace Debugger
similarity index 77%
rename from src/plugins/debugger/gdb/plaingdbadapter.h
rename to src/plugins/debugger/gdb/localplaingdbadapter.h
index 83e6aff..12a0bc8 100644 (file)
@@ -30,7 +30,9 @@
 #ifndef DEBUGGER_PLAINGDBADAPTER_H
 #define DEBUGGER_PLAINGDBADAPTER_H
 
-#include "abstractgdbadapter.h"
+#include "abstractplaingdbadapter.h"
+
+#include "abstractgdbprocess.h"
 
 #include <outputcollector.h>
 
@@ -43,30 +45,29 @@ namespace Internal {
 //
 ///////////////////////////////////////////////////////////////////////
 
-class PlainGdbAdapter : public AbstractGdbAdapter
+class LocalPlainGdbAdapter : public AbstractPlainGdbAdapter
 {
     Q_OBJECT
 
 public:
-    PlainGdbAdapter(GdbEngine *engine, QObject *parent = 0);
+    LocalPlainGdbAdapter(GdbEngine *engine, QObject *parent = 0);
 
     virtual DumperHandling dumperHandling() const;
 
     void startAdapter();
-    void startInferior();
-    void startInferiorPhase2();
     void interruptInferior();
     void shutdown();
-    const char *inferiorShutdownCommand() const { return "kill"; }
+    AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
 
 private:
-    void handleFileExecAndSymbols(const GdbResponse &response);
-    void handleExecRun(const GdbResponse &response);
-#ifdef Q_OS_LINUX
-    void handleInfoTarget(const GdbResponse &response);
-#endif
+    virtual QByteArray execFilePath() const;
+    virtual bool infoTargetNecessary() const;
+    virtual QByteArray toLocalEncoding(const QString &s) const;
+    virtual QString fromLocalEncoding(const QByteArray &b) const;
+    void checkForReleaseBuild();
 
     OutputCollector m_outputCollector;
+    LocalGdbProcess m_gdbProc;
 };
 
 } // namespace Internal
index 3edf269..fa46242 100644 (file)
@@ -85,8 +85,12 @@ void GdbEngine::updateLocalsPython(const QByteArray &varList)
         options += "defaults,";
     options.chop(1);
 
+    QByteArray resultVar;
+    if (!m_resultVarName.isEmpty())
+        resultVar = "resultvarname:" + m_resultVarName + ' ';
+
     postCommand("bb options:" + options + " vars:" + varList + ' '
-            + expanded + " watchers:" + watchers.toHex(),
+            + resultVar + expanded + " watchers:" + watchers.toHex(),
         WatchUpdate, CB(handleStackFramePython));
 }
 
@@ -114,8 +118,8 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response)
         //qDebug() << "SECOND CHUNK: " << out;
         int pos = out.indexOf("data=");
         if (pos != 0) {
-            qDebug() << "DISCARDING JUNK AT BEGIN OF RESPONSE: "
-                << out.left(pos);
+            debugMessage(_("DISCARDING JUNK AT BEGIN OF RESPONSE: "
+                + out.left(pos)));
             out = out.mid(pos);
         }
         GdbMi all;
@@ -197,7 +201,7 @@ void GdbEngine::updateAllPython()
     if (m_gdbAdapter->isTrkAdapter())
         m_gdbAdapter->trkReloadThreads();
     else
-        postCommand("-thread-list-ids", CB(handleStackListThreads), 0);
+        postCommand("-thread-list-ids", CB(handleThreadListIds), 0);
     manager()->reloadRegisters();
     updateLocals();
 }
diff --git a/src/plugins/debugger/gdb/remotegdbprocess.cpp b/src/plugins/debugger/gdb/remotegdbprocess.cpp
new file mode 100644 (file)
index 0000000..6e51a3f
--- /dev/null
@@ -0,0 +1,309 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "remotegdbprocess.h"
+
+#include "remoteplaingdbadapter.h"
+
+namespace Debugger {
+namespace Internal {
+
+RemoteGdbProcess::RemoteGdbProcess(const Core::SshServerInfo &server,
+    RemotePlainGdbAdapter *adapter, QObject *parent)
+    : AbstractGdbProcess(parent), m_serverInfo(server), m_adapter(adapter)
+{
+
+}
+
+QByteArray RemoteGdbProcess::readAllStandardOutput()
+{
+    QByteArray output = m_gdbOutput;
+    m_gdbOutput.clear();
+    return output;
+}
+
+QByteArray RemoteGdbProcess::readAllStandardError()
+{
+    QByteArray errorOutput = m_errorOutput;
+    m_errorOutput.clear();
+    return errorOutput;
+}
+
+void RemoteGdbProcess::start(const QString &cmd, const QStringList &args)
+{
+    m_gdbConn = Core::InteractiveSshConnection::create(m_serverInfo);
+    m_appOutputConn = Core::InteractiveSshConnection::create(m_serverInfo);
+    m_errOutputConn = Core::InteractiveSshConnection::create(m_serverInfo);
+    m_command = cmd;
+    m_cmdArgs = args;
+    m_errOutputConn->start();
+    m_appOutputConn->start();
+    m_gdbConn->start();
+ }
+
+bool RemoteGdbProcess::waitForStarted()
+{
+    if (!waitForInputReady(m_appOutputConn))
+        return false;
+    if (!sendAndWaitForEcho(m_appOutputConn, readerCmdLine(AppOutputFile)))
+        return false;
+    if (!waitForInputReady(m_errOutputConn))
+        return false;
+    if (!sendAndWaitForEcho(m_errOutputConn, readerCmdLine(ErrOutputFile)))
+        return false;
+    if (!waitForInputReady(m_gdbConn))
+        return false;
+    connect(m_appOutputConn.data(), SIGNAL(remoteOutputAvailable()),
+            this, SLOT(handleAppOutput()));
+    connect(m_errOutputConn.data(), SIGNAL(remoteOutputAvailable()),
+            this, SLOT(handleErrOutput()));
+    connect(m_gdbConn.data(), SIGNAL(remoteOutputAvailable()),
+            this, SLOT(handleGdbOutput()));
+    m_gdbStarted = false;
+    m_gdbCmdLine = "stty -echo && DISPLAY=:0.0 " + m_command.toUtf8() + ' '
+        + m_cmdArgs.join(QLatin1String(" ")).toUtf8()
+        + " -tty=" + AppOutputFile + " 2>" + ErrOutputFile + '\n';
+    if (!m_wd.isEmpty())
+        m_gdbCmdLine.prepend("cd " + m_wd.toUtf8() + " && ");
+    if (sendInput(m_gdbCmdLine) != m_gdbCmdLine.count())
+        return false;
+
+    return true;
+}
+
+qint64 RemoteGdbProcess::write(const QByteArray &data)
+{
+    if (!m_gdbStarted || !m_inputToSend.isEmpty() || !m_lastSeqNr.isEmpty()) {
+        m_inputToSend.enqueue(data);
+        return data.size();
+    } else {
+        return sendInput(data);
+    }
+}
+
+void RemoteGdbProcess::kill()
+{
+    stopReaders();
+    Core::InteractiveSshConnection::Ptr controlConn
+        = Core::InteractiveSshConnection::create(m_serverInfo);
+    if (!controlConn->hasError()) {
+        if (controlConn->start())
+            controlConn->sendInput("pkill -x gdb\r\n");
+    }
+
+    m_gdbConn->quit();
+    emit finished(0, QProcess::CrashExit);
+}
+
+QProcess::ProcessState RemoteGdbProcess::state() const
+{
+    return m_gdbStarted ? QProcess::Running : QProcess::Starting;
+}
+
+QString RemoteGdbProcess::errorString() const
+{
+    return m_gdbConn ? m_gdbConn->error() : QString();
+}
+
+void RemoteGdbProcess::handleGdbOutput()
+{
+    m_currentGdbOutput
+        += removeCarriageReturn(m_gdbConn->waitForRemoteOutput(0));
+#if 0
+    qDebug("%s: complete unread output is '%s'", Q_FUNC_INFO, m_currentGdbOutput.data());
+#endif
+    if (checkForGdbExit(m_currentGdbOutput)) {
+        m_currentGdbOutput.clear();
+        return;
+    }
+
+    if (!m_currentGdbOutput.endsWith('\n'))
+        return;
+
+    if (!m_gdbStarted) {
+        const int index = m_currentGdbOutput.indexOf(m_gdbCmdLine);
+        if (index != -1)
+            m_currentGdbOutput.remove(index, m_gdbCmdLine.size());
+        // Note: We can't guarantee that we will match the command line,
+        // because the remote terminal sometimes inserts control characters.
+        // Otherwise we could set m_gdbStarted here.
+    }
+
+    m_gdbStarted = true;
+
+    if (m_currentGdbOutput.contains(m_lastSeqNr + '^'))
+        m_lastSeqNr.clear();
+
+    if (m_lastSeqNr.isEmpty() && !m_inputToSend.isEmpty()) {
+#if 0
+        qDebug("Sending queued command: %s", m_inputToSend.head().data());
+#endif
+        sendInput(m_inputToSend.dequeue());
+    }
+
+    if (!m_currentGdbOutput.isEmpty()) {
+        const int startPos
+            = m_gdbOutput.isEmpty() ? findAnchor(m_currentGdbOutput) : 0;
+        if (startPos != -1) {
+            m_gdbOutput += m_currentGdbOutput.mid(startPos);
+            m_currentGdbOutput.clear();
+            emit readyReadStandardOutput();
+        }
+    }
+}
+
+QProcessEnvironment RemoteGdbProcess::processEnvironment() const
+{
+    return QProcessEnvironment(); // TODO: Provide actual environment.
+}
+
+void RemoteGdbProcess::setProcessEnvironment(const QProcessEnvironment & /* env */)
+{
+    // TODO: Do something.
+}
+
+void RemoteGdbProcess::setEnvironment(const QStringList & /* env */)
+{
+    // TODO: Do something.
+}
+
+void RemoteGdbProcess::setWorkingDirectory(const QString &dir)
+{
+    m_wd = dir;
+}
+
+int RemoteGdbProcess::findAnchor(const QByteArray &data) const
+{
+    for (int pos = 0; pos < data.count(); ++pos) {
+        const char c = data.at(pos);
+        if (isdigit(c) || c == '*' || c == '+' || c == '=' || c == '~'
+            || c == '@' || c == '&' || c == '^')
+            return pos;
+    }
+    return -1;
+}
+
+qint64 RemoteGdbProcess::sendInput(const QByteArray &data)
+{
+    int pos;
+    for (pos = 0; pos < data.size(); ++pos)
+        if (!isdigit(data.at(pos)))
+            break;
+    m_lastSeqNr = data.left(pos);
+    return m_gdbConn->sendInput(data) ? data.size() : 0;
+}
+
+void RemoteGdbProcess::handleAppOutput()
+{
+    m_adapter->handleApplicationOutput(m_appOutputConn->waitForRemoteOutput(0));
+}
+
+void RemoteGdbProcess::handleErrOutput()
+{
+    m_errorOutput += m_errOutputConn->waitForRemoteOutput(0);
+    emit readyReadStandardError();
+}
+
+void RemoteGdbProcess::stopReaders()
+{
+    if (m_appOutputConn) {
+        disconnect(m_appOutputConn.data(), SIGNAL(remoteOutputAvailable()),
+                   this, SLOT(handleAppOutput()));
+        m_appOutputConn->sendInput(CtrlC);
+        m_appOutputConn->quit();
+    }
+    if (m_errOutputConn)  {
+        disconnect(m_errOutputConn.data(), SIGNAL(remoteOutputAvailable()),
+                   this, SLOT(handleErrOutput()));
+        m_errOutputConn->sendInput(CtrlC);
+        m_errOutputConn->quit();
+    }
+}
+
+QByteArray RemoteGdbProcess::readerCmdLine(const QByteArray &file)
+{
+    return "rm -f " + file + " && mkfifo " + file +  " && cat " + file + "\r\n";
+}
+
+QByteArray RemoteGdbProcess::removeCarriageReturn(const QByteArray &data)
+{
+    QByteArray output;
+    for (int i = 0; i < data.size(); ++i) {
+        const char c = data.at(i);
+        if (c != '\r')
+            output += c;
+    }
+    return output;
+}
+
+bool RemoteGdbProcess::checkForGdbExit(QByteArray &output)
+{
+    const QByteArray exitString("^exit");
+    const int exitPos = output.indexOf(exitString);
+    if (exitPos == -1)
+        return false;
+
+    emit finished(0, QProcess::NormalExit);
+    disconnect(m_gdbConn.data(), SIGNAL(remoteOutputAvailable()),
+               this, SLOT(handleGdbOutput()));
+    output.remove(exitPos + exitString.size(), output.size());
+    stopReaders();
+    return true;
+}
+
+bool RemoteGdbProcess::waitForInputReady(Core::InteractiveSshConnection::Ptr &conn)
+{
+    if (conn->waitForRemoteOutput(m_serverInfo.timeout).isEmpty())
+        return false;
+    while (!conn->waitForRemoteOutput(100).isEmpty())
+        ;
+    return true;
+}
+
+bool RemoteGdbProcess::sendAndWaitForEcho(Core::InteractiveSshConnection::Ptr &conn,
+    const QByteArray &cmdLine)
+{
+    conn->sendInput(cmdLine);
+    QByteArray allOutput;
+    while (!allOutput.endsWith(cmdLine)) {
+        const QByteArray curOutput = conn->waitForRemoteOutput(100);
+        if (curOutput.isEmpty())
+            return false;
+        allOutput += curOutput;
+    }
+    return true;
+}
+
+
+const QByteArray RemoteGdbProcess::CtrlC = QByteArray(1, 0x3);
+const QByteArray RemoteGdbProcess::AppOutputFile("app_output");
+const QByteArray RemoteGdbProcess::ErrOutputFile("err_output");
+
+} // namespace Internal
+} // namespace Debugger
diff --git a/src/plugins/debugger/gdb/remotegdbprocess.h b/src/plugins/debugger/gdb/remotegdbprocess.h
new file mode 100644 (file)
index 0000000..1008b33
--- /dev/null
@@ -0,0 +1,111 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef REMOTEGDBPROCESS_H
+#define REMOTEGDBPROCESS_H
+
+#include "abstractgdbprocess.h"
+
+#include <coreplugin/ssh/sshconnection.h>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QQueue>
+
+namespace Debugger {
+namespace Internal {
+
+class RemotePlainGdbAdapter;
+
+class RemoteGdbProcess : public AbstractGdbProcess
+{
+    Q_OBJECT
+public:
+    RemoteGdbProcess(const Core::SshServerInfo &server,
+                     RemotePlainGdbAdapter *adapter, QObject *parent = 0);
+
+    virtual QByteArray readAllStandardOutput();
+    virtual QByteArray readAllStandardError();
+
+    virtual void start(const QString &cmd, const QStringList &args);
+    virtual bool waitForStarted();
+    virtual qint64 write(const QByteArray &data);
+    virtual void kill();
+
+    virtual QProcess::ProcessState state() const;
+    virtual QString errorString() const;
+
+    virtual QProcessEnvironment processEnvironment() const;
+    virtual void setProcessEnvironment(const QProcessEnvironment &env);
+    virtual void setEnvironment(const QStringList &env);
+    virtual void setWorkingDirectory(const QString &dir);
+
+    static const QByteArray CtrlC;
+
+private slots:
+    void handleGdbOutput();
+    void handleAppOutput();
+    void handleErrOutput();
+
+private:
+    static QByteArray readerCmdLine(const QByteArray &file);
+
+    int findAnchor(const QByteArray &data) const;
+    qint64 sendInput(const QByteArray &data);
+    void stopReaders();
+    QByteArray removeCarriageReturn(const QByteArray &data);
+    bool checkForGdbExit(QByteArray &output);
+    bool sendAndWaitForEcho(Core::InteractiveSshConnection::Ptr &conn,
+        const QByteArray &cmdLine);
+    bool waitForInputReady(Core::InteractiveSshConnection::Ptr &conn);
+
+    static const QByteArray AppOutputFile;
+    static const QByteArray ErrOutputFile;
+
+    Core::SshServerInfo m_serverInfo;
+    Core::InteractiveSshConnection::Ptr m_gdbConn;
+    Core::InteractiveSshConnection::Ptr m_appOutputConn;
+    Core::InteractiveSshConnection::Ptr m_errOutputConn;
+    QByteArray m_gdbOutput;
+    QByteArray m_errorOutput;
+    QString m_command;
+    QStringList m_cmdArgs;
+    QString m_wd;
+    QQueue<QByteArray> m_inputToSend;
+    QByteArray m_currentGdbOutput;
+    QByteArray m_lastSeqNr;
+    QByteArray m_gdbCmdLine;
+    bool m_gdbStarted;
+
+    RemotePlainGdbAdapter *m_adapter;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // REMOTEGDBPROCESS_H
@@ -27,7 +27,7 @@
 **
 **************************************************************************/
 
-#include "remotegdbadapter.h"
+#include "remotegdbserveradapter.h"
 
 #include "debuggerstringutils.h"
 #include "gdbengine.h"
@@ -43,7 +43,7 @@ namespace Debugger {
 namespace Internal {
 
 #define CB(callback) \
-    static_cast<GdbEngine::AdapterCallback>(&RemoteGdbAdapter::callback), \
+    static_cast<GdbEngine::AdapterCallback>(&RemoteGdbServerAdapter::callback), \
     STRINGIFY(callback)
 
 ///////////////////////////////////////////////////////////////////////
@@ -52,7 +52,7 @@ namespace Internal {
 //
 ///////////////////////////////////////////////////////////////////////
 
-RemoteGdbAdapter::RemoteGdbAdapter(GdbEngine *engine, int toolChainType, QObject *parent) :
+RemoteGdbServerAdapter::RemoteGdbServerAdapter(GdbEngine *engine, int toolChainType, QObject *parent) :
     AbstractGdbAdapter(engine, parent),
     m_toolChainType(toolChainType)
 {
@@ -64,7 +64,7 @@ RemoteGdbAdapter::RemoteGdbAdapter(GdbEngine *engine, int toolChainType, QObject
         this, SLOT(readUploadStandardError()));
 }
 
-AbstractGdbAdapter::DumperHandling RemoteGdbAdapter::dumperHandling() const
+AbstractGdbAdapter::DumperHandling RemoteGdbServerAdapter::dumperHandling() const
 {
     switch (m_toolChainType) {
     case ProjectExplorer::ToolChain::MinGW:
@@ -82,7 +82,7 @@ AbstractGdbAdapter::DumperHandling RemoteGdbAdapter::dumperHandling() const
     return DumperLoadedByGdbPreload;
 }
 
-void RemoteGdbAdapter::startAdapter()
+void RemoteGdbServerAdapter::startAdapter()
 {
     QTC_ASSERT(state() == EngineStarting, qDebug() << state());
     setState(AdapterStarting);
@@ -105,7 +105,7 @@ void RemoteGdbAdapter::startAdapter()
     emit adapterStarted();
 }
 
-void RemoteGdbAdapter::uploadProcError(QProcess::ProcessError error)
+void RemoteGdbServerAdapter::uploadProcError(QProcess::ProcessError error)
 {
     QString msg;
     switch (error) {
@@ -139,19 +139,19 @@ void RemoteGdbAdapter::uploadProcError(QProcess::ProcessError error)
     showMessageBox(QMessageBox::Critical, tr("Error"), msg);
 }
 
-void RemoteGdbAdapter::readUploadStandardOutput()
+void RemoteGdbServerAdapter::readUploadStandardOutput()
 {
     QByteArray ba = m_uploadProc.readAllStandardOutput();
     m_engine->showDebuggerOutput(LogOutput, QString::fromLocal8Bit(ba, ba.length()));
 }
 
-void RemoteGdbAdapter::readUploadStandardError()
+void RemoteGdbServerAdapter::readUploadStandardError()
 {
     QByteArray ba = m_uploadProc.readAllStandardError();
     m_engine->showDebuggerOutput(LogError, QString::fromLocal8Bit(ba, ba.length()));
 }
 
-void RemoteGdbAdapter::startInferior()
+void RemoteGdbServerAdapter::startInferior()
 {
     QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
 
@@ -176,14 +176,14 @@ void RemoteGdbAdapter::startInferior()
         CB(handleFileExecAndSymbols));
 }
 
-void RemoteGdbAdapter::handleSetTargetAsync(const GdbResponse &response)
+void RemoteGdbServerAdapter::handleSetTargetAsync(const GdbResponse &response)
 {
     QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
     if (response.resultClass == GdbResultError)
         qDebug() << "Adapter too old: does not support asynchronous mode.";
 }
 
-void RemoteGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response)
+void RemoteGdbServerAdapter::handleFileExecAndSymbols(const GdbResponse &response)
 {
     QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
     if (response.resultClass == GdbResultDone) {
@@ -203,7 +203,7 @@ void RemoteGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response)
     }
 }
 
-void RemoteGdbAdapter::handleTargetRemote(const GdbResponse &record)
+void RemoteGdbServerAdapter::handleTargetRemote(const GdbResponse &record)
 {
     QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
     if (record.resultClass == GdbResultDone) {
@@ -220,19 +220,19 @@ void RemoteGdbAdapter::handleTargetRemote(const GdbResponse &record)
     }
 }
 
-void RemoteGdbAdapter::startInferiorPhase2()
+void RemoteGdbServerAdapter::startInferiorPhase2()
 {
     m_engine->continueInferiorInternal();
 }
 
-void RemoteGdbAdapter::interruptInferior()
+void RemoteGdbServerAdapter::interruptInferior()
 {
     // FIXME: On some gdb versions like git 170ffa5d7dd this produces
     // >810^error,msg="mi_cmd_exec_interrupt: Inferior not executing."
     m_engine->postCommand("-exec-interrupt", GdbEngine::Immediate);
 }
 
-void RemoteGdbAdapter::shutdown()
+void RemoteGdbServerAdapter::shutdown()
 {
     // FIXME: cleanup missing
 }
@@ -32,6 +32,8 @@
 
 #include "abstractgdbadapter.h"
 
+#include "abstractgdbprocess.h"
+
 namespace Debugger {
 namespace Internal {
 
@@ -41,12 +43,12 @@ namespace Internal {
 //
 ///////////////////////////////////////////////////////////////////////
 
-class RemoteGdbAdapter : public AbstractGdbAdapter
+class RemoteGdbServerAdapter : public AbstractGdbAdapter
 {
     Q_OBJECT
 
 public:
-    RemoteGdbAdapter(GdbEngine *engine, int toolChainType, QObject *parent = 0);
+    RemoteGdbServerAdapter(GdbEngine *engine, int toolChainType, QObject *parent = 0);
 
     virtual DumperHandling dumperHandling() const;
 
@@ -55,6 +57,7 @@ public:
     void startInferiorPhase2();
     void interruptInferior();
     void shutdown();
+    AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
 
 private:
     Q_SLOT void readUploadStandardOutput();
@@ -68,6 +71,7 @@ private:
     const int m_toolChainType;
 
     QProcess m_uploadProc;
+    LocalGdbProcess m_gdbProc;
 };
 
 } // namespace Internal
diff --git a/src/plugins/debugger/gdb/remoteplaingdbadapter.cpp b/src/plugins/debugger/gdb/remoteplaingdbadapter.cpp
new file mode 100644 (file)
index 0000000..77443ad
--- /dev/null
@@ -0,0 +1,93 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "remoteplaingdbadapter.h"
+
+#include <debugger/debuggeractions.h>
+#include <debugger/debuggerstringutils.h>
+#include <utils/qtcassert.h>
+
+
+namespace Debugger {
+namespace Internal {
+
+RemotePlainGdbAdapter::RemotePlainGdbAdapter(GdbEngine *engine,
+                                               QObject *parent)
+    : AbstractPlainGdbAdapter(engine, parent),
+      m_gdbProc(engine->startParameters().sshserver, this)
+{
+}
+
+void RemotePlainGdbAdapter::startAdapter()
+{
+    QTC_ASSERT(state() == EngineStarting, qDebug() << state());
+    setState(AdapterStarting);
+    debugMessage(QLatin1String("TRYING TO START ADAPTER"));
+
+    if (!startParameters().workingDirectory.isEmpty())
+        m_gdbProc.setWorkingDirectory(startParameters().workingDirectory);
+    if (!startParameters().environment.isEmpty())
+        m_gdbProc.setEnvironment(startParameters().environment);
+
+    if (m_engine->startGdb(QStringList(), m_engine->startParameters().debuggerCommand))
+        emit adapterStarted();
+}
+
+void RemotePlainGdbAdapter::interruptInferior()
+{
+    m_gdbProc.write(RemoteGdbProcess::CtrlC);
+}
+
+QByteArray RemotePlainGdbAdapter::execFilePath() const
+{
+    return startParameters().executable.toUtf8();
+}
+
+bool RemotePlainGdbAdapter::infoTargetNecessary() const
+{
+    return true;
+}
+
+QByteArray RemotePlainGdbAdapter::toLocalEncoding(const QString &s) const
+{
+    return s.toUtf8();
+}
+
+QString RemotePlainGdbAdapter::fromLocalEncoding(const QByteArray &b) const
+{
+    return QString::fromUtf8(b);
+}
+
+void RemotePlainGdbAdapter::handleApplicationOutput(const QByteArray &output)
+{
+    m_engine->manager()->showApplicationOutput(output, false);
+}
+
+} // namespace Internal
+} // namespace Debugger
diff --git a/src/plugins/debugger/gdb/remoteplaingdbadapter.h b/src/plugins/debugger/gdb/remoteplaingdbadapter.h
new file mode 100644 (file)
index 0000000..a9e089b
--- /dev/null
@@ -0,0 +1,64 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef REMOTEGDBCLIENTADAPTER_H
+#define REMOTEGDBCLIENTADAPTER_H
+
+#include "abstractplaingdbadapter.h"
+#include "remotegdbprocess.h"
+
+namespace Debugger {
+namespace Internal {
+
+class RemotePlainGdbAdapter : public AbstractPlainGdbAdapter
+{
+    Q_OBJECT
+    friend class RemoteGdbProcess;
+public:
+    RemotePlainGdbAdapter(GdbEngine *engine, QObject *parent = 0);
+
+    virtual void startAdapter();
+    virtual void interruptInferior();
+    virtual AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
+    virtual DumperHandling dumperHandling() const { return DumperLoadedByGdbPreload; }
+
+private:
+    virtual QByteArray execFilePath() const;
+    virtual bool infoTargetNecessary() const;
+    virtual QByteArray toLocalEncoding(const QString &s) const;
+    virtual QString fromLocalEncoding(const QByteArray &b) const;
+    void handleApplicationOutput(const QByteArray &output);
+
+    RemoteGdbProcess m_gdbProc;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // REMOTEGDBCLIENTADAPTER_H
index ddb95c5..489a579 100644 (file)
@@ -91,7 +91,7 @@ void TermGdbAdapter::startAdapter()
 //    m_stubProc.stop();
 //    m_stubProc.blockSignals(false);
 
-    m_stubProc.setWorkingDirectory(startParameters().workingDir);
+    m_stubProc.setWorkingDirectory(startParameters().workingDirectory);
     // Set environment + dumper preload.
     QStringList environment = startParameters().environment;
     m_stubProc.setEnvironment(environment);
index 1e05cbd..54a09e4 100644 (file)
@@ -32,6 +32,8 @@
 
 #include "abstractgdbadapter.h"
 
+#include "abstractgdbprocess.h"
+
 #include <consoleprocess.h>
 
 namespace Debugger {
@@ -57,6 +59,7 @@ public:
     void startInferior();
     void startInferiorPhase2();
     void interruptInferior();
+    AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
 
 private:
     void handleStubAttached(const GdbResponse &response);
@@ -69,6 +72,7 @@ private:
     Q_SLOT void stubMessage(const QString &msg, bool isError);
 
     Utils::ConsoleProcess m_stubProc;
+    LocalGdbProcess m_gdbProc;
 };
 
 } // namespace Internal
index 2c9e28c..f64fbdf 100644 (file)
@@ -35,7 +35,7 @@
 #include "bluetoothlistener_gui.h"
 
 #include "registerhandler.h"
-#include "stackhandler.h"
+#include "threadshandler.h"
 #include "debuggeractions.h"
 #include "debuggerstringutils.h"
 #include "watchutils.h"
@@ -1929,7 +1929,7 @@ void TrkGdbAdapter::write(const QByteArray &data)
            trkReadMemoryMessage(m_session.dataseg, 12));
         return;
     }
-    m_engine->m_gdbProc.write(data);
+    m_gdbProc.write(data);
 }
 
 uint oldPC;
index a80a955..c2af383 100644 (file)
@@ -35,6 +35,7 @@
 #include "trkutils.h"
 #include "trkdevice.h"
 #include "launcher.h"
+#include "abstractgdbprocess.h"
 
 #include <QtCore/QHash>
 #include <QtCore/QPointer>
@@ -182,6 +183,7 @@ private:
     void startInferiorPhase2();
     void interruptInferior();
     void shutdown();
+    AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
 
     void cleanup();
     void emitDelayedInferiorStartFailed(const QString &msg);
@@ -307,6 +309,7 @@ private:
     QString m_symbolFile;
     int m_verbose;
     bool m_bufferedMemoryRead;
+    LocalGdbProcess m_gdbProc;
 };
 
 } // namespace Internal
index f093376..b788247 100644 (file)
@@ -105,7 +105,7 @@ public:
     virtual void reloadModules() = 0;
     virtual void loadSymbols(const QString &moduleName) = 0;
     virtual void loadAllSymbols() = 0;
-    virtual QList<Symbol> moduleSymbols(const QString &moduleName) = 0;
+    virtual void requestModuleSymbols(const QString &moduleName) = 0;
 
     virtual void reloadRegisters() = 0;
 
diff --git a/src/plugins/debugger/images/watchpoint.png b/src/plugins/debugger/images/watchpoint.png
new file mode 100644 (file)
index 0000000..133378a
Binary files /dev/null and b/src/plugins/debugger/images/watchpoint.png differ
index d92ae76..f2270dd 100644 (file)
@@ -60,7 +60,7 @@ public:
 
     // QAbstractItemModel
     int columnCount(const QModelIndex &parent) const
-        { return parent.isValid() ? 0 : 4; }
+        { return parent.isValid() ? 0 : 5; }
     int rowCount(const QModelIndex &parent) const
         { return parent.isValid() ? 0 : m_modules.size(); }
     QModelIndex parent(const QModelIndex &) const { return QModelIndex(); }
@@ -97,6 +97,7 @@ QVariant ModulesModel::headerData(int section,
     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
         static QString headers[] = {
             tr("Module name") + "        ",
+            tr("Module path") + "        ",
             tr("Symbols read") + "        ",
             tr("Start address") + "        ",
             tr("End address") + "        "
@@ -124,14 +125,18 @@ QVariant ModulesModel::data(const QModelIndex &index, int role) const
             break;
         case 1:
             if (role == Qt::DisplayRole)
-                return module.symbolsRead ? m_yes : m_no;
+                return module.modulePath;
             break;
         case 2:
             if (role == Qt::DisplayRole)
-                return module.startAddress;
+                return module.symbolsRead ? m_yes : m_no;
             break;
         case 3:
             if (role == Qt::DisplayRole)
+                return module.startAddress;
+            break;
+        case 4:
+            if (role == Qt::DisplayRole)
                 return module.endAddress;
             break;
     }
index c0f8d19..9f4a98b 100644 (file)
@@ -78,6 +78,7 @@ public:
 
 public:
     QString moduleName;
+    QString modulePath;
     bool symbolsRead;
     QString startAddress;
     QString endAddress;
index 4144f82..df427ba 100644 (file)
@@ -175,6 +175,7 @@ void ModulesWindow::resizeColumnsToContents()
     resizeColumnToContents(0);
     resizeColumnToContents(1);
     resizeColumnToContents(2);
+    resizeColumnToContents(3);
 }
 
 void ModulesWindow::setAlwaysResizeColumnsToContents(bool on)
@@ -186,6 +187,7 @@ void ModulesWindow::setAlwaysResizeColumnsToContents(bool on)
     header()->setResizeMode(1, mode);
     header()->setResizeMode(2, mode);
     header()->setResizeMode(3, mode);
+    header()->setResizeMode(4, mode);
     //setColumnHidden(3, true);
 }
 
@@ -197,27 +199,8 @@ void ModulesWindow::setModel(QAbstractItemModel *model)
 
 void ModulesWindow::showSymbols(const QString &name)
 {
-    if (name.isEmpty())
-        return;
-    QApplication::setOverrideCursor(Qt::WaitCursor);
-    const QList<Symbol> symbols = m_debuggerManager->moduleSymbols(name);
-    QApplication::restoreOverrideCursor();
-    if (symbols.empty())
-        return;
-    QTreeWidget *w = new QTreeWidget;
-    w->setColumnCount(3);
-    w->setRootIsDecorated(false);
-    w->setAlternatingRowColors(true);
-    w->setHeaderLabels(QStringList() << tr("Address") << tr("Code") << tr("Symbol"));
-    w->setWindowTitle(tr("Symbols in \"%1\"").arg(name));
-    foreach (const Symbol &s, symbols) {
-        QTreeWidgetItem *it = new QTreeWidgetItem;
-        it->setData(0, Qt::DisplayRole, s.address);
-        it->setData(1, Qt::DisplayRole, s.state);
-        it->setData(2, Qt::DisplayRole, s.name);
-        w->addTopLevelItem(it);
-    }
-    emit newDockRequested(w);
+    if (!name.isEmpty())
+        m_debuggerManager->requestModuleSymbols(name);
 }
 
 } // namespace Internal
index 0fa6702..49eb20a 100644 (file)
@@ -394,13 +394,52 @@ void PdbEngine::loadAllSymbols()
 
 void PdbEngine::reloadModules()
 {
+    postCommand("qdebug('listmodules')", CB(handleListModules));
+}
+
+void PdbEngine::handleListModules(const PdbResponse &response)
+{
+    GdbMi out;
+    out.fromString(response.data.trimmed());
+    QList<Module> modules;
+    foreach (const GdbMi &item, out.children()) {
+        Module module;
+        module.moduleName = _(item.findChild("name").data());
+        QString path = _(item.findChild("value").data());
+        int pos = path.indexOf(_("' from '"));
+        if (pos != -1) {
+            path = path.mid(pos + 8);
+            if (path.size() >= 2)
+                path.chop(2);
+        } else if (path.startsWith(_("<module '"))
+                && path.endsWith(_("' (built-in)>"))) {
+            path = _("(builtin)");
+        }
+        module.modulePath = path;
+        modules.append(module);
+    }
+    manager()->modulesHandler()->setModules(modules);
 }
 
-QList<Symbol> PdbEngine::moduleSymbols(const QString & /*moduleName*/)
+void PdbEngine::requestModuleSymbols(const QString &moduleName)
 {
-    return QList<Symbol>();
+    postCommand("qdebug('listsymbols','" + moduleName.toLatin1() + "')",
+        CB(handleListSymbols), moduleName);
 }
 
+void PdbEngine::handleListSymbols(const PdbResponse &response)
+{
+    GdbMi out;
+    out.fromString(response.data.trimmed());
+    QList<Symbol> symbols;
+    QString moduleName = response.cookie.toString();
+    foreach (const GdbMi &item, out.children()) {
+        Symbol symbol;
+        symbol.name = _(item.findChild("name").data());
+        symbols.append(symbol);
+    }
+    manager()->showModuleSymbols(moduleName, symbols);
+}
 
 //////////////////////////////////////////////////////////////////////
 //
@@ -771,6 +810,11 @@ void PdbEngine::debugMessage(const QString &msg)
     showDebuggerOutput(LogDebug, msg);
 }
 
+unsigned PdbEngine::debuggerCapabilities() const
+{
+    return ReloadModuleCapability;
+}
+
 IDebuggerEngine *createPdbEngine(DebuggerManager *manager)
 {
     return new PdbEngine(manager);
index 2b1f9d1..9262b6a 100644 (file)
@@ -94,7 +94,7 @@ private:
 
     void loadSymbols(const QString &moduleName);
     void loadAllSymbols();
-    virtual QList<Symbol> moduleSymbols(const QString &moduleName);
+    void requestModuleSymbols(const QString &moduleName);
     void reloadModules();
     void reloadRegisters() {}
     void reloadSourceFiles() {}
@@ -107,6 +107,7 @@ private:
 private:
     void debugMessage(const QString &msg);
     QString errorMessage(QProcess::ProcessError error) const;
+    unsigned debuggerCapabilities() const;
 
     Q_SLOT void handlePdbFinished(int, QProcess::ExitStatus status);
     Q_SLOT void handlePdbError(QProcess::ProcessError error);
@@ -135,6 +136,8 @@ private:
     void handleStop(const PdbResponse &response);
     void handleBacktrace(const PdbResponse &response);
     void handleListLocals(const PdbResponse &response);
+    void handleListModules(const PdbResponse &response);
+    void handleListSymbols(const PdbResponse &response);
     void handleLoadDumper(const PdbResponse &response);
     void handleBreakInsert(const PdbResponse &response);
 
index 8b0566a..3185c10 100644 (file)
@@ -448,9 +448,8 @@ void ScriptEngine::reloadModules()
 {
 }
 
-QList<Symbol> ScriptEngine::moduleSymbols(const QString & /*moduleName*/)
+void ScriptEngine::requestModuleSymbols(const QString & /*moduleName*/)
 {
-    return QList<Symbol>();
 }
 
 
index 22d28ed..e320c46 100644 (file)
@@ -93,7 +93,7 @@ private:
 
     void loadSymbols(const QString &moduleName);
     void loadAllSymbols();
-    virtual QList<Symbol> moduleSymbols(const QString &moduleName);
+    void requestModuleSymbols(const QString &moduleName);
     void reloadModules();
     void reloadRegisters() {}
     void reloadSourceFiles() {}
diff --git a/src/plugins/debugger/stackframe.cpp b/src/plugins/debugger/stackframe.cpp
new file mode 100644 (file)
index 0000000..9a0797f
--- /dev/null
@@ -0,0 +1,112 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "stackframe.h"
+#include "stackhandler.h"
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QTextStream>
+
+namespace Debugger {
+namespace Internal {
+
+////////////////////////////////////////////////////////////////////////
+//
+// StackFrame
+//
+////////////////////////////////////////////////////////////////////////
+
+StackFrame::StackFrame()
+  : level(0), line(0)
+{}
+
+void StackFrame::clear()
+{
+    line = level = 0;
+    function.clear();
+    file.clear();
+    from.clear();
+    to.clear();
+    address.clear();
+}
+
+bool StackFrame::isUsable() const
+{
+    return !file.isEmpty() && QFileInfo(file).isReadable();
+}
+
+QString StackFrame::toString() const
+{
+    QString res;
+    QTextStream str(&res);
+    str << StackHandler::tr("Address:") << ' ' << address << ' '
+        << StackHandler::tr("Function:") << ' ' << function << ' '
+        << StackHandler::tr("File:") << ' ' << file << ' '
+        << StackHandler::tr("Line:") << ' ' << line << ' '
+        << StackHandler::tr("From:") << ' ' << from << ' '
+        << StackHandler::tr("To:") << ' ' << to;
+    return res;
+}
+
+QString StackFrame::toToolTip() const
+{
+    QString res;
+    QTextStream str(&res);
+    str << "<html><body><table>"
+        << "<tr><td>" << StackHandler::tr("Address:") << "</td><td>" <<  address << "</td></tr>"
+        << "<tr><td>" << StackHandler::tr("Function:") << "</td><td>" << function << "</td></tr>"
+        << "<tr><td>" << StackHandler::tr("File:") << "</td><td>" << QDir::toNativeSeparators(file) << "</td></tr>"
+        << "<tr><td>" << StackHandler::tr("Line:") << "</td><td>" << line << "</td></tr>"
+        << "<tr><td>" << StackHandler::tr("From:") << "</td><td>" << from << "</td></tr>"
+        << "<tr><td>" << StackHandler::tr("To:") << "</td><td>" << to << "</td></tr>"
+        << "</table></body></html>";
+    return res;
+}
+
+QDebug operator<<(QDebug d, const  StackFrame &f)
+{
+    QString res;
+    QTextStream str(&res);
+    str << "level=" << f.level << " address=" << f.address;
+    if (!f.function.isEmpty())
+        str << ' ' << f.function;
+    if (!f.file.isEmpty())
+        str << ' ' << f.file << ':' << f.line;
+    if (!f.from.isEmpty())
+        str << " from=" << f.from;
+    if (!f.to.isEmpty())
+        str << " to=" << f.to;
+    d.nospace() << res;
+    return d;
+}
+
+} // namespace Internal
+} // namespace Debugger
index 5913d0c..bdfc7b5 100644 (file)
 namespace Debugger {
 namespace Internal {
 
-StackFrame::StackFrame()
-  : level(0), line(0)
-{}
-
-void StackFrame::clear()
-{
-    line = level = 0;
-    function.clear();
-    file.clear();
-    from.clear();
-    to.clear();
-    address.clear();
-}
-
-bool StackFrame::isUsable() const
-{
-    return !file.isEmpty() && QFileInfo(file).isReadable();
-}
-
-QString StackFrame::toString() const
-{
-    QString res;
-    QTextStream str(&res);
-    str << StackHandler::tr("Address:") << ' ' << address << ' '
-        << StackHandler::tr("Function:") << ' ' << function << ' '
-        << StackHandler::tr("File:") << ' ' << file << ' '
-        << StackHandler::tr("Line:") << ' ' << line << ' '
-        << StackHandler::tr("From:") << ' ' << from << ' '
-        << StackHandler::tr("To:") << ' ' << to;
-    return res;
-}
-
-QString StackFrame::toToolTip() const
-{
-    QString res;
-    QTextStream str(&res);
-    str << "<html><body><table>"
-        << "<tr><td>" << StackHandler::tr("Address:") << "</td><td>" <<  address << "</td></tr>"
-        << "<tr><td>" << StackHandler::tr("Function:") << "</td><td>" << function << "</td></tr>"
-        << "<tr><td>" << StackHandler::tr("File:") << "</td><td>" << QDir::toNativeSeparators(file) << "</td></tr>"
-        << "<tr><td>" << StackHandler::tr("Line:") << "</td><td>" << line << "</td></tr>"
-        << "<tr><td>" << StackHandler::tr("From:") << "</td><td>" << from << "</td></tr>"
-        << "<tr><td>" << StackHandler::tr("To:") << "</td><td>" << to << "</td></tr>"
-        << "</table></body></html>";
-    return res;
-}
-
-QDebug operator<<(QDebug d, const  StackFrame &f)
-{
-    QString res;
-    QTextStream str(&res);
-    str << "level=" << f.level << " address=" << f.address;
-    if (!f.function.isEmpty())
-        str << ' ' << f.function;
-    if (!f.file.isEmpty())
-        str << ' ' << f.file << ':' << f.line;
-    if (!f.from.isEmpty())
-        str << " from=" << f.from;
-    if (!f.to.isEmpty())
-        str << " to=" << f.to;
-    d.nospace() << res;
-    return d;
-}
 
 ////////////////////////////////////////////////////////////////////////
 //
@@ -262,153 +199,5 @@ bool StackHandler::isDebuggingDebuggingHelpers() const
 }
 
 
-////////////////////////////////////////////////////////////////////////
-//
-// ThreadsHandler
-//
-////////////////////////////////////////////////////////////////////////
-
-ThreadData::ThreadData(int threadId) :
-    id(threadId),
-    address(0),
-    line(-1)
-{
-}
-
-void ThreadData::notifyRunning()
-{
-    address = 0;
-    function.clear();
-    file.clear();
-    line = -1;
-}
-
-enum { IdColumn, AddressColumn, FunctionColumn, FileColumn, LineColumn, ColumnCount };
-
-ThreadsHandler::ThreadsHandler(QObject *parent)  :
-    QAbstractTableModel(parent),
-    m_currentIndex(0),
-    m_positionIcon(QLatin1String(":/debugger/images/location_16.png")),
-    m_emptyIcon(QLatin1String(":/debugger/images/debugger_empty_14.png"))
-{
-}
-
-int ThreadsHandler::rowCount(const QModelIndex &parent) const
-{
-    // Since the stack is not a tree, row count is 0 for any valid parent
-    return parent.isValid() ? 0 : m_threads.size();
-}
-
-int ThreadsHandler::columnCount(const QModelIndex &parent) const
-{
-    return parent.isValid() ? 0 : int(ColumnCount);
-}
-
-QVariant ThreadsHandler::data(const QModelIndex &index, int role) const
-{
-    if (!index.isValid())
-        return QVariant();
-    const int row = index.row();
-    if (row  >= m_threads.size())
-        return QVariant();
-    const ThreadData &thread = m_threads.at(row);
-
-    if (role == Qt::DisplayRole) {
-        switch (index.column()) {
-        case IdColumn:
-            return thread.id;
-        case FunctionColumn:
-            return thread.function;
-        case FileColumn:
-            return thread.file;
-        case LineColumn:
-            return thread.line >= 0 ? QString::number(thread.line) : QString();
-        case AddressColumn:
-            return thread.address > 0 ? QLatin1String("0x") + QString::number(thread.address, 16) : QString();
-        }
-    } else if (role == Qt::ToolTipRole) {
-        if (thread.address == 0)
-            return tr("Thread: %1").arg(thread.id);
-        // Stopped
-        if (thread.file.isEmpty())
-            return tr("Thread: %1 at %2 (0x%3)").arg(thread.id).arg(thread.function).arg(thread.address, 0, 16);
-        return tr("Thread: %1 at %2, %3:%4 (0x%5)").
-                arg(thread.id).arg(thread.function, thread.file).arg(thread.line).arg(thread.address, 0, 16);
-    } else if (role == Qt::DecorationRole && index.column() == 0) {
-        // Return icon that indicates whether this is the active stack frame
-        return (index.row() == m_currentIndex) ? m_positionIcon : m_emptyIcon;
-    }
-
-    return QVariant();
-}
-
-QVariant ThreadsHandler::headerData(int section, Qt::Orientation orientation, int role) const
-{
-    if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
-        return QVariant();
-    switch (section) {
-    case IdColumn:
-        return tr("Thread ID");
-    case FunctionColumn:
-        return tr("Function");
-    case FileColumn:
-        return tr("File");
-    case LineColumn:
-        return tr("Line");
-    case AddressColumn:
-        return tr("Address");
-    }
-    return QVariant();
-}
-
-void ThreadsHandler::setCurrentThread(int index)
-{
-    if (index == m_currentIndex)
-        return;
-
-    // Emit changed for previous frame
-    QModelIndex i = ThreadsHandler::index(m_currentIndex, 0);
-    emit dataChanged(i, i);
-
-    m_currentIndex = index;
-
-    // Emit changed for new frame
-    i = ThreadsHandler::index(m_currentIndex, 0);
-    emit dataChanged(i, i);
-}
-
-void ThreadsHandler::setThreads(const QList<ThreadData> &threads)
-{
-    m_threads = threads;
-    if (m_currentIndex >= m_threads.size())
-        m_currentIndex = m_threads.size() - 1;
-    reset();
-}
-
-QList<ThreadData> ThreadsHandler::threads() const
-{
-    return m_threads;
-}
-
-void ThreadsHandler::removeAll()
-{
-    m_threads.clear();
-    m_currentIndex = 0;
-    reset();
-}
-
-void ThreadsHandler::notifyRunning()
-{
-    // Threads stopped (that is, address != 0 showing)?
-    if (m_threads.empty())
-        return;
-    if (m_threads.front().address == 0)
-        return;
-    const QList<ThreadData>::iterator end = m_threads.end();
-    for (QList<ThreadData>::iterator it = m_threads.begin(); it != end; ++it)
-        it->notifyRunning();
-    emit dataChanged(index(0, 1), index(m_threads.size()- 1, ColumnCount - 1));
-}
-
 } // namespace Internal
 } // namespace Debugger
index 6c6cd6b..28c5cd1 100644 (file)
 namespace Debugger {
 namespace Internal {
 
+////////////////////////////////////////////////////////////////////////
+//
+// StackModel
+//
+////////////////////////////////////////////////////////////////////////
+
 struct StackCookie
 {
     StackCookie() : isFull(true), gotoLocation(false) {}
@@ -92,56 +98,6 @@ private:
 };
 
 
-////////////////////////////////////////////////////////////////////////
-//
-// ThreadsHandler
-//
-////////////////////////////////////////////////////////////////////////
-
-struct ThreadData
-{
-    ThreadData(int threadId = 0);
-    void notifyRunning(); // Clear state information
-
-    int id;
-    // State information when stopped
-    quint64 address;
-    QString function;
-    QString file;
-    int line;
-};
-
-/*! A model to represent the running threads in a QTreeView or ComboBox */
-class ThreadsHandler : public QAbstractTableModel
-{
-    Q_OBJECT
-
-public:
-    ThreadsHandler(QObject *parent = 0);
-
-    void setCurrentThread(int index);
-    void selectThread(int index);
-    void setThreads(const QList<ThreadData> &threads);
-    void removeAll();
-    QList<ThreadData> threads() const;
-    QAbstractItemModel *threadsModel() { return this; }
-
-    // Clear out all frame information
-    void notifyRunning();
-
-private:
-    int rowCount(const QModelIndex &parent = QModelIndex()) const;
-    int columnCount(const QModelIndex &parent = QModelIndex()) const;
-    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
-    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
-
-private:
-    QList<ThreadData> m_threads;
-    int m_currentIndex;
-    const QIcon m_positionIcon;
-    const QIcon m_emptyIcon;
-};
-
 
 } // namespace Internal
 } // namespace Debugger
index 90ed85a..c340813 100644 (file)
@@ -48,6 +48,9 @@
        </property>
       </widget>
      </item>
+     <item row="0" column="1">
+      <widget class="Utils::PathChooser" name="execFile" native="true"/>
+     </item>
      <item row="1" column="0">
       <widget class="QLabel" name="argLabel">
        <property name="text">
      <item row="1" column="1">
       <widget class="QLineEdit" name="argsEdit"/>
      </item>
-     <item row="0" column="1">
-      <widget class="Utils::PathChooser" name="execFile" native="true"/>
+     <item row="2" column="0">
+      <widget class="QLabel" name="workingDirectoryLabel">
+       <property name="text">
+        <string>Working directory:</string>
+       </property>
+      </widget>
      </item>
      <item row="2" column="1">
+      <widget class="Utils::PathChooser" name="workingDirectory" native="true"/>
+     </item>
+     <item row="3" column="1">
       <widget class="QCheckBox" name="checkBoxBreakAtMain">
        <property name="text">
         <string/>
        </property>
       </widget>
      </item>
-     <item row="2" column="0">
+     <item row="3" column="0">
       <widget class="QLabel" name="labelBreakAtMain">
        <property name="text">
         <string>Break at 'main':</string>
diff --git a/src/plugins/debugger/tcf/json.cpp b/src/plugins/debugger/tcf/json.cpp
new file mode 100644 (file)
index 0000000..f8bf75b
--- /dev/null
@@ -0,0 +1,372 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "json.h"
+
+#include <utils/qtcassert.h>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QTextStream>
+
+#include <ctype.h>
+
+//#define DEBUG_JASON
+#ifdef DEBUG_JASON
+#define JDEBUG(s) qDebug() << s
+#else
+#define JDEBUG(s)
+#endif
+
+namespace Debugger {
+namespace Internal {
+
+static void skipSpaces(const char *&from, const char *to)
+{
+    while (from != to && isspace(*from))
+        ++from;
+}
+
+QTextStream &operator<<(QTextStream &os, const JsonValue &mi)
+{
+    return os << mi.toString();
+}
+
+void JsonValue::parsePair(const char *&from, const char *to)
+{
+    skipSpaces(from, to);
+    JDEBUG("parsePair: " << QByteArray(from, to - from));
+    m_name = parseCString(from, to);
+    skipSpaces(from, to);
+    while (from < to && *from != ':') {
+        JDEBUG("not a colon" << *from);
+        ++from;
+    }
+    ++from;
+    parseValue(from, to);
+    skipSpaces(from, to);
+}
+
+QByteArray JsonValue::parseNumber(const char *&from, const char *to)
+{
+    QByteArray result;
+    while (from < to && *from >= '0' && *from <= '9')
+        result.append(*from++);
+    return result;
+}
+
+QByteArray JsonValue::parseCString(const char *&from, const char *to)
+{
+    QByteArray result;
+    JDEBUG("parseCString: " << QByteArray(from, to - from));
+    if (*from != '"') {
+        qDebug() << "JSON Parse Error, double quote expected";
+        ++from; // So we don't hang
+        return QByteArray();
+    }
+    const char *ptr = from;
+    ++ptr;
+    while (ptr < to) {
+        if (*ptr == '"') {
+            ++ptr;
+            result = QByteArray(from + 1, ptr - from - 2);
+            break;
+        }
+        if (*ptr == '\\') {
+            ++ptr;
+            if (ptr == to) {
+                qDebug() << "JSON Parse Error, unterminated backslash escape";
+                from = ptr; // So we don't hang
+                return QByteArray();
+            }
+        }
+        ++ptr;
+    }
+    from = ptr;
+
+    int idx = result.indexOf('\\');
+    if (idx >= 0) {
+        char *dst = result.data() + idx;
+        const char *src = dst + 1, *end = result.data() + result.length();
+        do {
+            char c = *src++;
+            switch (c) {
+                case 'a': *dst++ = '\a'; break;
+                case 'b': *dst++ = '\b'; break;
+                case 'f': *dst++ = '\f'; break;
+                case 'n': *dst++ = '\n'; break;
+                case 'r': *dst++ = '\r'; break;
+                case 't': *dst++ = '\t'; break;
+                case 'v': *dst++ = '\v'; break;
+                case '"': *dst++ = '"'; break;
+                case '\\': *dst++ = '\\'; break;
+                default:
+                    {
+                        int chars = 0;
+                        uchar prod = 0;
+                        forever {
+                            if (c < '0' || c > '7') {
+                                --src;
+                                break;
+                            }
+                            prod = prod * 8 + c - '0';
+                            if (++chars == 3 || src == end)
+                                break;
+                            c = *src++;
+                        }
+                        if (!chars) {
+                            qDebug() << "JSON Parse Error, unrecognized backslash escape";
+                            return QByteArray();
+                        }
+                        *dst++ = prod;
+                    }
+            }
+            while (src != end) {
+                char c = *src++;
+                if (c == '\\')
+                    break;
+                *dst++ = c;
+            }
+        } while (src != end);
+        *dst = 0;
+        result.truncate(dst - result.data());
+    }
+
+    JDEBUG("parseCString, got " << result);
+    return result;
+}
+
+void JsonValue::parseValue(const char *&from, const char *to)
+{
+    JDEBUG("parseValue: " << QByteArray(from, to - from));
+    switch (*from) {
+        case '{':
+            parseObject(from, to);
+            break;
+        case '[':
+            parseArray(from, to);
+            break;
+        case '"':
+            m_type = String;
+            m_data = parseCString(from, to);
+            break;
+        case '0': case '1': case '2': case '3': case '4':
+        case '5': case '6': case '7': case '8': case '9':
+            m_type = Number;
+            m_data = parseNumber(from, to);
+        default:
+            break;
+    }
+}
+
+void JsonValue::parseObject(const char *&from, const char *to)
+{
+    JDEBUG("parseObject: " << QByteArray(from, to - from));
+    QTC_ASSERT(*from == '{', /**/);
+    ++from;
+    m_type = Object;
+    while (from < to) {
+        if (*from == '}') {
+            ++from;
+            break;
+        }
+        JsonValue child;
+        child.parsePair(from, to);
+        if (!child.isValid())
+            return;
+        m_children += child;
+        if (*from == ',')
+            ++from;
+    }
+}
+
+void JsonValue::parseArray(const char *&from, const char *to)
+{
+    JDEBUG("parseArray: " << QByteArray(from, to - from));
+    QTC_ASSERT(*from == '[', /**/);
+    ++from;
+    m_type = Array;
+    while (from < to) {
+        if (*from == ']') {
+            ++from;
+            break;
+        }
+        JsonValue child;
+        child.parseValue(from, to);
+        if (child.isValid())
+            m_children += child;
+        if (*from == ',')
+            ++from;
+    }
+}
+
+void JsonValue::setStreamOutput(const QByteArray &name, const QByteArray &content)
+{
+    if (content.isEmpty())
+        return;
+    JsonValue child;
+    child.m_type = String;
+    child.m_name = name;
+    child.m_data = content;
+    m_children += child;
+    if (m_type == Invalid)
+        m_type = Object;
+}
+
+static QByteArray ind(int indent)
+{
+    return QByteArray(2 * indent, ' ');
+}
+
+void JsonValue::dumpChildren(QByteArray * str, bool multiline, int indent) const
+{
+    for (int i = 0; i < m_children.size(); ++i) {
+        if (i != 0) {
+            *str += ',';
+            if (multiline)
+                *str += '\n';
+        }
+        if (multiline)
+            *str += ind(indent);
+        *str += m_children.at(i).toString(multiline, indent);
+    }
+}
+
+class MyString : public QString {
+public:
+    ushort at(int i) const { return constData()[i].unicode(); }
+};
+
+template<class ST, typename CT>
+inline ST escapeCStringTpl(const ST &ba)
+{
+    ST ret;
+    ret.reserve(ba.length() * 2);
+    for (int i = 0; i < ba.length(); ++i) {
+        CT c = ba.at(i);
+        switch (c) {
+            case '\\': ret += "\\\\"; break;
+            case '\a': ret += "\\a"; break;
+            case '\b': ret += "\\b"; break;
+            case '\f': ret += "\\f"; break;
+            case '\n': ret += "\\n"; break;
+            case '\r': ret += "\\r"; break;
+            case '\t': ret += "\\t"; break;
+            case '\v': ret += "\\v"; break;
+            case '"': ret += "\\\""; break;
+            default:
+                if (c < 32 || c == 127) {
+                    ret += '\\';
+                    ret += '0' + (c >> 6);
+                    ret += '0' + ((c >> 3) & 7);
+                    ret += '0' + (c & 7);
+                } else {
+                    ret += c;
+                }
+        }
+    }
+    return ret;
+}
+
+QString JsonValue::escapeCString(const QString &ba)
+{
+    return escapeCStringTpl<MyString, ushort>(static_cast<const MyString &>(ba));
+}
+
+QByteArray JsonValue::escapeCString(const QByteArray &ba)
+{
+    return escapeCStringTpl<QByteArray, uchar>(ba);
+}
+
+QByteArray JsonValue::toString(bool multiline, int indent) const
+{
+    QByteArray result;
+    switch (m_type) {
+        case Invalid:
+            if (multiline)
+                result += ind(indent) + "Invalid\n";
+            else
+                result += "Invalid";
+            break;
+        case String:
+            if (!m_name.isEmpty())
+                result += m_name + "=";
+            result += '"' + escapeCString(m_data) + '"';
+            break;
+        case Number:
+            if (!m_name.isEmpty())
+                result += '"' + m_name + "\":";
+            result += m_data;
+            break;
+        case Object:
+            if (!m_name.isEmpty())
+                result += m_name + '=';
+            if (multiline) {
+                result += "{\n";
+                dumpChildren(&result, multiline, indent + 1);
+                result += '\n' + ind(indent) + "}";
+            } else {
+                result += "{";
+                dumpChildren(&result, multiline, indent + 1);
+                result += "}";
+            }
+            break;
+        case Array:
+            if (!m_name.isEmpty())
+                result += m_name + "=";
+            if (multiline) {
+                result += "[\n";
+                dumpChildren(&result, multiline, indent + 1);
+                result += '\n' + ind(indent) + "]";
+            } else {
+                result += "[";
+                dumpChildren(&result, multiline, indent + 1);
+                result += "]";
+            }
+            break;
+    }
+    return result;
+}
+
+void JsonValue::fromString(const QByteArray &ba)
+{
+    const char *from = ba.constBegin();
+    const char *to = ba.constEnd();
+    parseValue(from, to);
+}
+
+JsonValue JsonValue::findChild(const char *name) const
+{
+    for (int i = 0; i < m_children.size(); ++i)
+        if (m_children.at(i).m_name == name)
+            return m_children.at(i);
+    return JsonValue();
+}
+
+} // namespace Internal
+} // namespace Debugger
diff --git a/src/plugins/debugger/tcf/json.h b/src/plugins/debugger/tcf/json.h
new file mode 100644 (file)
index 0000000..18c42a5
--- /dev/null
@@ -0,0 +1,100 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DEBUGGER_JSON_H
+#define DEBUGGER_JSON_H
+
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+
+namespace Debugger {
+namespace Internal {
+
+class JsonValue
+{
+public:
+    JsonValue() : m_type(Invalid) {}
+    explicit JsonValue(const QByteArray &str) { fromString(str); }
+
+    QByteArray m_name;
+    QByteArray m_data;
+    QList<JsonValue> m_children;
+
+    enum Type {
+        Invalid,
+        String,
+        Number,
+        Object,
+        Array,
+    };
+
+    Type m_type;
+
+    inline Type type() const { return m_type; }
+    inline QByteArray name() const { return m_name; }
+    inline bool hasName(const char *name) const { return m_name == name; }
+
+    inline bool isValid() const { return m_type != Invalid; }
+    inline bool isNumber() const { return m_type == Number; }
+    inline bool isString() const { return m_type == String; }
+    inline bool isObject() const { return m_type == Object; }
+    inline bool isArray() const { return m_type == Array; }
+
+
+    inline QByteArray data() const { return m_data; }
+    inline const QList<JsonValue> &children() const { return m_children; }
+    inline int childCount() const { return m_children.size(); }
+
+    const JsonValue &childAt(int index) const { return m_children[index]; }
+    JsonValue &childAt(int index) { return m_children[index]; }
+    JsonValue findChild(const char *name) const;
+
+    QByteArray toString(bool multiline = false, int indent = 0) const;
+    void fromString(const QByteArray &str);
+    void setStreamOutput(const QByteArray &name, const QByteArray &content);
+
+private:
+    static QByteArray parseCString(const char *&from, const char *to);
+    static QByteArray parseNumber(const char *&from, const char *to);
+    static QByteArray escapeCString(const QByteArray &ba);
+    static QString escapeCString(const QString &ba);
+    void parsePair(const char *&from, const char *to);
+    void parseValue(const char *&from, const char *to);
+    void parseObject(const char *&from, const char *to);
+    void parseArray(const char *&from, const char *to);
+
+    void dumpChildren(QByteArray *str, bool multiline, int indent) const;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+//Q_DECLARE_METATYPE(GdbDebugger::Internal::JsonValue);
+
+#endif // DEBUGGER_JSON_H
diff --git a/src/plugins/debugger/tcf/tcf.pri b/src/plugins/debugger/tcf/tcf.pri
new file mode 100644 (file)
index 0000000..faaad28
--- /dev/null
@@ -0,0 +1,11 @@
+HEADERS += \
+    $$PWD/json.h \
+    $$PWD/tcfengine.h \
+
+SOURCES += \
+    $$PWD/json.cpp \
+    $$PWD/tcfengine.cpp \
+
+FORMS += 
+
+RESOURCES += 
diff --git a/src/plugins/debugger/tcf/tcfengine.cpp b/src/plugins/debugger/tcf/tcfengine.cpp
new file mode 100644 (file)
index 0000000..7982e4e
--- /dev/null
@@ -0,0 +1,569 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "tcfengine.h"
+
+#include "debuggerstringutils.h"
+#include "debuggerdialogs.h"
+#include "breakhandler.h"
+#include "debuggerconstants.h"
+#include "debuggermanager.h"
+#include "moduleshandler.h"
+#include "registerhandler.h"
+#include "stackhandler.h"
+#include "watchhandler.h"
+#include "watchutils.h"
+#include "moduleshandler.h"
+#include "json.h"
+
+#include <utils/qtcassert.h>
+
+#include <QtCore/QDateTime>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTimer>
+
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QMainWindow>
+#include <QtGui/QMessageBox>
+#include <QtGui/QToolTip>
+
+#include <QtNetwork/QTcpSocket>
+
+#define DEBUG_TCF 1
+#if DEBUG_TCF
+#   define SDEBUG(s) qDebug() << s
+#else
+#   define SDEBUG(s)
+#endif
+# define XSDEBUG(s) qDebug() << s
+
+#define CB(callback) &TcfEngine::callback, STRINGIFY(callback)
+
+//#define USE_CONGESTION_CONTROL
+
+static QByteArray C(const QByteArray &ba1,
+    const QByteArray &ba2 = QByteArray(),
+    const QByteArray &ba3 = QByteArray(),
+    const QByteArray &ba4 = QByteArray(),
+    const QByteArray &ba5 = QByteArray())
+{
+    QByteArray result = ba1;
+    if (!ba2.isEmpty()) { result += '\0'; result += ba2; }
+    if (!ba3.isEmpty()) { result += '\0'; result += ba3; }
+    if (!ba4.isEmpty()) { result += '\0'; result += ba4; }
+    if (!ba5.isEmpty()) { result += '\0'; result += ba5; }
+    return result;
+}
+
+namespace Debugger {
+namespace Internal {
+
+///////////////////////////////////////////////////////////////////////
+//
+// TcfCommand
+//
+///////////////////////////////////////////////////////////////////////
+
+
+QString TcfEngine::TcfCommand::toString() const
+{
+    return quoteUnprintableLatin1(command);
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// TcfEngine
+//
+///////////////////////////////////////////////////////////////////////
+
+TcfEngine::TcfEngine(DebuggerManager *manager)
+    : IDebuggerEngine(manager)
+{
+    m_congestion = 0;
+    m_inAir = 0;
+
+    m_sendTimer.setSingleShot(true);
+    m_sendTimer.setInterval(100); // ms
+    connect(&m_sendTimer, SIGNAL(timeout()), this, SLOT(handleSendTimer()));
+
+    m_socket = new QTcpSocket(this);
+    connect(m_socket, SIGNAL(connected()), this, SLOT(socketConnected()));
+    connect(m_socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
+    connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)),
+        this, SLOT(socketError(QAbstractSocket::SocketError)));
+
+    //void aboutToClose ()
+    //void bytesWritten ( qint64 bytes )
+    //void readChannelFinished ()
+    connect(m_socket, SIGNAL(readyRead()), this, SLOT(socketReadyRead()));
+
+    //connect(m_socket, SIGNAL(hostFound())
+    //connect(m_socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy, QAuthenticator *)))
+    //connect(m_socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+    //    thism SLOT(socketStateChanged(QAbstractSocket::SocketState)));
+}
+
+TcfEngine::~TcfEngine()
+{
+}
+
+void TcfEngine::socketReadyRead()
+{
+    //XSDEBUG("TcfEngine::socketReadyRead()");
+    m_inbuffer.append(m_socket->readAll());
+    int pos = 0;
+    while (1) {
+        // the  "\3" is followed by either "\1" or "\2"
+        int next = m_inbuffer.indexOf("\3", pos);
+        //qDebug() << "pos: " << pos << "next: " << next;
+        if (next == -1)
+            break;
+        handleResponse(m_inbuffer.mid(pos, next - pos));
+        pos = next + 2; 
+    }
+    m_inbuffer.clear();
+}
+
+void TcfEngine::socketConnected()
+{
+    showStatusMessage("Socket connected.");
+    m_socket->waitForConnected(2000);
+    //sendCommand("Locator", "redirect", "ID");
+}
+
+void TcfEngine::socketDisconnected()
+{
+    XSDEBUG("FIXME:  TcfEngine::socketDisconnected()");
+}
+
+void TcfEngine::socketError(QAbstractSocket::SocketError)
+{
+    QString msg = tr("%1.").arg(m_socket->errorString());
+    //QMessageBox::critical(q->mainWindow(), tr("Error"), msg);
+    showStatusMessage(msg);
+    manager()->notifyInferiorExited();
+}
+
+void TcfEngine::executeDebuggerCommand(const QString &command)
+{
+    QByteArray cmd = command.toUtf8();
+    cmd = cmd.mid(cmd.indexOf(' ') + 1);
+    QByteArray null;
+    null.append('\0');
+    // FIXME: works for single-digit escapes only
+    cmd.replace("\\0", null);
+    cmd.replace("\\1", "\1");
+    cmd.replace("\\3", "\3");
+    TcfCommand tcf;
+    tcf.command = cmd;
+    enqueueCommand(tcf);
+}
+
+void TcfEngine::shutdown()
+{
+    m_congestion = 0;
+    m_inAir = 0;
+    m_services.clear();
+    exitDebugger(); 
+}
+
+void TcfEngine::exitDebugger()
+{
+    SDEBUG("TcfEngine::exitDebugger()");
+    manager()->notifyInferiorExited();
+}
+
+void TcfEngine::startDebugger(const DebuggerStartParametersPtr &sp)
+{
+    setState(InferiorRunningRequested);
+    showStatusMessage(tr("Running requested..."), 5000);
+    const int pos = sp->remoteChannel.indexOf(QLatin1Char(':'));
+    const QString host = sp->remoteChannel.left(pos);
+    const quint16 port = sp->remoteChannel.mid(pos + 1).toInt();
+    //QTimer::singleShot(0, this, SLOT(runInferior()));
+    m_socket->connectToHost(host, port);
+    emit startSuccessful();
+}
+
+void TcfEngine::continueInferior()
+{
+    SDEBUG("TcfEngine::continueInferior()");
+}
+
+void TcfEngine::runInferior()
+{
+}
+
+void TcfEngine::interruptInferior()
+{
+    XSDEBUG("TcfEngine::interruptInferior()");
+}
+
+void TcfEngine::executeStep()
+{
+    //SDEBUG("TcfEngine::executeStep()");
+}
+
+void TcfEngine::executeStepI()
+{
+    //SDEBUG("TcfEngine::executeStepI()");
+}
+
+void TcfEngine::executeStepOut()
+{
+    //SDEBUG("TcfEngine::executeStepOut()");
+}
+
+void TcfEngine::executeNext()
+{
+    //SDEBUG("TcfEngine::nextExec()");
+}
+
+void TcfEngine::executeNextI()
+{
+    //SDEBUG("TcfEngine::executeNextI()");
+}
+
+void TcfEngine::executeRunToLine(const QString &fileName, int lineNumber)
+{
+    Q_UNUSED(fileName)
+    Q_UNUSED(lineNumber)
+    SDEBUG("FIXME:  TcfEngine::executeRunToLine()");
+}
+
+void TcfEngine::executeRunToFunction(const QString &functionName)
+{
+    Q_UNUSED(functionName)
+    XSDEBUG("FIXME:  TcfEngine::executeRunToFunction()");
+}
+
+void TcfEngine::executeJumpToLine(const QString &fileName, int lineNumber)
+{
+    Q_UNUSED(fileName)
+    Q_UNUSED(lineNumber)
+    XSDEBUG("FIXME:  TcfEngine::executeJumpToLine()");
+}
+
+void TcfEngine::activateFrame(int index)
+{
+    Q_UNUSED(index)
+}
+
+void TcfEngine::selectThread(int index)
+{
+    Q_UNUSED(index)
+}
+
+void TcfEngine::attemptBreakpointSynchronization()
+{
+}
+
+void TcfEngine::loadSymbols(const QString &moduleName)
+{
+    Q_UNUSED(moduleName)
+}
+
+void TcfEngine::loadAllSymbols()
+{
+}
+
+void TcfEngine::reloadModules()
+{
+}
+
+void TcfEngine::requestModuleSymbols(const QString &moduleName)
+{
+    Q_UNUSED(moduleName)
+}
+
+
+void TcfEngine::handleResponse(const QByteArray &response)
+{
+    static QTime lastTime;
+
+    //debugMessage(_("            "), currentTime());
+    QList<QByteArray> parts = response.split('\0');
+    if (parts.size() < 2 || !parts.last().isEmpty()) {
+        SDEBUG("WRONG RESPONSE PACKET LAYOUT" << parts);
+        //if (response.isEmpty())
+            acknowledgeResult();
+        return;
+    }
+    parts.removeLast(); // always empty
+    QByteArray tag = parts.at(0);
+    int n = parts.size();
+    if (n == 2 && tag == "N") { // unidentified command
+        int token = parts.at(1).toInt();
+        TcfCommand tcf = m_cookieForToken[token];
+        SDEBUG("COMMAND NOT RECOGNIZED FOR TOKEN" << token << tcf.toString());
+        showDebuggerOutput(LogOutput, QString::number(token) + "^"
+               + "NOT RECOQNIZED: " + quoteUnprintableLatin1(response));
+        acknowledgeResult();
+    } else if (n == 2 && tag == "F") { // flow control
+        m_congestion = parts.at(1).toInt();
+        SDEBUG("CONGESTION: " << m_congestion);
+    } else if (n == 4 && tag == "R") { // result data
+        acknowledgeResult();
+        int token = parts.at(1).toInt();
+        QByteArray message = parts.at(2);
+        JsonValue data(parts.at(3));
+        showDebuggerOutput(LogOutput, QString("%1^%2%3").arg(token)
+            .arg(quoteUnprintableLatin1(response))
+            .arg(QString::fromUtf8(data.toString())));
+        TcfCommand tcf = m_cookieForToken[token];
+        JsonValue result(data);
+        SDEBUG("GOOD RESPONSE: " << quoteUnprintableLatin1(response));
+        if (tcf.callback)
+            (this->*(tcf.callback))(result, tcf.cookie);
+    } else if (n == 3 && tag == "P") { // progress data (partial result)
+        //int token = parts.at(1).toInt();
+        QByteArray data = parts.at(2);
+        SDEBUG(_("\nTCF PARTIAL:") << quoteUnprintableLatin1(response));
+    } else if (n == 4 && tag == "E") { // an event
+        QByteArray service = parts.at(1);
+        QByteArray eventName = parts.at(2);
+        JsonValue data(parts.at(3));
+        if (eventName != "peerHeartBeat")
+            SDEBUG(_("\nTCF EVENT:") << quoteUnprintableLatin1(response)
+                << data.toString());
+        if (service == "Locator" && eventName == "Hello") {
+            m_services.clear();
+            foreach (const JsonValue &service, data.children())
+                m_services.append(service.data());
+            QTimer::singleShot(0, this, SLOT(startDebugging()));
+        }
+    } else {
+        SDEBUG("UNKNOWN RESPONSE PACKET:"
+            << quoteUnprintableLatin1(response) << parts);
+    }
+}
+
+void TcfEngine::startDebugging()
+{
+    //foreach (const QByteArray &service, m_services) {
+    //    postCommand(CB(handleRunControlGetChildren),
+    //        service, "getChildren", "\"\"");
+    //}
+
+    postCommand(C("Diagnostics", "getChildren", "\"\""),
+        CB(handleRunControlGetChildren));
+    postCommand(C("Streams", "getChildren", "\"\""));
+    postCommand(C("Expressions", "getChildren", "\"\""));
+    postCommand(C("SysMonitor", "getChildren", "\"\""));
+    //postCommand(C("FileSystem", "getChildren", "\"\""));
+    //postCommand(C("Processes", "getChildren", "\"\""));
+    //postCommand(CB(handleRunControlGetChildren), "LineNumbers", "getChildren");
+    //postCommand(CB(handleRunControlGetChildren), "Symbols", "getChildren");
+    //postCommand(CB(handleRunControlGetChildren), "StackTrace", "getChildren");
+    //postCommand(CB(handleRunControlGetChildren), "Registers", "getChildren");
+    //postCommand(CB(handleRunControlGetChildren), "Memory", "getChildren");
+    //postCommand(CB(handleRunControlGetChildren), "Breakpoints", "getChildren");
+    //postCommand(CB(handleRunControlGetChildren), "RunControl", "getChildren");
+    //postCommand(CB(handleRunControlGetChildren), "Locator", "getChildren");
+
+
+    //postCommand(CB(handleRunControlSuspend),
+    //    "RunControl", "suspend", "\"Thread1\"");
+    //postCommand(CB(handleRunControlSuspend),
+    //    "RunControl", "getContext", "\"P12318\"");
+
+    //postCommand(C("Locator", "sync"), CB(handleRunControlGetChildren));
+    //postCommand("Locator", "redirect", "ID");
+
+    //postCommand(C("FileSystem", "open", "\"/bin/ls\"", "1", "2", "3"),
+    //    CB(handleRunControlGetChildren));
+    postCommand(C("FileSystem", "stat", "\"/bin/ls\""),
+        CB(handleRunControlGetChildren));
+}
+
+void TcfEngine::postCommand(const QByteArray &cmd,
+    TcfCommandCallback callback, const char *callbackName)
+{
+    static int token = 20;
+    ++token;
+    
+    //const char marker_eom = -1;
+    //const char marker_eos = -2;
+    //const char marker_null = -3;
+
+    QByteArray ba = "C";
+    ba.append('\0');
+    ba.append(QByteArray::number(token));
+    ba.append('\0');
+    ba.append(cmd);
+    ba.append('\0');
+    ba.append('\3');
+    ba.append('\1');
+
+    TcfCommand tcf;
+    tcf.command = ba;
+    tcf.callback = callback;
+    tcf.callbackName = callbackName;
+    tcf.token = token;
+
+    m_cookieForToken[token] = tcf;
+
+    enqueueCommand(tcf);
+}
+
+// Congestion control does not seem to work that way. Basically it's
+// already too late when we get a flow control packet
+void TcfEngine::enqueueCommand(const TcfCommand &cmd)
+{
+#ifdef USE_CONGESTION_CONTROL
+    // congestion controled
+    if (m_congestion <= 0 && m_sendQueue.isEmpty()) {
+        //SDEBUG("DIRECT SEND" << cmd.toString());
+        sendCommandNow(cmd);
+    } else {
+        SDEBUG("QUEUE " << cmd.toString());
+        m_sendQueue.enqueue(cmd);
+        m_sendTimer.start();
+    }
+#else
+    // synchrounously
+    if (m_inAir == 0)
+        sendCommandNow(cmd);
+    else
+        m_sendQueue.enqueue(cmd);
+#endif
+}
+
+void TcfEngine::handleSendTimer()
+{
+    QTC_ASSERT(!m_sendQueue.isEmpty(), return);
+
+    if (m_congestion > 0) {
+        // not ready...
+        SDEBUG("WAITING FOR CONGESTION TO GO DOWN...");
+        m_sendTimer.start();
+    } else {
+        // go!
+        sendCommandNow(m_sendQueue.dequeue());
+    }
+}
+
+void TcfEngine::sendCommandNow(const TcfCommand &cmd)
+{
+    ++m_inAir;
+    int result = m_socket->write(cmd.command);
+    Q_UNUSED(result)
+    m_socket->flush();
+    showDebuggerInput(LogInput, QString::number(cmd.token) + " " + cmd.toString());
+    SDEBUG("SEND " <<  cmd.toString()); //<< " " << QString::number(result));
+}
+
+void TcfEngine::acknowledgeResult()
+{
+#if !defined(USE_CONGESTION_CONTROL)
+    QTC_ASSERT(m_inAir == 1, /**/);
+    m_inAir = 0;
+    if (!m_sendQueue.isEmpty())
+        sendCommandNow(m_sendQueue.dequeue());
+#endif
+}
+
+void TcfEngine::handleRunControlSuspend(const JsonValue &data, const QVariant &)
+{
+    SDEBUG("HANDLE RESULT" << data.toString());
+}
+
+void TcfEngine::handleRunControlGetChildren(const JsonValue &data, const QVariant &)
+{
+    SDEBUG("HANDLE RUN CONTROL GET CHILDREN" << data.toString());
+}
+
+void TcfEngine::handleSysMonitorGetChildren(const JsonValue &data, const QVariant &)
+{
+    SDEBUG("HANDLE RUN CONTROL GET CHILDREN" << data.toString());
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Tooltip specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+static WatchData m_toolTip;
+static QPoint m_toolTipPos;
+static QHash<QString, WatchData> m_toolTipCache;
+
+void TcfEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos)
+{
+    Q_UNUSED(mousePos)
+    Q_UNUSED(editor)
+    Q_UNUSED(cursorPos)
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// Watch specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+void TcfEngine::assignValueInDebugger(const QString &expression,
+    const QString &value)
+{
+    XSDEBUG("ASSIGNING: " << expression + '=' + value);
+    updateLocals();
+}
+
+void TcfEngine::updateLocals()
+{
+}
+
+void TcfEngine::updateWatchData(const WatchData &)
+{
+    //qq->watchHandler()->rebuildModel();
+    showStatusMessage(tr("Stopped."), 5000);
+}
+
+void TcfEngine::updateSubItem(const WatchData &data0)
+{
+    Q_UNUSED(data0)
+    QTC_ASSERT(false, return);
+}
+
+void TcfEngine::debugMessage(const QString &msg)
+{
+    showDebuggerOutput(LogDebug, msg);
+}
+
+IDebuggerEngine *createTcfEngine(DebuggerManager *manager)
+{
+    return new TcfEngine(manager);
+}
+
+} // namespace Internal
+} // namespace Debugger
diff --git a/src/plugins/debugger/tcf/tcfengine.h b/src/plugins/debugger/tcf/tcfengine.h
new file mode 100644 (file)
index 0000000..79b8079
--- /dev/null
@@ -0,0 +1,168 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DEBUGGER_TCFENGINE_H
+#define DEBUGGER_TCFENGINE_H
+
+#include <QtCore/QByteArray>
+#include <QtCore/QHash>
+#include <QtCore/QMap>
+#include <QtCore/QObject>
+#include <QtCore/QPoint>
+#include <QtCore/QProcess>
+#include <QtCore/QQueue>
+#include <QtCore/QSet>
+#include <QtCore/QTimer>
+#include <QtCore/QVariant>
+
+#include <QtNetwork/QAbstractSocket>
+
+QT_BEGIN_NAMESPACE
+class QTcpSocket;
+QT_END_NAMESPACE
+
+#include "idebuggerengine.h"
+#include "debuggermanager.h"
+#include "json.h"
+
+namespace Debugger {
+namespace Internal {
+
+class ScriptAgent;
+class WatchData;
+
+class TcfEngine : public IDebuggerEngine
+{
+    Q_OBJECT
+
+public:
+    explicit TcfEngine(DebuggerManager *parent);
+    ~TcfEngine();
+
+private:
+    // IDebuggerEngine implementation
+    void executeStep();
+    void executeStepOut();
+    void executeNext();
+    void executeStepI();
+    void executeNextI();
+
+    void shutdown();
+    void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos);
+    void startDebugger(const DebuggerStartParametersPtr &sp);
+    void exitDebugger();
+
+    void continueInferior();
+    Q_SLOT void runInferior();
+    void interruptInferior();
+
+    void executeRunToLine(const QString &fileName, int lineNumber);
+    void executeRunToFunction(const QString &functionName);
+    void executeJumpToLine(const QString &fileName, int lineNumber);
+
+    void activateFrame(int index);
+    void selectThread(int index);
+
+    void attemptBreakpointSynchronization();
+
+    void assignValueInDebugger(const QString &expr, const QString &value);
+    void executeDebuggerCommand(const QString & command);
+
+    void loadSymbols(const QString &moduleName);
+    void loadAllSymbols();
+    void requestModuleSymbols(const QString &moduleName);
+    void reloadModules();
+    void reloadRegisters() {}
+    void reloadSourceFiles() {}
+    void reloadFullStack() {}
+
+    bool supportsThreads() const { return true; }
+    void maybeBreakNow(bool byFunction);
+    void updateWatchData(const WatchData &data);
+    void updateLocals();
+    void updateSubItem(const WatchData &data);
+
+    Q_SLOT void socketConnected();
+    Q_SLOT void socketDisconnected();
+    Q_SLOT void socketError(QAbstractSocket::SocketError);
+    Q_SLOT void socketReadyRead();
+
+    void handleResponse(const QByteArray &ba);
+    void handleRunControlSuspend(const JsonValue &response, const QVariant &);
+    void handleRunControlGetChildren(const JsonValue &response, const QVariant &);
+    void handleSysMonitorGetChildren(const JsonValue &response, const QVariant &);
+
+private:
+    Q_SLOT void startDebugging();
+
+    typedef void (TcfEngine::*TcfCommandCallback)
+        (const JsonValue &record, const QVariant &cookie);
+
+    struct TcfCommand
+    {
+        TcfCommand() : flags(0), token(-1), callback(0), callbackName(0) {}
+
+        QString toString() const;
+
+        int flags;
+        int token;
+        TcfCommandCallback callback;
+        const char *callbackName;
+        QByteArray command;
+        QVariant cookie;
+    };
+
+    void postCommand(const QByteArray &cmd,
+        TcfCommandCallback callback = 0, const char *callbackName = 0);
+    void sendCommandNow(const TcfCommand &command);
+    void debugMessage(const QString &msg);
+
+    QHash<int, TcfCommand> m_cookieForToken;
+
+    QQueue<TcfCommand> m_sendQueue;
+    
+    // timer based congestion control. does not seem to work well.
+    void enqueueCommand(const TcfCommand &command);
+    Q_SLOT void handleSendTimer();
+    int m_congestion;
+    QTimer m_sendTimer;
+
+    // synchrounous communication
+    void acknowledgeResult();
+    int m_inAir;
+
+    QTcpSocket *m_socket;
+    QByteArray m_inbuffer;
+    QList<QByteArray> m_services;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_TCFENGINE_H
diff --git a/src/plugins/debugger/threadshandler.cpp b/src/plugins/debugger/threadshandler.cpp
new file mode 100644 (file)
index 0000000..3cd67a9
--- /dev/null
@@ -0,0 +1,205 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "threadshandler.h"
+
+namespace Debugger {
+namespace Internal {
+
+////////////////////////////////////////////////////////////////////////
+//
+// ThreadsHandler
+//
+///////////////////////////////////////////////////////////////////////
+
+ThreadData::ThreadData(int threadId)
+{
+    notifyRunning();
+    id = threadId;
+}
+
+void ThreadData::notifyRunning()
+{
+    address = 0;
+    function.clear();
+    fileName.clear();
+    frameLevel = -1;
+    state.clear();
+    lineNumber = -1;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// ThreadsHandler
+//
+///////////////////////////////////////////////////////////////////////
+
+ThreadsHandler::ThreadsHandler(QObject *parent)  :
+    QAbstractTableModel(parent),
+    m_currentIndex(0),
+    m_positionIcon(QLatin1String(":/debugger/images/location_16.png")),
+    m_emptyIcon(QLatin1String(":/debugger/images/debugger_empty_14.png"))
+{
+}
+
+int ThreadsHandler::rowCount(const QModelIndex &parent) const
+{
+    // Since the stack is not a tree, row count is 0 for any valid parent
+    return parent.isValid() ? 0 : m_threads.size();
+}
+
+int ThreadsHandler::columnCount(const QModelIndex &parent) const
+{
+    return parent.isValid() ? 0 : int(ThreadData::ColumnCount);
+}
+
+QVariant ThreadsHandler::data(const QModelIndex &index, int role) const
+{
+    if (!index.isValid())
+        return QVariant();
+    const int row = index.row();
+    if (row  >= m_threads.size())
+        return QVariant();
+    const ThreadData &thread = m_threads.at(row);
+
+    if (role == Qt::DisplayRole) {
+        switch (index.column()) {
+        case ThreadData::IdColumn:
+            return thread.id;
+        case ThreadData::FunctionColumn:
+            return thread.function;
+        case ThreadData::FileColumn:
+            return thread.fileName;
+        case ThreadData::LineColumn:
+            return thread.lineNumber >= 0 ? QString::number(thread.lineNumber) : QString();
+        case ThreadData::AddressColumn:
+            return thread.address > 0 ? QLatin1String("0x") + QString::number(thread.address, 16) : QString();
+        case ThreadData::CoreColumn:
+            return thread.core;
+        case ThreadData::StateColumn:
+            return thread.state;
+        }
+    } else if (role == Qt::ToolTipRole) {
+        if (thread.address == 0)
+            return tr("Thread: %1").arg(thread.id);
+        // Stopped
+        if (thread.fileName.isEmpty())
+            return tr("Thread: %1 at %2 (0x%3)").arg(thread.id).arg(thread.function).arg(thread.address, 0, 16);
+        return tr("Thread: %1 at %2, %3:%4 (0x%5)").
+                arg(thread.id).arg(thread.function, thread.fileName).arg(thread.lineNumber).arg(thread.address, 0, 16);
+    } else if (role == Qt::DecorationRole && index.column() == 0) {
+        // Return icon that indicates whether this is the active stack frame
+        return (index.row() == m_currentIndex) ? m_positionIcon : m_emptyIcon;
+    }
+
+    return QVariant();
+}
+
+QVariant ThreadsHandler::headerData(int section, Qt::Orientation orientation, int role) const
+{
+    if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
+        return QVariant();
+    switch (section) {
+    case ThreadData::IdColumn:
+        return tr("Thread ID");
+    case ThreadData::FunctionColumn:
+        return tr("Function");
+    case ThreadData::FileColumn:
+        return tr("File");
+    case ThreadData::LineColumn:
+        return tr("Line");
+    case ThreadData::AddressColumn:
+        return tr("Address");
+    case ThreadData::CoreColumn:
+        return tr("Core");
+    case ThreadData::StateColumn:
+        return tr("State");
+    }
+    return QVariant();
+}
+
+int ThreadsHandler::currentThreadId() const
+{
+    if (m_currentIndex < 0 || m_currentIndex >= m_threads.size())
+        return -1;
+    return m_threads[m_currentIndex].id;
+}
+
+void ThreadsHandler::setCurrentThread(int index)
+{
+    if (index == m_currentIndex)
+        return;
+
+    // Emit changed for previous frame
+    QModelIndex i = ThreadsHandler::index(m_currentIndex, 0);
+    emit dataChanged(i, i);
+
+    m_currentIndex = index;
+
+    // Emit changed for new frame
+    i = ThreadsHandler::index(m_currentIndex, 0);
+    emit dataChanged(i, i);
+}
+
+void ThreadsHandler::setThreads(const QList<ThreadData> &threads)
+{
+    m_threads = threads;
+    if (m_currentIndex >= m_threads.size())
+        m_currentIndex = m_threads.size() - 1;
+    reset();
+}
+
+QList<ThreadData> ThreadsHandler::threads() const
+{
+    return m_threads;
+}
+
+void ThreadsHandler::removeAll()
+{
+    m_threads.clear();
+    m_currentIndex = 0;
+    reset();
+}
+
+void ThreadsHandler::notifyRunning()
+{
+    // Threads stopped (that is, address != 0 showing)?
+    if (m_threads.empty())
+        return;
+    if (m_threads.front().address == 0)
+        return;
+    const QList<ThreadData>::iterator end = m_threads.end();
+    for (QList<ThreadData>::iterator it = m_threads.begin(); it != end; ++it)
+        it->notifyRunning();
+    emit dataChanged(index(0, 1),
+        index(m_threads.size() - 1, ThreadData::ColumnCount - 1));
+}
+
+} // namespace Internal
+} // namespace Debugger
diff --git a/src/plugins/debugger/threadshandler.h b/src/plugins/debugger/threadshandler.h
new file mode 100644 (file)
index 0000000..10e242a
--- /dev/null
@@ -0,0 +1,122 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef THREADSHANDLER_H
+#define THREADSHANDLER_H
+
+#include <QtCore/QAbstractTableModel>
+#include <QtCore/QList>
+
+#include <QtGui/QIcon>
+
+
+namespace Debugger {
+namespace Internal {
+
+////////////////////////////////////////////////////////////////////////
+//
+// ThreadData
+//
+////////////////////////////////////////////////////////////////////////
+
+/*! A structure containing information about a single thread */
+struct ThreadData
+{
+    ThreadData(int threadId = 0);
+
+    enum {
+        IdColumn,
+        AddressColumn,
+        FunctionColumn,
+        FileColumn,
+        LineColumn,
+        StateColumn,
+        CoreColumn,
+        ColumnCount = CoreColumn
+    };
+
+    // Permanent data.
+    int id;
+    QString targetId;
+    QString core;
+
+    // State information when stopped
+    void notifyRunning(); // Clear state information
+
+    int frameLevel;
+    quint64 address;
+    QString function;
+    QString fileName;
+    QString state;
+    int lineNumber;
+};
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// ThreadsHandler
+//
+////////////////////////////////////////////////////////////////////////
+
+/*! A model to represent the running threads in a QTreeView or ComboBox */
+class ThreadsHandler : public QAbstractTableModel
+{
+    Q_OBJECT
+
+public:
+    ThreadsHandler(QObject *parent = 0);
+
+    int currentThreadId() const;
+    void setCurrentThread(int index);
+    void selectThread(int index);
+    void setThreads(const QList<ThreadData> &threads);
+    void removeAll();
+    QList<ThreadData> threads() const;
+    QAbstractItemModel *threadsModel() { return this; }
+
+    // Clear out all frame information
+    void notifyRunning();
+
+private:
+    int rowCount(const QModelIndex &parent = QModelIndex()) const;
+    int columnCount(const QModelIndex &parent = QModelIndex()) const;
+    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+
+private:
+    QList<ThreadData> m_threads;
+    int m_currentIndex;
+    const QIcon m_positionIcon;
+    const QIcon m_emptyIcon;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // THREADSHANDLER_H
index b4cfd13..c74d4ef 100644 (file)
@@ -120,6 +120,10 @@ WatchModel::WatchModel(WatchHandler *handler, WatchType type)
     m_root->parent = 0;
 
     switch (m_type) {
+        case ReturnWatch:
+            m_root->iname = "return";
+            m_root->name = WatchHandler::tr("Return Value");
+            break;
         case LocalsWatch:
             m_root->iname = "local";
             m_root->name = WatchHandler::tr("Locals");
@@ -560,6 +564,23 @@ static inline QString truncateValue(QString v)
     return v;
 }
 
+// Get a pointer address from pointer values reported by the debugger.
+// Fix CDB formatting of pointers "0x00000000`000003fd class foo *",
+// check gdb formatting of characters.
+static inline quint64 pointerValue(QString data)
+{
+    if (data.isEmpty() || !data.startsWith(QLatin1String("0x")))
+        return 0;
+    data.remove(0, 2);
+    const int blankPos = data.indexOf(QLatin1Char(' '));
+    if (blankPos != -1)
+        data.truncate(blankPos);
+    data.remove(QLatin1Char('`'));
+    bool ok;
+    const quint64 address = data.toULongLong(&ok, 16);
+    return ok ? address : quint64(0);
+}
+
 QVariant WatchModel::data(const QModelIndex &idx, int role) const
 {
     const WatchItem *item = watchItem(idx);
@@ -632,16 +653,22 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
         case IndividualFormatRole:
             return m_handler->m_individualFormats.value(data.addr, -1);
 
-        case AddressRole: {
-            if (!data.addr.isEmpty())
-                return data.addr;
-            bool ok;
-            (void) data.value.toULongLong(&ok, 0);
-            if (ok)
-                return data.value;
-            return QVariant();
-        }
+        case AddressRole:
+            if (!data.addr.isEmpty()) {
+                bool ok;
+                const quint64 address = data.addr.toULongLong(&ok, 16);
+                if (ok)
+                    return QVariant(address);
+            }
+            return QVariant(quint64(0));
+
+        case RawValueRole:
+            return data.value;
 
+        case PointerValue:
+            if (isPointerType(data.type))
+                return pointerValue(data.value);
+            return QVariant(quint64(0));
         default:
             break;
     }
@@ -964,6 +991,7 @@ WatchHandler::WatchHandler(DebuggerManager *manager)
     m_expandPointers = true;
     m_inChange = false;
 
+    m_return = new WatchModel(this, ReturnWatch);
     m_locals = new WatchModel(this, LocalsWatch);
     m_watchers = new WatchModel(this, WatchersWatch);
     m_tooltips = new WatchModel(this, TooltipsWatch);
@@ -981,6 +1009,7 @@ WatchHandler::WatchHandler(DebuggerManager *manager)
 void WatchHandler::beginCycle()
 {
     ++generationCounter;
+    m_return->beginCycle();
     m_locals->beginCycle();
     m_watchers->beginCycle();
     m_tooltips->beginCycle();
@@ -988,6 +1017,7 @@ void WatchHandler::beginCycle()
 
 void WatchHandler::endCycle()
 {
+    m_return->endCycle();
     m_locals->endCycle();
     m_watchers->endCycle();
     m_tooltips->endCycle();
@@ -997,8 +1027,10 @@ void WatchHandler::endCycle()
 void WatchHandler::cleanup()
 {
     m_expandedINames.clear();
+    m_return->reinitialize();
     m_locals->reinitialize();
     m_tooltips->reinitialize();
+    m_return->m_fetchTriggered.clear();
     m_locals->m_fetchTriggered.clear();
     m_watchers->m_fetchTriggered.clear();
     m_tooltips->m_fetchTriggered.clear();
@@ -1014,6 +1046,7 @@ void WatchHandler::cleanup()
 
 void WatchHandler::emitAllChanged()
 {
+    m_return->emitAllChanged();
     m_locals->emitAllChanged();
     m_watchers->emitAllChanged();
     m_tooltips->emitAllChanged();
@@ -1337,6 +1370,7 @@ void WatchHandler::loadSessionData()
 WatchModel *WatchHandler::model(WatchType type) const
 {
     switch (type) {
+        case ReturnWatch: return m_return;
         case LocalsWatch: return m_locals;
         case WatchersWatch: return m_watchers;
         case TooltipsWatch: return m_tooltips;
@@ -1347,6 +1381,8 @@ WatchModel *WatchHandler::model(WatchType type) const
 
 WatchModel *WatchHandler::modelForIName(const QByteArray &iname) const
 {
+    if (iname.startsWith("return"))
+        return m_return;
     if (iname.startsWith("local"))
         return m_locals;
     if (iname.startsWith("tooltip"))
@@ -1372,8 +1408,12 @@ QString WatchHandler::watcherEditPlaceHolder()
 
 void WatchHandler::setFormat(const QString &type, int format)
 {
-    m_typeFormats[type] = format;
+    if (format == -1)
+        m_typeFormats.remove(type);
+    else
+        m_typeFormats[type] = format;
     saveTypeFormats();
+    m_return->emitDataChanged(1);
     m_locals->emitDataChanged(1);
     m_watchers->emitDataChanged(1);
     m_tooltips->emitDataChanged(1);
index 8890dee..daf8507 100644 (file)
@@ -51,7 +51,7 @@ namespace Internal {
 
 class WatchItem;
 class WatchHandler;
-enum WatchType { LocalsWatch, WatchersWatch, TooltipsWatch };
+enum WatchType { ReturnWatch, LocalsWatch, WatchersWatch, TooltipsWatch };
 
 enum WatchRoles
 {
@@ -61,7 +61,9 @@ enum WatchRoles
     TypeFormatListRole,
     TypeFormatRole,  // Used to communicate alternative formats to the view.
     IndividualFormatRole,
-    AddressRole,     // Some memory address related to the object.
+    AddressRole,     // Memory address of variable as quint64.
+    RawValueRole,    // Unformatted value as string.
+    PointerValue     // Pointer value (address) as quint64.
 };
 
 enum IntegerFormat
@@ -206,6 +208,7 @@ private:
     // Items expanded in the Locals & Watchers view.
     QSet<QByteArray> m_expandedINames; 
 
+    WatchModel *m_return;
     WatchModel *m_locals;
     WatchModel *m_watchers;
     WatchModel *m_tooltips;
index 46a6989..3b625d5 100644 (file)
@@ -361,7 +361,7 @@ int getUninitializedVariablesI(const CPlusPlus::Snapshot &snapshot,
     const CPlusPlus::Document::Ptr doc = docIt.value();
     // Look at symbol at line and find its function. Either it is the
     // function itself or some expression/variable.
-    const CPlusPlus::Symbol *symbolAtLine = doc->findSymbolAt(line, 0);
+    const CPlusPlus::Symbol *symbolAtLine = doc->lastVisibleSymbolAt(line, 0);
     if (!symbolAtLine)
         return 4;
     // First figure out the function to do a safety name check
index af07154..243aaad 100644 (file)
@@ -30,6 +30,8 @@
 #include "watchwindow.h"
 #include "watchhandler.h"
 
+#include "breakpoint.h"
+#include "breakhandler.h"
 #include "debuggeractions.h"
 #include "debuggeragents.h"
 #include "debuggerdialogs.h"
@@ -202,20 +204,36 @@ void WatchWindow::dropEvent(QDropEvent *ev)
     //QTreeView::dropEvent(ev);
 }
 
+static inline void toggleWatchPoint(DebuggerManager *manager, quint64 address)
+{
+    const QByteArray addressBA = QByteArray("0x") + QByteArray::number(address, 16);
+    const int index = manager->breakHandler()->findWatchPointIndexByAddress(addressBA);
+    if (index == -1) {
+        BreakpointData *data = new BreakpointData;
+        data->type = BreakpointData::WatchpointType;
+        data->address = addressBA;
+        manager->breakHandler()->appendBreakpoint(data);
+    } else {
+        manager->breakHandler()->removeBreakpoint(index);
+    }
+    manager->attemptBreakpointSynchronization();
+}
+
 void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
 {
     const QModelIndex idx = indexAt(ev->pos());
     const QModelIndex mi0 = idx.sibling(idx.row(), 0);
     const QModelIndex mi1 = idx.sibling(idx.row(), 1);
     const QModelIndex mi2 = idx.sibling(idx.row(), 2);
-    const QString addr = model()->data(mi0, AddressRole).toString();
+    const quint64 address = model()->data(mi0, AddressRole).toULongLong();
+    const quint64 pointerValue = model()->data(mi0, PointerValue).toULongLong();
     const QString exp = model()->data(mi0, ExpressionRole).toString();
     const QString type = model()->data(mi2).toString();
 
     const QStringList alternativeFormats =
         model()->data(mi0, TypeFormatListRole).toStringList();
     const int typeFormat =
-        qMax(int(DecimalFormat), model()->data(mi0, TypeFormatRole).toInt());
+        model()->data(mi0, TypeFormatRole).toInt();
     const int individualFormat =
         model()->data(mi0, IndividualFormatRole).toInt();
     const int effectiveIndividualFormat =
@@ -223,12 +241,18 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
 
     QMenu typeFormatMenu;
     QList<QAction *> typeFormatActions;
+    QAction *clearTypeFormatAction = 0;
     if (idx.isValid()) {
         typeFormatMenu.setTitle(
             tr("Change Format for Type \"%1\"").arg(type));
         if (alternativeFormats.isEmpty()) {
             typeFormatMenu.setEnabled(false);
         } else {
+            clearTypeFormatAction = typeFormatMenu.addAction(tr("Clear"));
+            clearTypeFormatAction->setEnabled(typeFormat != -1);
+            clearTypeFormatAction->setCheckable(true);
+            clearTypeFormatAction->setChecked(typeFormat == -1);
+            typeFormatMenu.addSeparator();
             for (int i = 0; i != alternativeFormats.size(); ++i) {
                 const QString format = alternativeFormats.at(i);
                 QAction *act = new QAction(format, &typeFormatMenu);
@@ -247,14 +271,16 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
     QMenu individualFormatMenu;
     QList<QAction *> individualFormatActions;
     QAction *clearIndividualFormatAction = 0;
-    if (idx.isValid() && !addr.isEmpty()) {
+    if (idx.isValid() && address) {
         individualFormatMenu.setTitle(
-            tr("Change Format for Object at %1").arg(addr));
+            tr("Change Format for Object at 0x%1").arg(address, 0, 16));
         if (alternativeFormats.isEmpty()) {
             individualFormatMenu.setEnabled(false);
         } else {
             clearIndividualFormatAction = individualFormatMenu.addAction(tr("Clear"));
             clearIndividualFormatAction->setEnabled(individualFormat != -1);
+            clearIndividualFormatAction->setCheckable(true);
+            clearIndividualFormatAction->setChecked(individualFormat == -1);
             individualFormatMenu.addSeparator();
             for (int i = 0; i != alternativeFormats.size(); ++i) {
                 const QString format = alternativeFormats.at(i);
@@ -282,17 +308,44 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
     QAction *actSelectWidgetToWatch = menu.addAction(tr("Select Widget to Watch"));
     actSelectWidgetToWatch->setEnabled(canHandleWatches);
 
-    const QString address = model()->data(mi0, AddressRole).toString();
-    QAction *actWatchKnownMemory = 0;
-    QAction *actWatchUnknownMemory = new QAction(tr("Open Memory Editor..."), &menu);
+    QAction *actOpenMemoryEditAtVariableAddress = 0;
+    QAction *actOpenMemoryEditAtPointerValue = 0;
+    QAction *actOpenMemoryEditor =
+        new QAction(tr("Open Memory Editor..."), &menu);
     const bool canShowMemory = engineCapabilities & ShowMemoryCapability;
-    actWatchUnknownMemory->setEnabled(actionsEnabled && canShowMemory);
+    actOpenMemoryEditor->setEnabled(actionsEnabled && canShowMemory);
+
+    // Offer to open address pointed to or variable address.
+    const bool createPointerActions = pointerValue &&  pointerValue != address;
 
-    if (canShowMemory && !address.isEmpty())
-        actWatchKnownMemory =
-            new QAction(tr("Open Memory Editor at %1").arg(address), &menu);
+    if (canShowMemory && address)
+        actOpenMemoryEditAtVariableAddress =
+            new QAction(tr("Open Memory Editor at Object's Address (0x%1)").arg(address, 0, 16), &menu);
+    if (createPointerActions)
+        actOpenMemoryEditAtPointerValue =
+                new QAction(tr("Open Memory Editor at Referenced Address (0x%1)").arg(pointerValue, 0, 16), &menu);
     menu.addSeparator();
 
+    QAction *actSetWatchPointAtVariableAddress = 0;
+    QAction *actSetWatchPointAtPointerValue= 0;
+    const bool canSetWatchpoint = engineCapabilities & WatchpointCapability;
+    if (canSetWatchpoint && address) {
+        actSetWatchPointAtVariableAddress =
+            new QAction(tr("Break on Changes at Object's Address (0x%1)").arg(address, 0, 16), &menu);
+        actSetWatchPointAtVariableAddress->setCheckable(true);
+        actSetWatchPointAtVariableAddress->setChecked(m_manager->breakHandler()->watchPointAt(address));
+        if (createPointerActions) {
+            actSetWatchPointAtPointerValue =
+                    new QAction(tr("Break on Changes at Referenced Address (0x%1)").arg(pointerValue, 0, 16), &menu);
+            actSetWatchPointAtPointerValue->setCheckable(true);
+            actSetWatchPointAtPointerValue->setChecked(m_manager->breakHandler()->watchPointAt(pointerValue));
+        }
+    } else {
+        actSetWatchPointAtVariableAddress =
+            new QAction(tr("Break on Changing Contents"), &menu);
+        actSetWatchPointAtVariableAddress->setEnabled(false);
+    }
+
     QAction *actWatchOrRemove;
     if (m_type == LocalsType) {
         actWatchOrRemove = theDebuggerAction(WatchExpression)->updatedAction(exp);
@@ -308,9 +361,14 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
     menu.addAction(actSelectWidgetToWatch);
     menu.addMenu(&typeFormatMenu);
     menu.addMenu(&individualFormatMenu);
-    if (actWatchKnownMemory)
-        menu.addAction(actWatchKnownMemory);
-    menu.addAction(actWatchUnknownMemory);
+    if (actOpenMemoryEditAtVariableAddress)
+        menu.addAction(actOpenMemoryEditAtVariableAddress);
+    if (actOpenMemoryEditAtPointerValue)
+        menu.addAction(actOpenMemoryEditAtPointerValue);
+    menu.addAction(actOpenMemoryEditor);
+    menu.addAction(actSetWatchPointAtVariableAddress);
+    if (actSetWatchPointAtPointerValue)
+        menu.addAction(actSetWatchPointAtPointerValue);
     menu.addSeparator();
 
     menu.addAction(theDebuggerAction(RecheckDebuggingHelpers));
@@ -338,6 +396,8 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
     menu.addAction(theDebuggerAction(SettingsDialog));
 
     QAction *act = menu.exec(ev->globalPos());
+    if (act == 0)
+        return;
 
     if (act == actAdjustColumnWidths) {
         resizeColumnsToContents();
@@ -346,19 +406,27 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
     } else if (act == actInsertNewWatchItem) {
         theDebuggerAction(WatchExpression)
             ->trigger(WatchHandler::watcherEditPlaceHolder());
-    } else if (actWatchKnownMemory != 0 && act == actWatchKnownMemory) {
+    } else if (act == actOpenMemoryEditAtVariableAddress) {
         (void) new MemoryViewAgent(m_manager, address);
-    } else if (actWatchUnknownMemory != 0 && act == actWatchUnknownMemory) {
+    } else if (act == actOpenMemoryEditAtPointerValue) {
+        (void) new MemoryViewAgent(m_manager, pointerValue);
+    } else if (act == actOpenMemoryEditor) {
         AddressDialog dialog;
         if (dialog.exec() == QDialog::Accepted) {
             (void) new MemoryViewAgent(m_manager, dialog.address());
         }
+    } else if (act == actSetWatchPointAtVariableAddress) {
+        toggleWatchPoint(m_manager, address);
+    } else if (act == actSetWatchPointAtPointerValue) {
+        toggleWatchPoint(m_manager, pointerValue);
     } else if (act == actSelectWidgetToWatch) {
         grabMouse(Qt::CrossCursor);
         m_grabbing = true;
     } else if (act == actClearCodeModelSnapshot) {
         m_manager->clearCppCodeModelSnapshot();
-    } else if (clearIndividualFormatAction && act == clearIndividualFormatAction) {
+    } else if (act == clearTypeFormatAction) {
+        model()->setData(mi1, -1, TypeFormatRole);
+    } else if (act == clearIndividualFormatAction) {
         model()->setData(mi1, -1, IndividualFormatRole);
     } else {
         for (int i = 0; i != typeFormatActions.size(); ++i) {
index e252a9f..b08f928 100644 (file)
@@ -48,7 +48,7 @@ class WatchWindow : public QTreeView
     Q_OBJECT
 
 public:
-    enum Type { LocalsType, TooltipType, WatchersType };
+    enum Type { ReturnType, LocalsType, TooltipType, WatchersType };
 
     WatchWindow(Type type, DebuggerManager *manager, QWidget *parent = 0);
     void setType(Type type) { m_type = type; }
index 120a27d..aa0244f 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="Designer" version="1.3.84" compatVersion="1.3.84">
+<plugin name="Designer" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,8 +14,8 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Qt Designer integration.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="Core" version="1.3.84"/>
+        <dependency name="Core" version="2.0.80"/>
 <!-- For compiling with CPP support enabled -->
-        <dependency name="CppEditor" version="1.3.84"/>
+        <dependency name="CppEditor" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 6f1f55e..895ac3a 100644 (file)
@@ -81,6 +81,7 @@ FormWindowEditor::FormWindowEditor(Internal::DesignerXmlEditor *editor,
     connect(&(d->m_file), SIGNAL(reload(QString)), this, SLOT(slotOpen(QString)));
     // Force update of open editors model.
     connect(&(d->m_file), SIGNAL(saved()), this, SIGNAL(changed()));
+    connect(&(d->m_file), SIGNAL(changed()), this, SIGNAL(changed()));
 }
 
 FormWindowEditor::~FormWindowEditor()
index a130cc9..ce5594e 100644 (file)
@@ -91,6 +91,15 @@ bool FormWindowFile::save(const QString &name /*= QString()*/)
     return true;
 }
 
+void FormWindowFile::rename(const QString &newName)
+{
+    m_formWindow->setFileName(newName);
+    QFileInfo fi(newName);
+    m_fileName = fi.absoluteFilePath();
+    emit setDisplayName(fi.fileName());
+    emit changed();
+}
+
 QString FormWindowFile::fileName() const
 {
     return m_fileName;
index 92dbc23..42d44c7 100644 (file)
@@ -60,6 +60,7 @@ public:
     virtual QString defaultPath() const;
     virtual QString suggestedFileName() const;
     virtual QString mimeType() const;
+    virtual void rename(const QString &newName);
 
     // Internal
     void setSuggestedFileName(const QString &fileName);
index 82b0df1..99f4397 100644 (file)
@@ -44,7 +44,8 @@
 #include <cplusplus/Literals.h>
 #include <cplusplus/Scope.h>
 #include <cplusplus/Control.h>
-#include <cplusplus/LookupContext.h>
+#include <cplusplus/TranslationUnit.h>
+#include <cplusplus/DeprecatedLookupContext.h>
 #include <coreplugin/icore.h>
 #include <coreplugin/editormanager/editormanager.h>
 #include <extensionsystem/pluginmanager.h>
@@ -204,7 +205,7 @@ static const Class *findClass(const Namespace *parentNameSpace, const QString &c
     return 0;
 }
 
-static const Function *findDeclaration(const Class *cl, const QString &functionName)
+static Function *findDeclaration(const Class *cl, const QString &functionName)
 {
     const QString funName = QString::fromUtf8(QMetaObject::normalizedSignature(functionName.toUtf8()));
     const unsigned mCount = cl->memberCount();
@@ -212,8 +213,8 @@ static const Function *findDeclaration(const Class *cl, const QString &functionN
     // we are only interested in declarations of methods
     const Overview overview;
     for (unsigned j = 0; j < mCount; j++) { // go through all members
-        if (const Declaration *decl = cl->memberAt(j)->asDeclaration())
-            if (const Function *fun = decl->type()->asFunctionType()) {
+        if (Declaration *decl = cl->memberAt(j)->asDeclaration())
+            if (Function *fun = decl->type()->asFunctionType()) {
                 // Format signature
                 QString memberFunction = overview.prettyName(fun->name());
                 memberFunction += QLatin1Char('(');
@@ -234,118 +235,21 @@ static const Function *findDeclaration(const Class *cl, const QString &functionN
     return 0;
 }
 
-// TODO: remove me, see below
-static bool isCompatible(const Name *name, const Name *otherName)
-{
-    if (const NameId *nameId = name->asNameId()) {
-        if (const TemplateNameId *otherTemplId = otherName->asTemplateNameId())
-            return nameId->identifier()->isEqualTo(otherTemplId->identifier());
-    } else if (const TemplateNameId *templId = name->asTemplateNameId()) {
-        if (const NameId *otherNameId = otherName->asNameId())
-            return templId->identifier()->isEqualTo(otherNameId->identifier());
-    }
-
-    return name->isEqualTo(otherName);
-}
-
-// TODO: remove me, see below
-static bool isCompatible(const Function *definition, const Symbol *declaration, const QualifiedNameId *declarationName)
-{
-    Function *declTy = declaration->type()->asFunctionType();
-    if (! declTy)
-        return false;
-
-    const Name *definitionName = definition->name();
-    if (const QualifiedNameId *q = definitionName->asQualifiedNameId()) {
-        if (! isCompatible(q->unqualifiedNameId(), declaration->name()))
-            return false;
-        else if (q->nameCount() > declarationName->nameCount())
-            return false;
-        else if (declTy->argumentCount() != definition->argumentCount())
-            return false;
-        else if (declTy->isConst() != definition->isConst())
-            return false;
-        else if (declTy->isVolatile() != definition->isVolatile())
-            return false;
-
-        for (unsigned i = 0; i < definition->argumentCount(); ++i) {
-            Symbol *arg = definition->argumentAt(i);
-            Symbol *otherArg = declTy->argumentAt(i);
-            if (! arg->type().isEqualTo(otherArg->type()))
-                return false;
-        }
-
-        for (unsigned i = 0; i != q->nameCount(); ++i) {
-            const Name *n = q->nameAt(q->nameCount() - i - 1);
-            const Name *m = declarationName->nameAt(declarationName->nameCount() - i - 1);
-            if (! isCompatible(n, m))
-                return false;
-        }
-        return true;
-    } else {
-        // ### TODO: implement isCompatible for unqualified name ids.
-    }
-    return false;
-}
-
 // TODO: remove me, this is taken from cppeditor.cpp. Find some common place for this method
-static Document::Ptr findDefinition(const Function *functionDeclaration, int *line)
+static Document::Ptr findDefinition(Function *functionDeclaration, int *line)
 {
-    CppTools::CppModelManagerInterface *cppModelManager = cppModelManagerInstance();
-    if (!cppModelManager)
-        return Document::Ptr();
+    if (CppTools::CppModelManagerInterface *cppModelManager = cppModelManagerInstance()) {
+        const Snapshot snapshot = cppModelManager->snapshot();
 
-    QVector<const Name *> qualifiedName;
-    Scope *scope = functionDeclaration->scope();
-    for (; scope; scope = scope->enclosingScope()) {
-        if (scope->isClassScope() || scope->isNamespaceScope()) {
-            if (scope->owner() && scope->owner()->name()) {
-                const Name *scopeOwnerName = scope->owner()->name();
-                if (const QualifiedNameId *q = scopeOwnerName->asQualifiedNameId()) {
-                    for (unsigned i = 0; i < q->nameCount(); ++i) {
-                        qualifiedName.prepend(q->nameAt(i));
+        if (Symbol *def = snapshot.findMatchingDefinition(functionDeclaration)) {
+            if (line)
+                *line = def->line();
 
-}
-                } else {
-                    qualifiedName.prepend(scopeOwnerName);
-                }
-            }
+            return snapshot.document(QString::fromUtf8(def->fileName(), def->fileNameLength()));
         }
     }
 
-    qualifiedName.append(functionDeclaration->name());
-
-    Control control;
-    const QualifiedNameId *q = control.qualifiedNameId(&qualifiedName[0], qualifiedName.size());
-    LookupContext context(&control);
-    const Snapshot documents = cppModelManager->snapshot();
-    foreach (Document::Ptr doc, documents) {
-        QList<Scope *> visibleScopes;
-        visibleScopes.append(doc->globalSymbols());
-        visibleScopes = context.expand(visibleScopes);
-        foreach (Scope *visibleScope, visibleScopes) {
-            Symbol *symbol = 0;
-            if (const NameId *nameId = q->unqualifiedNameId()->asNameId())
-                symbol = visibleScope->lookat(nameId->identifier());
-            else if (const DestructorNameId *dtorId = q->unqualifiedNameId()->asDestructorNameId())
-                symbol = visibleScope->lookat(dtorId->identifier());
-            else if (const TemplateNameId *templNameId = q->unqualifiedNameId()->asTemplateNameId())
-                symbol = visibleScope->lookat(templNameId->identifier());
-            else if (const OperatorNameId *opId = q->unqualifiedNameId()->asOperatorNameId())
-                symbol = visibleScope->lookat(opId->kind());
-            // ### cast operators
-            for (; symbol; symbol = symbol->next()) {
-                if (! symbol->isFunction())
-                    continue;
-                else if (! isCompatible(symbol->asFunction(), functionDeclaration, q))
-                    continue;
-                *line = symbol->line(); // TODO: shift the line so that we are inside a function. Maybe just find the nearest '{'?
-                return doc;
-            }
-        }
-    }
     return Document::Ptr();
-
 }
 
 static bool isEndingQuote(const QString &contents, int quoteIndex)
@@ -404,8 +308,10 @@ static inline ITextEditable *editableAt(const QString &fileName, int line, int c
     return qobject_cast<ITextEditable *>(TextEditor::BaseTextEditor::openEditorAt(fileName, line, column));
 }
 
-static void addDeclaration(const QString &docFileName, const Class *cl, const QString &functionName)
+static void addDeclaration(Document::Ptr doc, const Class *cl, const QString &functionName)
 {
+    const QString docFileName = doc->fileName();
+    TranslationUnit *unit = doc->translationUnit();
     QString declaration = QLatin1String("void ");
     declaration += functionName;
     declaration += QLatin1String(";\n");
@@ -423,7 +329,7 @@ static void addDeclaration(const QString &docFileName, const Class *cl, const QS
                     const int column = fun->column();
                     if (ITextEditable *editable = editableAt(docFileName, line, column)) {
                         unsigned dl, dc; // this position is the beginning of return value: "^void foo(...)"
-                        decl->getStartPosition(&dl, &dc);
+                        unit->getPosition(decl->startOffset(), &dl, &dc);
                         dc--; // if the first character in line is 'v' coming from "void" getStartPosition returns 1, not 0, so we always decrement it.
                         editable->gotoLine(dl, dc);
                         editable->position(ITextEditor::StartOfLine);
@@ -653,7 +559,7 @@ bool QtCreatorIntegration::navigateToSlot(const QString &objectName,
     int line = 0;
     Document::Ptr sourceDoc;
 
-    if (const Function *fun = findDeclaration(cl, functionName)) {
+    if (Function *fun = findDeclaration(cl, functionName)) {
         sourceDoc = findDefinition(fun, &line);
         if (!sourceDoc) {
             // add function definition to cpp file
@@ -661,7 +567,7 @@ bool QtCreatorIntegration::navigateToSlot(const QString &objectName,
         }
     } else {
         // add function declaration to cl
-        addDeclaration(doc->fileName(), cl, functionNameWithParameterNames);
+        addDeclaration(doc, cl, functionNameWithParameterNames);
 
         // add function definition to cpp file
         sourceDoc = addDefinition(docTable, doc->fileName(), className, functionNameWithParameterNames, &line);
index 310ab21..30b8724 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="FakeVim" version="1.3.84" compatVersion="1.3.84">
+<plugin name="FakeVim" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -13,9 +13,9 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>VI-style keyboard navigation.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="CppEditor" version="1.3.84"/><!-- Plugin adds items to the editor's context menu -->
-        <dependency name="TextEditor" version="1.3.84"/>
-        <dependency name="ProjectExplorer" version="1.3.84"/>
-        <dependency name="Core" version="1.3.84"/>
+        <dependency name="CppEditor" version="2.0.80"/><!-- Plugin adds items to the editor's context menu -->
+        <dependency name="TextEditor" version="2.0.80"/>
+        <dependency name="ProjectExplorer" version="2.0.80"/>
+        <dependency name="Core" version="2.0.80"/>
     </dependencyList>
 </plugin>
index f19b5b1..a17fbe1 100644 (file)
@@ -209,10 +209,13 @@ FakeVimSettings *theFakeVimSettings()
     item->setSettingsKey(group, _("IsKeyword"));
     instance->insertItem(ConfigIsKeyword, item, _("iskeyword"), _("isk"));
 
+    // Invented here.
     item = new SavedAction(instance);
-    item->setText(QCoreApplication::translate("FakeVim::Internal",
-        "FakeVim properties..."));
-    instance->insertItem(SettingsDialog, item);
+    item->setDefaultValue(false);
+    item->setValue(false);
+    item->setSettingsKey(group, _("ShowMarks"));
+    item->setCheckable(true);
+    instance->insertItem(ConfigShowMarks, item, _("showmarks"), _("sm"));
 
     return instance;
 }
index a05e129..5929376 100644 (file)
@@ -64,7 +64,7 @@ enum FakeVimSettingsCode
     ConfigIsKeyword,
 
     // other actions
-    SettingsDialog,
+    ConfigShowMarks,
 };
 
 class FakeVimSettings : public QObject
index a215514..2444135 100644 (file)
@@ -56,6 +56,7 @@
 //   m_tc.position() (== position()). The character below position() is not included
 //   if the last movement command was exclusive (MoveExclusive).
 //   The value of m_tc.anchor() is not used.
+//
 
 #include "fakevimhandler.h"
 #include "fakevimsyntax.h"
@@ -69,6 +70,7 @@
 #include <QtCore/QProcess>
 #include <QtCore/QRegExp>
 #include <QtCore/QTextStream>
+#include <QtCore/QTimer>
 #include <QtCore/QtAlgorithms>
 #include <QtCore/QStack>
 
@@ -126,51 +128,57 @@ namespace Internal {
 #define EDITOR(s) (m_textedit ? m_textedit->s : m_plaintextedit->s)
 
 const int ParagraphSeparator = 0x00002029;
+typedef QLatin1String _;
 
 using namespace Qt;
 
+/*! A \e Mode represents one of the basic modes of operation of FakeVim.
+*/
 
 enum Mode
 {
     InsertMode,
+    ReplaceMode,
     CommandMode,
     ExMode,
-    SearchForwardMode,
-    SearchBackwardMode,
 };
 
+/*! A \e SubMode is used for things that require one more data item
+    and are 'nested' behind a \l Mode.
+*/
 enum SubMode
 {
     NoSubMode,
-    ChangeSubMode,     // used for c
-    DeleteSubMode,     // used for d
-    FilterSubMode,     // used for !
-    IndentSubMode,     // used for =
-    RegisterSubMode,   // used for "
-    ReplaceSubMode,    // used for R and r
-    ShiftLeftSubMode,  // used for <
-    ShiftRightSubMode, // used for >
-    TransformSubMode,  // used for ~/gu/gU
-    WindowSubMode,     // used for Ctrl-w
-    YankSubMode,       // used for y
-    ZSubMode,          // used for z
-    CapitalZSubMode    // used for Z
+    ChangeSubMode,     // Used for c
+    DeleteSubMode,     // Used for d
+    FilterSubMode,     // Used for !
+    IndentSubMode,     // Used for =
+    RegisterSubMode,   // Used for "
+    ShiftLeftSubMode,  // Used for <
+    ShiftRightSubMode, // Used for >
+    TransformSubMode,  // Used for ~/gu/gU
+    WindowSubMode,     // Used for Ctrl-w
+    YankSubMode,       // Used for y
+    ZSubMode,          // Used for z
+    CapitalZSubMode    // Used for Z
 };
 
+/*! A \e SubSubMode is used for things that require one more data item
+    and are 'nested' behind a \l SubMode.
+*/
 enum SubSubMode
 {
-    // typically used for things that require one more data item
-    // and are 'nested' behind a mode
     NoSubSubMode,
-    FtSubSubMode,         // used for f, F, t, T
-    MarkSubSubMode,       // used for m
-    BackTickSubSubMode,   // used for `
-    TickSubSubMode,       // used for '
-    InvertCaseSubSubMode, // used for ~
-    DownCaseSubSubMode,   // used for gu
-    UpCaseSubSubMode,     // used for gU
-    ReplaceSubSubMode,    // used for r after visual mode
-    TextObjectSubSubMode, // used for thing like iw, aW, as etc.
+    FtSubSubMode,         // Used for f, F, t, T.
+    MarkSubSubMode,       // Used for m.
+    BackTickSubSubMode,   // Used for `.
+    TickSubSubMode,       // Used for '.
+    InvertCaseSubSubMode, // Used for ~.
+    DownCaseSubSubMode,   // Used for gu.
+    UpCaseSubSubMode,     // Used for gU.
+    ReplaceSubSubMode,    // Used for r after visual mode.
+    TextObjectSubSubMode, // Used for thing like iw, aW, as etc.
+    SearchSubSubMode,
 };
 
 enum VisualMode
@@ -188,14 +196,27 @@ enum MoveType
     MoveLineWise,
 };
 
-enum RangeMode
-{
-    RangeCharMode,  // v
-    RangeLineMode,  // V
-    RangeLineModeExclusive, // like above, but keep one newline when deleting
-    RangeBlockMode, // Ctrl-v
-    RangeBlockAndTailMode, // Ctrl-v for D and X
-};
+/*!
+    \enum RangeMode
+
+    The \e RangeMode serves as a means to define how the "Range" between
+    the \l cursor and the \l anchor position is to be interpreted.
+
+    \value RangeCharMode   Entered by pressing \key v. The range includes
+                           all characters between cursor and anchor.
+    \value RangeLineMode   Entered by pressing \key V. The range includes
+                           all lines between the line of the cursor and
+                           the line of the anchor.
+    \value RangeLineModeExclusice Like \l RangeLineMode, but keeps one
+                           newline when deleting.
+    \value RangeBlockMode  Entered by pressing \key Ctrl-v. The range includes
+                           all characters with line and column coordinates
+                           between line and columns coordinates of cursor and
+                           anchor.
+    \value RangeBlockAndTailMode Like \l RangeBlockMode, but also includes
+                           all characters in the affected lines up to the end
+                           of these lines.
+*/
 
 enum EventResult
 {
@@ -207,8 +228,8 @@ enum EventResult
 struct Column
 {
     Column(int p, int l) : physical(p), logical(l) {}
-    int physical; // number of characters in the data
-    int logical; // column on screen
+    int physical; // Number of characters in the data.
+    int logical; // Column on screen.
 };
 
 struct CursorPosition
@@ -223,33 +244,63 @@ struct CursorPosition
 struct Register
 {
     Register() : rangemode(RangeCharMode) {}
+    Register(const QString &c) : contents(c), rangemode(RangeCharMode) {}
     Register(const QString &c, RangeMode m) : contents(c), rangemode(m) {}
     QString contents;
     RangeMode rangemode;
 };
 
-struct Range
+QDebug operator<<(QDebug ts, const Register &reg)
 {
-    Range()
-        : beginPos(-1), endPos(-1), rangemode(RangeCharMode)
-    {}
+    return ts << reg.contents;
+}
 
-    Range(int b, int e, RangeMode m = RangeCharMode)
-        : beginPos(qMin(b, e)), endPos(qMax(b, e)), rangemode(m)
-    {}
+struct SearchData
+{
+    SearchData() { init(); }
 
-    QString toString() const
-    {
-        return QString("%1-%2 (mode: %3)").arg(beginPos).arg(endPos)
-            .arg(rangemode);
-    }
+    void init() { forward = true; mustMove = true; highlightMatches = true;
+        highlightCursor = true; }
 
-    int beginPos;
-    int endPos;
-    RangeMode rangemode;
+    QString needle;
+    bool forward;
+    bool mustMove;
+    bool highlightMatches;
+    bool highlightCursor;
 };
 
-QDebug &operator<<(QDebug &ts, const QList<QTextEdit::ExtraSelection> &sels)
+
+Range::Range()
+    : beginPos(-1), endPos(-1), rangemode(RangeCharMode)
+{}
+
+Range::Range(int b, int e, RangeMode m)
+    : beginPos(qMin(b, e)), endPos(qMax(b, e)), rangemode(m)
+{}
+
+QString Range::toString() const
+{
+    return QString("%1-%2 (mode: %3)").arg(beginPos).arg(endPos)
+        .arg(rangemode);
+}
+
+QDebug operator<<(QDebug ts, const Range &range)
+{
+    return ts << '[' << range.beginPos << ',' << range.endPos << ']';
+}
+
+
+
+ExCommand::ExCommand(const QString &c, const QString &a, const Range &r)
+    : cmd(c), hasBang(false), args(a), range(r)
+{}
+
+QDebug operator<<(QDebug ts, const ExCommand &cmd)
+{
+    return ts << cmd.cmd << ' ' << cmd.args << ' ' << cmd.range;
+}
+
+QDebug operator<<(QDebug ts, const QList<QTextEdit::ExtraSelection> &sels)
 {
     foreach (const QTextEdit::ExtraSelection &sel, sels)
         ts << "SEL: " << sel.cursor.anchor() << sel.cursor.position();
@@ -260,11 +311,14 @@ QString quoteUnprintable(const QString &ba)
 {
     QString res;
     for (int i = 0, n = ba.size(); i != n; ++i) {
-        QChar c = ba.at(i);
+        const QChar c = ba.at(i);
+        const int cc = c.unicode();
         if (c.isPrint())
             res += c;
+        else if (cc == '\n')
+            res += _("<CR>");
         else
-            res += QString("\\x%1").arg(c.unicode(), 2, 16);
+            res += QString("\\x%1").arg(c.unicode(), 2, 16, QLatin1Char('0'));
     }
     return res;
 }
@@ -280,9 +334,9 @@ static bool startsWithWhitespace(const QString &str, int col)
     return true;
 }
 
-inline QString msgE20MarkNotSet(const QString &text)
+inline QString msgMarkNotSet(const QString &text)
 {
-    return FakeVimHandler::tr("E20: Mark '%1' not set").arg(text);
+    return FakeVimHandler::tr("Mark '%1' not set").arg(text);
 }
 
 class Input
@@ -294,7 +348,7 @@ public:
     explicit Input(QChar x)
         : m_key(x.unicode()), m_xkey(x.unicode()), m_modifiers(0), m_text(x) {}
 
-    Input(int k, int m, QString t)
+    Input(int k, int m, const QString &t)
         : m_key(k), m_modifiers(m), m_text(t)
     {
         // m_xkey is only a cache.
@@ -305,11 +359,28 @@ public:
     {
         return m_xkey >= '0' && m_xkey <= '9';
     }
+
     bool isKey(int c) const
     {
         return !m_modifiers && m_key == c;
     }
 
+    bool isBackspace() const
+    {
+        return m_key == Key_Backspace || isControl('h');
+    }
+
+    bool isReturn() const
+    {
+        return m_key == Key_Return;
+    }
+
+    bool isEscape() const
+    {
+        return isKey(Key_Escape) || isKey(27) || isControl('c')
+            || isControl(Key_BracketLeft);
+    }
+
     bool is(int c) const
     {
         return m_xkey == c && (m_modifiers == 0 || m_modifiers == Qt::ShiftModifier);
@@ -328,13 +399,26 @@ public:
 
     bool operator==(const Input &a) const
     {
-        return a.m_key == m_key && m_text == a.m_text;
+        return a.m_key == m_key && a.m_modifiers == m_modifiers
+            && m_text == a.m_text;
     }
 
+    bool operator!=(const Input &a) const { return !operator==(a); }
+
     QString text() const { return m_text; }
 
+    QChar asChar() const
+    {
+        return (m_text.size() == 1 ? m_text.at(0) : QChar());
+    }
+
     int key() const { return m_key; }
 
+    QDebug dump(QDebug ts) const
+    {
+        return ts << m_key << '-' << m_modifiers << '-'
+            << quoteUnprintable(m_text);
+    }
 private:
     int m_key;
     int m_xkey;
@@ -342,10 +426,68 @@ private:
     QString m_text;
 };
 
-typedef QVector<Input> Inputs;
+QDebug operator<<(QDebug ts, const Input &input) { return input.dump(ts); }
+
+class Inputs : public QVector<Input>
+{
+public:
+    Inputs() {}
+    explicit Inputs(const QString &str) { parseFrom(str); }
+    void parseFrom(const QString &str);
+};
+
+
+void Inputs::parseFrom(const QString &str)
+{
+    const int n = str.size();
+    for (int i = 0; i < n; ++i) {
+        uint c0 = str.at(i).unicode(), c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0;
+        if (i + 1 < n)
+            c1 = str.at(i + 1).unicode();
+        if (i + 2 < n)
+            c2 = str.at(i + 2).unicode();
+        if (i + 3 < n)
+            c3 = str.at(i + 3).unicode();
+        if (i + 4 < n)
+            c4 = str.at(i + 4).unicode();
+        if (i + 5 < n)
+            c5 = str.at(i + 5).unicode();
+        if (c0 == '<') {
+            if ((c1 == 'C' || c1 == 'c') && c2 == '-' && c4 == '>') {
+                uint c = (c3 < 90 ? c3 : c3 - 32);
+                append(Input(c, Qt::ControlModifier, QString(QChar(c - 64))));
+                i += 4;
+            } else {
+                append(Input(QLatin1Char(c0)));
+            }
+        } else {
+            append(Input(QLatin1Char(c0)));
+        }
+    }
+}
+
+class History
+{
+public:
+    History() : m_index(0) {}
+    void append(const QString &item)
+        { //qDebug() << "APP: " << item << m_items;
+            m_items.removeAll(item);
+            m_items.append(item); m_index = m_items.size() - 1;  }
+    void down() { m_index = qMin(m_index + 1, m_items.size()); }
+    void up() { m_index = qMax(m_index - 1, 0); }
+    //void clear() { m_items.clear(); m_index = 0; }
+    void restart() { m_index = m_items.size(); }
+    QString current() const { return m_items.value(m_index, QString()); }
+    QStringList items() const { return m_items; }
+private:
+    QStringList m_items;
+    int m_index;
+};
+
 
 // Mappings for a specific mode.
-class ModeMapping : private QList<QPair<Inputs, Inputs> >
+class ModeMapping : public QList<QPair<Inputs, Inputs> >
 {
 public:
     ModeMapping() { test(); }
@@ -375,24 +517,24 @@ public:
             }
     }
 
-    // Returns 'false' if more input input is needed to decide whether a
-    // mapping needs to be applied. If a decision can be made, return 'true',
+    // Returns 'false' if more input is needed to decide whether a mapping
+    // needs to be applied. If a decision can be made, return 'true',
     // and replace *input with the mapped data.
-    bool mappingDone(Inputs *input) const
+    bool mappingDone(Inputs *inputs) const
     {
-        Q_UNUSED(input);
         // FIXME: inefficient.
         for (int i = 0; i != size(); ++i) {
+            const Inputs &haystack = at(i).first;
             // A mapping
-            if (startsWith(at(i).first, *input)) {
-                if (at(i).first.size() != input->size())
+            if (startsWith(haystack, *inputs)) {
+                if (haystack.size() != inputs->size())
                     return false; // This can be extended.
                 // Actual mapping.
-                *input = at(i).second;
+                *inputs = at(i).second;
                 return true;
             }
         }
-        // No extensible mapping found. Use input as-is.
+        // No extensible mapping found. Use inputs as-is.
         return true;
     }
 
@@ -403,13 +545,14 @@ private:
         if (needle.size() > haystack.size())
             return false;
         for (int i = 0; i != needle.size(); ++i) {
-            if (needle.at(i).text() != haystack.at(i).text())
+            if (needle.at(i) != haystack.at(i))
                 return false;
         }
         return true;
     }
 };
 
+
 class FakeVimHandler::Private : public QObject
 {
     Q_OBJECT
@@ -422,7 +565,7 @@ public:
     void handleCommand(const QString &cmd); // Sets m_tc + handleExCommand
     void handleExCommand(const QString &cmd);
 
-    // updates marks positions by the difference in positionChange
+    // Updates marks positions by the difference in positionChange.
     void fixMarks(int positionAction, int positionChange);
 
     void installEventFilter();
@@ -436,14 +579,16 @@ public:
     EventResult handleKey(const Input &);
     Q_SLOT EventResult handleKey2();
     EventResult handleInsertMode(const Input &);
+    EventResult handleReplaceMode(const Input &);
     EventResult handleCommandMode(const Input &);
     EventResult handleRegisterMode(const Input &);
-    EventResult handleMiniBufferModes(const Input &);
+    EventResult handleExMode(const Input &);
+    EventResult handleSearchSubSubMode(const Input &);
     EventResult handleCommandSubSubMode(const Input &);
     void finishMovement(const QString &dotCommand = QString());
     void finishMovement(const QString &dotCommand, int count);
     void resetCommandMode();
-    void search(const QString &needle, bool forward, bool incSearch = false);
+    void search(const SearchData &sd);
     void highlightMatches(const QString &needle);
     void stopIncrementalFind();
 
@@ -455,18 +600,18 @@ public:
     bool atEndOfLine() const
         { return m_tc.atBlockEnd() && m_tc.block().length() > 1; }
 
-    int lastPositionInDocument() const; // last valid pos in doc
+    int lastPositionInDocument() const; // Returns last valid position in doc.
     int firstPositionInLine(int line) const; // 1 based line, 0 based pos
     int lastPositionInLine(int line) const; // 1 based line, 0 based pos
     int lineForPosition(int pos) const;  // 1 based line, 0 based pos
     QString lineContents(int line) const; // 1 based line
-    void setLineContents(int line, const QString &contents) const; // 1 based line
+    void setLineContents(int line, const QString &contents); // 1 based line
 
     int linesOnScreen() const;
     int columnsOnScreen() const;
     int linesInDocument() const;
 
-    // all zero-based counting
+    // The following use all zero-based counting.
     int cursorLineOnScreen() const;
     int cursorLineInDocument() const;
     int physicalCursorColumnInDocument() const; // as stored in the data
@@ -482,7 +627,7 @@ public:
     void setCursorPosition(const CursorPosition &p)
         { setPosition(p.position); scrollToLineInDocument(p.scrollLine); }
 
-    // helper functions for indenting
+    // Helper functions for indenting/
     bool isElectricCharacter(QChar c) const;
     void indentSelectedText(QChar lastTyped = QChar());
     int indentText(const Range &range, QChar lastTyped = QChar());
@@ -500,7 +645,7 @@ public:
     void moveToMatchingParanthesis();
     void moveToWordBoundary(bool simple, bool forward, bool changeWord = false);
 
-    // to reduce line noise
+    // Convenience wrappers to reduce line noise.
     void moveToEndOfDocument() { m_tc.movePosition(EndOfDocument, MoveAnchor); }
     void moveToStartOfLine();
     void moveToEndOfLine();
@@ -515,11 +660,11 @@ public:
 
     bool handleFfTt(QString key);
 
-    // helper function for handleExCommand. return 1 based line index.
+    // Helper function for handleExCommand returning 1 based line index.
     int readLineCode(QString &cmd);
-    void selectRange(int beginLine, int endLine);
 
     void enterInsertMode();
+    void enterReplaceMode();
     void enterCommandMode();
     void enterExMode();
     void showRedMessage(const QString &msg);
@@ -527,20 +672,17 @@ public:
     void notImplementedYet();
     void updateMiniBuffer();
     void updateSelection();
+    void updateCursor();
     QWidget *editor() const;
     QChar characterAtCursor() const
         { return m_tc.document()->characterAt(m_tc.position()); }
     void beginEditBlock() { UNDO_DEBUG("BEGIN EDIT BLOCK"); m_tc.beginEditBlock(); }
     void beginEditBlock(int pos) { setUndoPosition(pos); beginEditBlock(); }
     void endEditBlock() { UNDO_DEBUG("END EDIT BLOCK"); m_tc.endEditBlock(); }
-    void joinPreviousEditBlock() { UNDO_DEBUG("JOIN EDIT BLOCK"); m_tc.joinPreviousEditBlock(); }
-
-    // this asks the layer above (e.g. the fake vim plugin or the
-    // stand-alone test application to handle the command)
-    void passUnknownExCommand(const QString &cmd);
-    // this asks the layer above (e.g. the fake vim plugin or the
-    // stand-alone test application to handle the set command)
-    void passUnknownSetCommand(const QString &cmd);
+    void joinPreviousEditBlock() { UNDO_DEBUG("JOIN"); m_tc.joinPreviousEditBlock(); }
+    void breakEditBlock()
+        { m_tc.beginEditBlock(); m_tc.insertText("x");
+          m_tc.deletePreviousChar(); m_tc.endEditBlock(); }
 
     bool isVisualMode() const { return m_visualMode != NoVisualMode; }
     bool isNoVisualMode() const { return m_visualMode == NoVisualMode; }
@@ -556,6 +698,8 @@ public:
     void selectBlockTextObject(bool inner, char left, char right);
     void selectQuotedStringTextObject(bool inner, int type);
 
+    Q_SLOT void importSelection();
+
 public:
     QTextEdit *m_textedit;
     QPlainTextEdit *m_plaintextedit;
@@ -570,7 +714,6 @@ public:
     QTextCursor m_tc;
     int m_oldPosition; // copy from last event to check for external changes
     int m_anchor;
-    static QHash<int, Register> m_registers;
     int m_register;
     QString m_mvcount;
     QString m_opcount;
@@ -582,10 +725,9 @@ public:
     bool m_anchorPastEnd;
     bool m_positionPastEnd; // '$' & 'l' in visual mode can move past eol
 
-    bool isSearchMode() const
-        { return m_mode == SearchForwardMode || m_mode == SearchBackwardMode; }
     int m_gflag;  // whether current command started with 'g'
 
+    QString m_commandPrefix;
     QString m_commandBuffer;
     QString m_currentFileName;
     QString m_currentMessage;
@@ -593,34 +735,44 @@ public:
     bool m_lastSearchForward;
     bool m_findPending;
     QString m_lastInsertion;
+    QString m_lastDeletion;
 
     int anchor() const { return m_anchor; }
     int position() const { return m_tc.position(); }
 
-    typedef void (FakeVimHandler::Private::*Transformation)(int, QTextCursor *);
-    void transformText(const Range &range, Transformation transformation);
-
-    void removeSelectedText();
+    struct TransformationData
+    {
+        TransformationData(const QString &s, const QVariant &d)
+            : from(s), extraData(d) {}
+        QString from;
+        QString to;
+        QVariant extraData;
+    };
+    typedef void (Private::*Transformation)(TransformationData *td);
+    void transformText(const Range &range, Transformation transformation,
+        const QVariant &extraData = QVariant());
+
+    void insertText(const Register &reg);
     void removeText(const Range &range);
-    void removeTransform(int, QTextCursor *);
+    void removeTransform(TransformationData *td);
 
-    void invertCaseSelectedText();
-    void invertCaseTransform(int, QTextCursor *);
+    void invertCase(const Range &range);
+    void invertCaseTransform(TransformationData *td);
 
-    void upCaseSelectedText();
-    void upCaseTransform(int, QTextCursor *);
+    void upCase(const Range &range);
+    void upCaseTransform(TransformationData *td);
 
-    void downCaseSelectedText();
-    void downCaseTransform(int, QTextCursor *);
+    void downCase(const Range &range);
+    void downCaseTransform(TransformationData *td);
 
-    QChar m_replacingCharacter;
-    void replaceSelectedText(); // replace each character with m_replacingCharacter
-    void replaceTransform(int, QTextCursor *);
+    QString m_replacement;
+    void replaceText(const Range &range, const QString &str);
+    void replaceTransform(TransformationData *td);
 
-    QString selectedText() const { return text(Range(position(), anchor())); }
-    QString text(const Range &range) const;
+    QString selectText(const Range &range) const;
+    void setCurrentRange(const Range &range);
+    Range currentRange() const { return Range(position(), anchor(), m_rangemode); }
 
-    void yankSelectedText();
     void yankText(const Range &range, int toregister = '"');
 
     void pasteText(bool afterCursor);
@@ -630,37 +782,26 @@ public:
     void redo();
     void setUndoPosition(int pos);
     QMap<int, int> m_undoCursorPosition; // revision -> position
-    bool m_beginEditBlock;
 
     // extra data for '.'
     void replay(const QString &text, int count);
-    void setDotCommand(const QString &cmd) { m_dotCommand = cmd; }
-    void setDotCommand(const QString &cmd, int n) { m_dotCommand = cmd.arg(n); }
-    QString m_dotCommand;
-    bool m_inReplay; // true if we are executing a '.'
+    void setDotCommand(const QString &cmd) { g.dotCommand = cmd; }
+    void setDotCommand(const QString &cmd, int n) { g.dotCommand = cmd.arg(n); }
 
     // extra data for ';'
     QString m_semicolonCount;
     Input m_semicolonType;  // 'f', 'F', 't', 'T'
     QString m_semicolonKey;
 
-    // history for '/'
-    QString lastSearchString() const;
-    static QStringList m_searchHistory;
-    int m_searchHistoryIndex;
-
-    // history for ':'
-    static QStringList m_commandHistory;
-    int m_commandHistoryIndex;
-
     // visual line mode
     void enterVisualMode(VisualMode visualMode);
     void leaveVisualMode();
     VisualMode m_visualMode;
 
     // marks as lines
+    int mark(int code) const;
+    void setMark(int code, int position);
     QHash<int, int> m_marks;
-    QString m_oldNeedle;
 
     // vi style configuration
     QVariant config(int code) const { return theFakeVimSetting(code)->value(); }
@@ -670,7 +811,6 @@ public:
 
     int m_targetColumn; // -1 if past end of line
     int m_visualTargetColumn; // 'l' can move past eol in visual mode only
-
     int m_cursorWidth;
 
     // auto-indent
@@ -683,46 +823,67 @@ public:
     void handleStartOfLine();
 
     void recordJump();
-    void recordNewUndo();
     QVector<CursorPosition> m_jumpListUndo;
     QVector<CursorPosition> m_jumpListRedo;
 
     QList<QTextEdit::ExtraSelection> m_searchSelections;
+    QTextCursor m_searchCursor;
+    QString m_oldNeedle;
 
-    bool handleExCommandHelper(const QString &cmd); // Returns success.
-    QString extractCommand(const QString &line, int *beginLine, int *endLine);
-    bool handleExBangCommand(const QString &line);
-    bool handleExDeleteCommand(const QString &line);
-    bool handleExGotoCommand(const QString &line);
-    bool handleExHistoryCommand(const QString &line);
-    bool handleExMapCommand(const QString &line);
-    bool handleExNormalCommand(const QString &line);
-    bool handleExReadCommand(const QString &line);
-    bool handleExRedoCommand(const QString &line);
-    bool handleExSetCommand(const QString &line);
-    bool handleExShiftRightCommand(const QString &line);
-    bool handleExSourceCommand(const QString &line);
-    bool handleExSubstituteCommand(const QString &line);
-    bool handleExWriteCommand(const QString &line);
-
-    // All mappings.
-    typedef QHash<char, ModeMapping> Mappings;
-    static Mappings m_mappings;
-
-    QVector<Input> m_pendingInput;
+    bool handleExCommandHelper(const ExCommand &cmd); // Returns success.
+    bool handleExPluginCommand(const ExCommand &cmd); // Handled by plugin?
+    bool handleExBangCommand(const ExCommand &cmd);
+    bool handleExDeleteCommand(const ExCommand &cmd);
+    bool handleExGotoCommand(const ExCommand &cmd);
+    bool handleExHistoryCommand(const ExCommand &cmd);
+    bool handleExRegisterCommand(const ExCommand &cmd);
+    bool handleExMapCommand(const ExCommand &cmd);
+    bool handleExNormalCommand(const ExCommand &cmd);
+    bool handleExReadCommand(const ExCommand &cmd);
+    bool handleExRedoCommand(const ExCommand &cmd);
+    bool handleExSetCommand(const ExCommand &cmd);
+    bool handleExShiftCommand(const ExCommand &cmd);
+    bool handleExSourceCommand(const ExCommand &cmd);
+    bool handleExSubstituteCommand(const ExCommand &cmd);
+    bool handleExWriteCommand(const ExCommand &cmd);
 
     void timerEvent(QTimerEvent *ev);
-    int m_inputTimer;
 
     void setupCharClass();
     int charClass(QChar c, bool simple) const;
     signed char m_charClass[256];
+
+    static struct GlobalData
+    {
+        GlobalData()
+        {
+            inReplay = false;
+            inputTimer = -1;
+        }
+
+        // Input.
+        Inputs pendingInput;
+        int inputTimer;
+
+        // Repetition.
+        QString dotCommand;
+        bool inReplay; // true if we are executing a '.'
+
+        // History for searches.
+        History searchHistory;
+
+        // History for :ex commands.
+        History commandHistory;
+
+        QHash<int, Register> registers;
+
+        // All mappings.
+        typedef QHash<char, ModeMapping> Mappings;
+        Mappings mappings;
+    } g;
 };
 
-QStringList FakeVimHandler::Private::m_searchHistory;
-QStringList FakeVimHandler::Private::m_commandHistory;
-QHash<int, Register> FakeVimHandler::Private::m_registers;
-FakeVimHandler::Private::Mappings FakeVimHandler::Private::m_mappings;
+FakeVimHandler::Private::GlobalData FakeVimHandler::Private::g;
 
 FakeVimHandler::Private::Private(FakeVimHandler *parent, QWidget *widget)
 {
@@ -752,11 +913,8 @@ void FakeVimHandler::Private::init()
     m_movetype = MoveInclusive;
     m_anchor = 0;
     m_cursorWidth = EDITOR(cursorWidth());
-    m_inReplay = false;
     m_justAutoIndented = 0;
     m_rangemode = RangeCharMode;
-    m_beginEditBlock = true;
-    m_inputTimer = -1;
 
     setupCharClass();
 }
@@ -768,6 +926,8 @@ bool FakeVimHandler::Private::wantsOverride(QKeyEvent *ev)
     KEY_DEBUG("SHORTCUT OVERRIDE" << key << "  PASSING: " << m_passing);
 
     if (key == Key_Escape) {
+        if (m_subsubmode == SearchSubSubMode)
+            return true;
         // Not sure this feels good. People often hit Esc several times
         if (isNoVisualMode() && m_mode == CommandMode)
             return false;
@@ -830,7 +990,7 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev)
             // Try to compensate for code completion
             if (dist > 0 && dist <= physicalCursorColumnInDocument()) {
                 Range range(m_oldPosition, m_tc.position());
-                m_lastInsertion.append(text(range));
+                m_lastInsertion.append(selectText(range));
             }
         } else if (!isVisualMode()) {
             if (atEndOfLine())
@@ -851,8 +1011,8 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev)
     //    key = shift(key);
     //}
 
-    QTC_ASSERT(
-        !(m_mode != InsertMode && m_tc.atBlockEnd() && m_tc.block().length() > 1),
+    QTC_ASSERT(m_mode == InsertMode || m_mode == ReplaceMode
+            || !m_tc.atBlockEnd() || m_tc.block().length() <= 1,
         qDebug() << "Cursor at EOL before key handler");
 
     EventResult result = handleKey(Input(key, mods, ev->text()));
@@ -862,8 +1022,8 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev)
         // We fake vi-style end-of-line behaviour
         m_fakeEnd = atEndOfLine() && m_mode == CommandMode && !isVisualBlockMode();
 
-        QTC_ASSERT(
-            !(m_mode != InsertMode && m_tc.atBlockEnd() && m_tc.block().length() > 1),
+        QTC_ASSERT(m_mode == InsertMode || m_mode == ReplaceMode
+                || !m_tc.atBlockEnd() || m_tc.block().length() <= 1,
             qDebug() << "Cursor at EOL after key handler");
 
         if (m_fakeEnd)
@@ -872,43 +1032,65 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev)
         EDITOR(setTextCursor(m_tc));
         m_oldPosition = m_tc.position();
     }
+
+    if (hasConfig(ConfigShowMarks))
+        updateSelection();
+
     return result;
 }
 
 void FakeVimHandler::Private::installEventFilter()
 {
+    EDITOR(viewport()->installEventFilter(q));
     EDITOR(installEventFilter(q));
 }
 
 void FakeVimHandler::Private::setupWidget()
 {
     enterCommandMode();
-    //EDITOR(setCursorWidth(QFontMetrics(ed->font()).width(QChar('x')));
     if (m_textedit) {
         m_textedit->setLineWrapMode(QTextEdit::NoWrap);
     } else if (m_plaintextedit) {
         m_plaintextedit->setLineWrapMode(QPlainTextEdit::NoWrap);
     }
     m_wasReadOnly = EDITOR(isReadOnly());
-    //EDITOR(setReadOnly(true));
 
     updateEditor();
+    importSelection();
+    updateMiniBuffer();
+    updateCursor();
+}
 
+void FakeVimHandler::Private::importSelection()
+{
     QTextCursor tc = EDITOR(textCursor());
+    int pos = tc.position();
+    int anc = tc.anchor();
     if (tc.hasSelection()) {
-        int pos = tc.position();
-        int anc = tc.anchor();
-        m_marks['<'] = anc;
-        m_marks['>'] = pos;
-        m_anchor = anc;
-        m_visualMode = VisualCharMode;
-        tc.clearSelection();
-        EDITOR(setTextCursor(tc));
-        m_tc = tc; // needed in updateSelection
-        updateSelection();
+        // FIXME: Why?
+        if (pos < anc)
+            --anc;
+        else
+            tc.movePosition(Left, KeepAnchor);
     }
-
-    updateMiniBuffer();
+    setMark('<', anc);
+    setMark('>', pos);
+    m_anchor = anc;
+    Qt::KeyboardModifiers mods = QApplication::keyboardModifiers();
+    if (!tc.hasSelection())
+        m_visualMode = NoVisualMode;
+    else if (mods & Qt::ControlModifier)
+        m_visualMode = VisualBlockMode;
+    else if (mods & Qt::AltModifier)
+        m_visualMode = VisualBlockMode;
+    else if (mods & Qt::ShiftModifier)
+        m_visualMode = VisualLineMode;
+    else
+        m_visualMode = VisualCharMode;
+    m_tc = tc; // needed in updateSelection
+    tc.clearSelection();
+    EDITOR(setTextCursor(tc));
+    updateSelection();
 }
 
 void FakeVimHandler::Private::updateEditor()
@@ -924,45 +1106,50 @@ void FakeVimHandler::Private::restoreWidget(int tabSize)
     //showBlackMessage(QString());
     //updateMiniBuffer();
     //EDITOR(removeEventFilter(q));
-    EDITOR(setReadOnly(m_wasReadOnly));
-    EDITOR(setCursorWidth(m_cursorWidth));
-    EDITOR(setOverwriteMode(false));
+    //EDITOR(setReadOnly(m_wasReadOnly));
     const int charWidth = QFontMetrics(EDITOR(font())).width(QChar(' '));
     EDITOR(setTabStopWidth(charWidth * tabSize));
 
     if (isVisualLineMode()) {
         m_tc = EDITOR(textCursor());
-        int beginLine = lineForPosition(m_marks['<']);
-        int endLine = lineForPosition(m_marks['>']);
+        int beginLine = lineForPosition(mark('<'));
+        int endLine = lineForPosition(mark('>'));
         m_tc.setPosition(firstPositionInLine(beginLine), MoveAnchor);
         m_tc.setPosition(lastPositionInLine(endLine), KeepAnchor);
         EDITOR(setTextCursor(m_tc));
-    } else if (isVisualCharMode()) {
+    } else if (isVisualCharMode() || isVisualBlockMode()) {
         m_tc = EDITOR(textCursor());
-        m_tc.setPosition(m_marks['<'], MoveAnchor);
-        m_tc.setPosition(m_marks['>'], KeepAnchor);
+        m_tc.setPosition(mark('<'), MoveAnchor);
+        m_tc.setPosition(mark('>'), KeepAnchor);
         EDITOR(setTextCursor(m_tc));
     }
 
     m_visualMode = NoVisualMode;
+    // Force "ordinary" cursor.
+    m_mode = InsertMode;
+    m_submode = NoSubMode;
+    m_subsubmode = NoSubSubMode;
+    updateCursor();
     updateSelection();
 }
 
 EventResult FakeVimHandler::Private::handleKey(const Input &input)
 {
-    if (m_mode == InsertMode || m_mode == CommandMode) {
-        m_pendingInput.append(input);
+    KEY_DEBUG("HANDLE INPUT: " << input);
+    if (m_mode == ExMode)
+        return handleExMode(input);
+    if (m_subsubmode == SearchSubSubMode)
+        return handleSearchSubSubMode(input);
+    if (m_mode == InsertMode || m_mode == ReplaceMode || m_mode == CommandMode) {
+        g.pendingInput.append(input);
         const char code = m_mode == InsertMode ? 'i' : 'n';
-        if (m_mappings[code].mappingDone(&m_pendingInput))
+        if (g.mappings[code].mappingDone(&g.pendingInput))
             return handleKey2();
-        if (m_inputTimer != -1)
-            killTimer(m_inputTimer);
-        m_inputTimer = startTimer(1000);
+        if (g.inputTimer != -1)
+            killTimer(g.inputTimer);
+        g.inputTimer = startTimer(1000);
         return EventHandled;
     }
-    if (m_mode == ExMode || m_mode == SearchForwardMode
-            || m_mode == SearchBackwardMode)
-        return handleMiniBufferModes(input);
     return EventUnhandled;
 }
 
@@ -971,22 +1158,32 @@ EventResult FakeVimHandler::Private::handleKey2()
     setUndoPosition(m_tc.position());
     if (m_mode == InsertMode) {
         EventResult result = EventUnhandled;
-        foreach (const Input &in, m_pendingInput) {
+        foreach (const Input &in, g.pendingInput) {
             EventResult r = handleInsertMode(in);
             if (r == EventHandled)
                 result = EventHandled;
         }
-        m_pendingInput.clear();
+        g.pendingInput.clear();
+        return result;
+    }
+    if (m_mode == ReplaceMode) {
+        EventResult result = EventUnhandled;
+        foreach (const Input &in, g.pendingInput) {
+            EventResult r = handleReplaceMode(in);
+            if (r == EventHandled)
+                result = EventHandled;
+        }
+        g.pendingInput.clear();
         return result;
     }
     if (m_mode == CommandMode) {
         EventResult result = EventUnhandled;
-        foreach (const Input &in, m_pendingInput) {
+        foreach (const Input &in, g.pendingInput) {
             EventResult r = handleCommandMode(in);
             if (r == EventHandled)
                 result = EventHandled;
         }
-        m_pendingInput.clear();
+        g.pendingInput.clear();
         return result;
     }
     return EventUnhandled;
@@ -1020,7 +1217,7 @@ void FakeVimHandler::Private::setAnchor()
     if (!isVisualMode()) {
         m_anchor = m_tc.position();
     } else {
-    //    m_marks['<'] = m_tc.position();
+    //    setMark('<', m_tc.position());
     }
 }
 
@@ -1085,14 +1282,14 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
         enterExMode();
         m_currentMessage.clear();
         m_commandBuffer = QString(".,+%1!").arg(qAbs(endLine - beginLine));
-        m_commandHistory.append(QString());
-        m_commandHistoryIndex = m_commandHistory.size() - 1;
+        //g.commandHistory.append(QString());
         updateMiniBuffer();
+        updateCursor();
         return;
     }
 
     if (isVisualMode())
-        m_marks['>'] = m_tc.position();
+        setMark('>', m_tc.position());
 
     if (m_submode == ChangeSubMode
         || m_submode == DeleteSubMode
@@ -1107,7 +1304,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
 
         if (m_movetype == MoveInclusive) {
             if (anchor() <= position()) {
-                if ( !m_tc.atBlockEnd())
+                if (!m_tc.atBlockEnd())
                     moveRight(); // correction
             } else {
                 m_anchor++;
@@ -1124,9 +1321,9 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
         }
 
         if (m_submode != TransformSubMode) {
-            yankSelectedText();
+            yankText(currentRange(), m_register);
             if (m_movetype == MoveLineWise)
-                m_registers[m_register].rangemode = RangeLineMode;
+                g.registers[m_register].rangemode = RangeLineMode;
         }
 
         m_positionPastEnd = m_anchorPastEnd = false;
@@ -1135,17 +1332,17 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
     if (m_submode == ChangeSubMode) {
         if (m_rangemode == RangeLineMode)
             m_rangemode = RangeLineModeExclusive;
-        removeSelectedText();
+        removeText(currentRange());
         if (!dotCommand.isEmpty())
             setDotCommand(QLatin1Char('c') + dotCommand);
         if (m_movetype == MoveLineWise)
             insertAutomaticIndentation(true);
         endEditBlock();
+        setUndoPosition(position());
         enterInsertMode();
-        m_beginEditBlock = false;
         m_submode = NoSubMode;
     } else if (m_submode == DeleteSubMode) {
-        removeSelectedText();
+        removeText(currentRange());
         if (!dotCommand.isEmpty())
             setDotCommand(QLatin1Char('d') + dotCommand);
         if (m_movetype == MoveLineWise)
@@ -1161,7 +1358,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
         const int la = lineForPosition(anchor());
         const int lp = lineForPosition(position());
         if (m_register != '"') {
-            setPosition(m_marks[m_register]);
+            setPosition(mark(m_register));
             moveToStartOfLine();
         } else {
             if (anchor() <= position())
@@ -1171,19 +1368,19 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
             showBlackMessage(QString("%1 lines yanked").arg(qAbs(la - lp) + 1));
     } else if (m_submode == TransformSubMode) {
         if (m_subsubmode == InvertCaseSubSubMode) {
-            invertCaseSelectedText();
+            invertCase(currentRange());
             if (!dotCommand.isEmpty())
                 setDotCommand(QLatin1Char('~') + dotCommand);
         } else if (m_subsubmode == UpCaseSubSubMode) {
-            upCaseSelectedText();
+            upCase(currentRange());
             if (!dotCommand.isEmpty())
                 setDotCommand("gU" + dotCommand);
         } else if (m_subsubmode == DownCaseSubSubMode) {
-            downCaseSelectedText();
+            downCase(currentRange());
             if (!dotCommand.isEmpty())
                 setDotCommand("gu" + dotCommand);
         } else if (m_subsubmode == ReplaceSubSubMode) {
-            replaceSelectedText();
+            replaceText(currentRange(), m_replacement);
             if (!dotCommand.isEmpty())
                 setDotCommand("r" + dotCommand);
         }
@@ -1193,28 +1390,26 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
         if (m_movetype == MoveLineWise)
             handleStartOfLine();
         endEditBlock();
-    } else if (m_submode == ReplaceSubMode) {
-        m_submode = NoSubMode;
     } else if (m_submode == IndentSubMode) {
         recordJump();
         beginEditBlock();
         indentSelectedText();
         endEditBlock();
         m_submode = NoSubMode;
-        updateMiniBuffer();
     } else if (m_submode == ShiftRightSubMode) {
         recordJump();
         shiftRegionRight(1);
         m_submode = NoSubMode;
-        updateMiniBuffer();
     } else if (m_submode == ShiftLeftSubMode) {
         recordJump();
         shiftRegionLeft(1);
         m_submode = NoSubMode;
-        updateMiniBuffer();
     }
 
     resetCommandMode();
+    updateSelection();
+    updateMiniBuffer();
+    updateCursor();
 }
 
 void FakeVimHandler::Private::resetCommandMode()
@@ -1226,14 +1421,19 @@ void FakeVimHandler::Private::resetCommandMode()
     m_register = '"';
     m_tc.clearSelection();
     m_rangemode = RangeCharMode;
-
-    updateSelection();
-    updateMiniBuffer();
 }
 
 void FakeVimHandler::Private::updateSelection()
 {
     QList<QTextEdit::ExtraSelection> selections = m_searchSelections;
+    if (!m_searchCursor.isNull()) {
+        QTextEdit::ExtraSelection sel;
+        sel.cursor = m_searchCursor;
+        sel.format = m_searchCursor.blockCharFormat();
+        sel.format.setForeground(Qt::white);
+        sel.format.setBackground(Qt::black);
+        selections.append(sel);
+    }
     if (isVisualMode()) {
         QTextEdit::ExtraSelection sel;
         sel.cursor = m_tc;
@@ -1246,7 +1446,7 @@ void FakeVimHandler::Private::updateSelection()
         sel.format.setBackground(Qt::black);
 #endif
         const int cursorPos = m_tc.position();
-        const int anchorPos = m_marks['<'];
+        const int anchorPos = mark('<');
         //qDebug() << "POS: " << cursorPos << " ANCHOR: " << anchorPos;
         if (isVisualCharMode()) {
             sel.cursor.setPosition(qMin(cursorPos, anchorPos), MoveAnchor);
@@ -1287,6 +1487,19 @@ void FakeVimHandler::Private::updateSelection()
         }
     }
     //qDebug() << "SELECTION: " << selections;
+    if (hasConfig(ConfigShowMarks)) {
+        for (QHashIterator<int, int> it(m_marks); it.hasNext(); ) {
+            it.next();
+            QTextEdit::ExtraSelection sel;
+            sel.cursor = m_tc;
+            sel.cursor.setPosition(it.value(), MoveAnchor);
+            sel.cursor.setPosition(it.value() + 1, KeepAnchor);
+            sel.format = m_tc.blockCharFormat();
+            sel.format.setForeground(Qt::blue);
+            sel.format.setBackground(Qt::green);
+            selections.append(sel);
+        }
+    }
     emit q->selectionChanged(selections);
 }
 
@@ -1309,17 +1522,13 @@ void FakeVimHandler::Private::updateMiniBuffer()
             msg = "-- VISUAL BLOCK --";
         }
     } else if (m_mode == InsertMode) {
-        if (m_submode == ReplaceSubMode)
-            msg = "-- REPLACE --";
-        else
-            msg = "-- INSERT --";
-    } else {
-        if (m_mode == SearchForwardMode)
-            msg += '/';
-        else if (m_mode == SearchBackwardMode)
-            msg += '?';
-        else if (m_mode == ExMode)
-            msg += ':';
+        msg = "-- INSERT --";
+    } else if (m_mode == ReplaceMode) {
+        msg = "-- REPLACE --";
+    } else if (!m_commandPrefix.isEmpty()) {
+        //QTC_ASSERT(m_mode == ExMode || m_subsubmode == SearchSubSubMode,
+        //    qDebug() << "MODE: " << m_mode << m_subsubmode);
+        msg = m_commandPrefix;
         foreach (QChar c, m_commandBuffer) {
             if (c.unicode() < 32) {
                 msg += '^';
@@ -1330,6 +1539,9 @@ void FakeVimHandler::Private::updateMiniBuffer()
         }
         if (!msg.isEmpty() && m_mode != CommandMode)
             msg += QChar(10073); // '|'; // FIXME: Use a real "cursor"
+    } else {
+        QTC_ASSERT(m_mode == CommandMode && m_subsubmode != SearchSubSubMode, /**/);
+        msg = "-- COMMAND --";
     }
 
     emit q->commandBufferChanged(msg);
@@ -1337,7 +1549,8 @@ void FakeVimHandler::Private::updateMiniBuffer()
     int linesInDoc = linesInDocument();
     int l = cursorLineInDocument();
     QString status;
-    const QString pos = QString::fromLatin1("%1,%2").arg(l + 1).arg(physicalCursorColumnInDocument() + 1);
+    const QString pos = QString::fromLatin1("%1,%2")
+        .arg(l + 1).arg(physicalCursorColumnInDocument() + 1);
     // FIXME: physical "-" logical
     if (linesInDoc != 0) {
         status = FakeVimHandler::tr("%1%2%").arg(pos, -10).arg(l * 100 / linesInDoc, 4);
@@ -1427,23 +1640,34 @@ EventResult FakeVimHandler::Private::handleCommandSubSubMode(const Input &input)
             m_rangemode = RangeLineMode;
         else if (isVisualBlockMode())
             m_rangemode = RangeBlockMode;
-        if (!input.text().isEmpty() && input.text().at(0).isPrint()) {
+        // FIXME: Consolidate.
+        if (isVisualMode()) {
             leaveVisualMode();
-            m_replacingCharacter = input.text().at(0);
+            m_replacement = input.text();
+            finishMovement();
+        } else {
+            Range range(position(), position() + count(), RangeCharMode);
+            m_replacement = input.text();
+            Transformation tr = &FakeVimHandler::Private::replaceTransform;
+            transformText(range, tr);
+            m_subsubmode = NoSubSubMode;
+            m_submode = NoSubMode;
+            setDotCommand("%1r" + input.text(), count());
             finishMovement();
         }
     } else if (m_subsubmode == MarkSubSubMode) {
-        m_marks[input.key()] = m_tc.position();
+        setMark(input.asChar().unicode(), m_tc.position());
         m_subsubmode = NoSubSubMode;
     } else if (m_subsubmode == BackTickSubSubMode
             || m_subsubmode == TickSubSubMode) {
-        if (m_marks.contains(input.key())) {
-            setPosition(m_marks[input.key()]);
+        int m = mark(input.asChar().unicode());
+        if (m != -1) {
+            setPosition(m);
             if (m_subsubmode == TickSubSubMode)
                 moveToFirstNonBlankOnLine();
             finishMovement();
         } else {
-            showRedMessage(msgE20MarkNotSet(input.text()));
+            showRedMessage(msgMarkNotSet(input.text()));
         }
         m_subsubmode = NoSubSubMode;
     } else {
@@ -1456,7 +1680,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
 {
     EventResult handled = EventHandled;
 
-    if (input.isKey(Key_Escape) || input.isControl(Key_BracketLeft)) {
+    if (input.isEscape()) {
         if (isVisualMode()) {
             leaveVisualMode();
         } else if (m_submode != NoSubMode) {
@@ -1465,6 +1689,8 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
             finishMovement();
         } else {
             resetCommandMode();
+            updateSelection();
+            updateMiniBuffer();
         }
     } else if (m_subsubmode != NoSubSubMode) {
         handleCommandSubSubMode(input);
@@ -1472,7 +1698,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         emit q->windowCommandRequested(input.key());
         m_submode = NoSubMode;
     } else if (m_submode == RegisterSubMode) {
-        m_register = input.key();
+        m_register = input.asChar().unicode();
         m_submode = NoSubMode;
         m_rangemode = RangeLineMode;
     } else if (m_submode == ChangeSubMode && input.is('c')) { // tested
@@ -1519,12 +1745,12 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         finishMovement();
     } else if (m_submode == ZSubMode) {
         //qDebug() << "Z_MODE " << cursorLineInDocument() << linesOnScreen();
-        if (input.isKey(Key_Return) || input.is('t')) {
+        if (input.isReturn() || input.is('t')) {
             // Cursor line to top of window.
             if (!m_mvcount.isEmpty())
                 setPosition(firstPositionInLine(count()));
             scrollUp(- cursorLineOnScreen());
-            if (input.isKey(Key_Return))
+            if (input.isReturn())
                 moveToFirstNonBlankOnLine();
             finishMovement();
         } else if (input.is('.') || input.is('z')) {
@@ -1554,23 +1780,6 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
             handleExCommand(QString(QLatin1Char('x')));
         else if (input.is('Q'))
             handleExCommand("q!");
-    } else if (m_submode == ReplaceSubMode) {
-        const QString text = input.text();
-        if (count() <= (rightDist() + atEndOfLine()) && text.size() == 1
-                && (text.at(0).isPrint() || text.at(0).isSpace())) {
-            if (atEndOfLine())
-                moveLeft();
-            setAnchor();
-            moveRight(count());
-            removeSelectedText();
-            m_tc.insertText(QString(count(), text.at(0)));
-            m_movetype = MoveExclusive;
-            setDotCommand("%1r" + text, count());
-            moveLeft();
-        }
-        setTargetColumn();
-        m_submode = NoSubMode;
-        finishMovement();
     } else if (input.isDigit()) {
         if (input.is('0') && m_mvcount.isEmpty()) {
             m_movetype = MoveExclusive;
@@ -1601,18 +1810,18 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         finishMovement();
     } else if (input.is(':')) {
         enterExMode();
+        g.commandHistory.restart();
         m_currentMessage.clear();
         m_commandBuffer.clear();
         if (isVisualMode())
             m_commandBuffer = "'<,'>";
-        m_commandHistory.append(QString());
-        m_commandHistoryIndex = m_commandHistory.size() - 1;
         updateMiniBuffer();
     } else if (input.is('/') || input.is('?')) {
+        m_lastSearchForward = input.is('/');
+        g.searchHistory.restart();
         if (hasConfig(ConfigUseCoreSearch)) {
             // re-use the core dialog.
             m_findPending = true;
-            m_lastSearchForward = (input.is('/'));
             EDITOR(setTextCursor(m_tc));
             emit q->findRequested(!m_lastSearchForward);
             m_tc = EDITOR(textCursor());
@@ -1620,25 +1829,35 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         } else {
             // FIXME: make core find dialog sufficiently flexible to
             // produce the "default vi" behaviour too. For now, roll our own.
-            enterExMode(); // to get the cursor disabled
             m_currentMessage.clear();
-            m_mode = (input.is('/')) ? SearchForwardMode : SearchBackwardMode;
-            m_commandBuffer.clear();
-            m_searchHistory.append(QString());
-            m_searchHistoryIndex = m_searchHistory.size() - 1;
+            m_movetype = MoveExclusive;
+            m_subsubmode = SearchSubSubMode;
+            m_commandPrefix = QLatin1Char(m_lastSearchForward ? '/' : '?');
+            m_commandBuffer = QString();
+            updateCursor();
             updateMiniBuffer();
         }
     } else if (input.is('`')) {
         m_subsubmode = BackTickSubSubMode;
     } else if (input.is('#') || input.is('*')) {
         // FIXME: That's not proper vim behaviour
-        m_tc.select(QTextCursor::WordUnderCursor);
-        QString needle = "\\<" + m_tc.selection().toPlainText() + "\\>";
-        m_searchHistory.append(needle);
-        m_lastSearchForward = (input.is('*'));
-        updateMiniBuffer();
-        search(needle, m_lastSearchForward);
-        recordJump();
+        QTextCursor tc = m_tc;
+        tc.select(QTextCursor::WordUnderCursor);
+        QString needle = "\\<" + tc.selection().toPlainText() + "\\>";
+        g.searchHistory.append(needle);
+        m_lastSearchForward = input.is('*');
+        m_currentMessage.clear();
+        m_commandPrefix = QLatin1Char(m_lastSearchForward ? '/' : '?');
+        m_commandBuffer = needle;
+        SearchData sd;
+        sd.needle = needle;
+        sd.forward = m_lastSearchForward;
+        sd.highlightCursor = false;
+        sd.highlightMatches = true;
+        search(sd);
+        //m_searchCursor = QTextCursor();
+        //updateSelection();
+        //updateMiniBuffer();
     } else if (input.is('\'')) {
         m_subsubmode = TickSubSubMode;
     } else if (input.is('|')) {
@@ -1652,12 +1871,11 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         enterExMode();
         m_currentMessage.clear();
         m_commandBuffer = "'<,'>!";
-        m_commandHistory.append(QString());
-        m_commandHistoryIndex = m_commandHistory.size() - 1;
+        //g.commandHistory.append(QString());
         updateMiniBuffer();
     } else if (input.is('"')) {
         m_submode = RegisterSubMode;
-    } else if (input.isKey(Key_Return)) {
+    } else if (input.isReturn()) {
         moveToStartOfLine();
         moveDown();
         moveToFirstNonBlankOnLine();
@@ -1693,12 +1911,13 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
     } else if (input.is(',')) {
         passShortcuts(true);
     } else if (input.is('.')) {
-        //qDebug() << "REPEATING" << quoteUnprintable(m_dotCommand) << count();
-        QString savedCommand = m_dotCommand;
-        m_dotCommand.clear();
+        //qDebug() << "REPEATING" << quoteUnprintable(g.dotCommand) << count()
+        //    << input;
+        QString savedCommand = g.dotCommand;
+        g.dotCommand.clear();
         replay(savedCommand, count());
         enterCommandMode();
-        m_dotCommand = savedCommand;
+        g.dotCommand = savedCommand;
     } else if (input.is('<') && isNoVisualMode()) {
         m_submode = ShiftLeftSubMode;
     } else if (input.is('<') && isVisualMode()) {
@@ -1722,12 +1941,16 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         finishMovement();
     } else if ((!isVisualMode() && input.is('a')) || (isVisualMode() && input.is('A'))) {
         leaveVisualMode();
+        setUndoPosition(position());
+        breakEditBlock();
         enterInsertMode();
         m_lastInsertion.clear();
         if (!atEndOfLine())
             moveRight();
         updateMiniBuffer();
     } else if (input.is('A')) {
+        setUndoPosition(position());
+        breakEditBlock();
         enterInsertMode();
         moveBehindEndOfLine();
         setDotCommand(QString(QLatin1Char('A')));
@@ -1791,14 +2014,14 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
     } else if ((input.is('d') || input.is('x')) && isVisualLineMode()) {
         leaveVisualMode();
         m_rangemode = RangeLineMode;
-        yankSelectedText();
-        removeSelectedText();
+        yankText(currentRange(), m_register);
+        removeText(currentRange());
         handleStartOfLine();
     } else if ((input.is('d') || input.is('x')) && isVisualBlockMode()) {
         leaveVisualMode();
         m_rangemode = RangeBlockMode;
-        yankSelectedText();
-        removeSelectedText();
+        yankText(currentRange(), m_register);
+        removeText(currentRange());
         setPosition(qMin(position(), anchor()));
     } else if (input.is('D') && isNoVisualMode()) {
         if (atEndOfLine())
@@ -1815,14 +2038,14 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         leaveVisualMode();
         m_rangemode = RangeLineMode;
         m_submode = NoSubMode;
-        yankSelectedText();
-        removeSelectedText();
+        yankText(currentRange(), m_register);
+        removeText(currentRange());
         moveToFirstNonBlankOnLine();
     } else if ((input.is('D') || input.is('X')) && isVisualBlockMode()) {
         leaveVisualMode();
         m_rangemode = RangeBlockAndTailMode;
-        yankSelectedText();
-        removeSelectedText();
+        yankText(currentRange(), m_register);
+        removeText(currentRange());
         setPosition(qMin(position(), anchor()));
     } else if (input.isControl('d')) {
         int sline = cursorLineOnScreen();
@@ -1874,8 +2097,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
             m_tc.setPosition(firstPositionInLine(n), KeepAnchor);
         }
         finishMovement(dotCommand);
-    } else if (input.is('h') || input.isKey(Key_Left)
-            || input.isKey(Key_Backspace) || input.isControl('h')) {
+    } else if (input.is('h') || input.isKey(Key_Left) || input.isBackspace()) {
         m_movetype = MoveExclusive;
         int n = qMin(count(), leftDist());
         if (m_fakeEnd && m_tc.block().length() > 1)
@@ -1890,6 +2112,8 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         finishMovement();
     } else if (!isVisualMode() && (input.is('i') || input.isKey(Key_Insert))) {
         setDotCommand(QString(QLatin1Char('i'))); // setDotCommand("%1i", count());
+        setUndoPosition(position());
+        breakEditBlock();
         enterInsertMode();
         updateMiniBuffer();
         if (atEndOfLine())
@@ -1909,6 +2133,8 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
             m_gflag = false;
             m_tc.clearSelection();
         }
+        setUndoPosition(position());
+        breakEditBlock();
         enterInsertMode();
     } else if (input.isControl('i')) {
         if (!m_jumpListRedo.isEmpty()) {
@@ -1930,12 +2156,12 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
                 setAnchor();
                 moveRight();
                 if (m_gflag) {
-                    removeSelectedText();
+                    removeText(currentRange());
                 } else {
                     while (characterAtCursor() == ' '
                         || characterAtCursor() == '\t')
                         moveRight();
-                    removeSelectedText();
+                    removeText(currentRange());
                     m_tc.insertText(QString(QLatin1Char(' ')));
                 }
             }
@@ -1973,8 +2199,12 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         handleStartOfLine();
         finishMovement();
     } else if (input.is('n') || input.is('N')) {
-        search(lastSearchString(), m_lastSearchForward);
-        recordJump();
+        SearchData sd;
+        sd.needle = g.searchHistory.current();
+        sd.forward = input.is('n') ? m_lastSearchForward : !m_lastSearchForward;
+        sd.highlightCursor = false;
+        sd.highlightMatches = true;
+        search(sd);
     } else if (isVisualMode() && (input.is('o') || input.is('O'))) {
         int pos = position();
         setPosition(anchor());
@@ -1985,20 +2215,28 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         if (m_positionPastEnd)
             m_visualTargetColumn = -1;
         updateSelection();
-    } else if (input.is('o') || input.is('O')) {
-        beginEditBlock();
+    } else if (input.is('o')) {
         setDotCommand("%1o", count());
+        setUndoPosition(position());
+        breakEditBlock();
         enterInsertMode();
-        m_beginEditBlock = false;
+        beginEditBlock(position());
         moveToFirstNonBlankOnLine();
-        if (input.is('O'))
-            moveToStartOfLine();
-        else
-            moveBehindEndOfLine();
-        m_tc.insertText("\n");
-        if (input.is('O'))
-            moveUp();
-        insertAutomaticIndentation(input.is('o'));
+        moveBehindEndOfLine();
+        insertText(Register("\n"));
+        insertAutomaticIndentation(true);
+        endEditBlock();
+    } else if (input.is('O')) {
+        setDotCommand("%1O", count());
+        setUndoPosition(position());
+        breakEditBlock();
+        enterInsertMode();
+        beginEditBlock(position());
+        moveToFirstNonBlankOnLine();
+        moveToStartOfLine();
+        insertText(Register("\n"));
+        moveUp();
+        insertAutomaticIndentation(false);
         endEditBlock();
     } else if (input.isControl('o')) {
         if (!m_jumpListUndo.isEmpty()) {
@@ -2011,19 +2249,13 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         setTargetColumn();
         setDotCommand("%1p", count());
         finishMovement();
-    } else if (isVisualMode() && input.is('r')) {
+    } else if (input.is('r')) {
         m_submode = TransformSubMode;
         m_subsubmode = ReplaceSubSubMode;
-    } else if (input.is('r')) {
-        m_submode = ReplaceSubMode;
-        setDotCommand(QString(QLatin1Char('r')));
     } else if (!isVisualMode() && input.is('R')) {
-        // FIXME: right now we repeat the insertion count() times,
-        // but not the deletion
-        m_lastInsertion.clear();
-        enterInsertMode();
-        m_submode = ReplaceSubMode;
-        setDotCommand(QString(QLatin1Char('R')));
+        setUndoPosition(position());
+        breakEditBlock();
+        enterReplaceMode();
         updateMiniBuffer();
     } else if (input.isControl('r')) {
         redo();
@@ -2033,11 +2265,13 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
             moveLeft();
         setAnchor();
         moveRight(qMin(count(), rightDist()));
-        yankSelectedText();
-        removeSelectedText();
+        yankText(currentRange(), m_register);
+        removeText(currentRange());
         setDotCommand("%1s", count());
         m_opcount.clear();
         m_mvcount.clear();
+        setUndoPosition(position());
+        breakEditBlock();
         enterInsertMode();
     } else if (input.is('S')) {
         if (!isVisualMode()) {
@@ -2046,8 +2280,9 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
             setPosition(lastPositionInLine(line + count() - 1));
         }
         setDotCommand("%1S", count());
+        setUndoPosition(position());
+        breakEditBlock();
         enterInsertMode();
-        m_beginEditBlock = false;
         m_submode = ChangeSubMode;
         m_movetype = MoveLineWise;
         finishMovement();
@@ -2116,8 +2351,8 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         if (leftDist() > 0) {
             setAnchor();
             moveLeft(qMin(count(), leftDist()));
-            yankSelectedText();
-            removeSelectedText();
+            yankText(currentRange(), m_register);
+            removeText(currentRange());
         }
         finishMovement();
     } else if ((m_submode == YankSubMode && input.is('y'))
@@ -2143,14 +2378,14 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
             || (input.is('Y') && isVisualLineMode())
             || (input.is('Y') && isVisualCharMode())) {
         m_rangemode = RangeLineMode;
-        yankSelectedText();
+        yankText(currentRange(), m_register);
         setPosition(qMin(position(), anchor()));
         moveToStartOfLine();
         leaveVisualMode();
         finishMovement();
     } else if ((input.is('y') || input.is('Y')) && isVisualBlockMode()) {
         m_rangemode = RangeBlockMode;
-        yankSelectedText();
+        yankText(currentRange(), m_register);
         setPosition(qMin(position(), anchor()));
         leaveVisualMode();
         finishMovement();
@@ -2159,18 +2394,19 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
     } else if (input.is('Z')) {
         m_submode = CapitalZSubMode;
     } else if (!m_gflag && input.is('~') && !isVisualMode()) {
+        m_movetype = MoveExclusive;
         if (!atEndOfLine()) {
             beginEditBlock();
             setAnchor();
             moveRight(qMin(count(), rightDist()));
             if (input.is('~')) {
-                invertCaseSelectedText();
+                invertCase(currentRange());
                 setDotCommand("%1~", count());
             } else if (input.is('u')) {
-                downCaseSelectedText();
+                downCase(currentRange());
                 setDotCommand("%1gu", count());
             } else if (input.is('U')) {
-                upCaseSelectedText();
+                upCase(currentRange());
                 setDotCommand("%1gU", count());
             }
             endEditBlock();
@@ -2180,6 +2416,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         || (m_gflag && input.is('u') && !isVisualMode())
         || (m_gflag && input.is('U') && !isVisualMode())) {
         m_gflag = false;
+        m_movetype = MoveExclusive;
         if (atEndOfLine())
             moveLeft();
         setAnchor();
@@ -2194,6 +2431,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         || (m_gflag && input.is('u') && isVisualMode())
         || (m_gflag && input.is('U') && isVisualMode())) {
         m_gflag = false;
+        m_movetype = MoveExclusive;
         if (isVisualLineMode())
             m_rangemode = RangeLineMode;
         else if (isVisualBlockMode())
@@ -2220,7 +2458,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
     } else if (input.is(Key_Delete)) {
         setAnchor();
         moveRight(qMin(1, rightDist()));
-        removeSelectedText();
+        removeText(currentRange());
     } else if (input.is(Key_BracketLeft) || input.is(Key_BracketRight)) {
 
     } else if (input.isControl(Key_BracketRight)) {
@@ -2241,13 +2479,36 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
     return handled;
 }
 
+EventResult FakeVimHandler::Private::handleReplaceMode(const Input &input)
+{
+    if (input.isEscape()) {
+        moveLeft(qMin(1, leftDist()));
+        setTargetColumn();
+        m_submode = NoSubMode;
+        m_mode = CommandMode;
+        finishMovement();
+    } else {
+        joinPreviousEditBlock();
+        if (!atEndOfLine()) {
+            setAnchor();
+            moveRight();
+            m_lastDeletion += selectText(Range(position(), anchor()));
+            removeText(currentRange());
+        }
+        const QString text = input.text();
+        m_lastInsertion += text;
+        insertText(text);
+        endEditBlock();
+    }
+    return EventHandled;
+}
+
 EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
 {
     //const int key = input.key;
     //const QString &text = input.text;
 
-    if (input.isKey(Key_Escape) || input.isKey(27) || input.isControl('c') ||
-         input.isControl(Key_BracketLeft)) {
+    if (input.isEscape()) {
         if (isVisualBlockMode() && !m_lastInsertion.contains('\n')) {
             leaveVisualMode();
             joinPreviousEditBlock();
@@ -2257,7 +2518,7 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
             setTargetColumn();
             for (int i = 0; i < m_visualInsertCount; ++i) {
                 moveDown();
-                m_tc.insertText(m_lastInsertion);
+                insertText(m_lastInsertion);
             }
             moveLeft(1);
             Range range(pos, position(), RangeBlockMode);
@@ -2266,32 +2527,26 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
             setDotCommand("p");
             endEditBlock();
         } else {
-            // normal insertion. start with '1', as one instance was
-            // already physically inserted while typing
-            QString data = m_lastInsertion;
-            for (int i = 1; i < count(); ++i) {
-                m_tc.insertText(m_lastInsertion);
+            // Normal insertion. Start with '1', as one instance was
+            // already physically inserted while typing.
+            QString data;
+            for (int i = 1; i < count(); ++i)
                 data += m_lastInsertion;
-            }
+            insertText(data);
             moveLeft(qMin(1, leftDist()));
             setTargetColumn();
             leaveVisualMode();
-            recordNewUndo();
         }
-        m_dotCommand += m_lastInsertion;
-        m_dotCommand += QChar(27);
+        g.dotCommand += m_lastInsertion;
+        g.dotCommand += QChar(27);
         enterCommandMode();
         m_submode = NoSubMode;
     } else if (input.isKey(Key_Insert)) {
-        if (m_submode == ReplaceSubMode) {
-            EDITOR(setCursorWidth(m_cursorWidth));
-            EDITOR(setOverwriteMode(false));
-            m_submode = NoSubMode;
-        } else {
-            EDITOR(setCursorWidth(m_cursorWidth));
-            EDITOR(setOverwriteMode(true));
-            m_submode = ReplaceSubMode;
-        }
+        if (m_mode == ReplaceMode)
+            m_mode = InsertMode;
+        else
+            m_mode = ReplaceMode;
+        updateCursor();
     } else if (input.isKey(Key_Left)) {
         moveLeft(count());
         setTargetColumn();
@@ -2320,13 +2575,13 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
         moveBehindEndOfLine();
         setTargetColumn();
         m_lastInsertion.clear();
-    } else if (input.isKey(Key_Return)) {
+    } else if (input.isReturn()) {
         m_submode = NoSubMode;
-        m_tc.insertBlock();
+        insertText(Register("\n"));
         m_lastInsertion += "\n";
         insertAutomaticIndentation(true);
         setTargetColumn();
-    } else if (input.isKey(Key_Backspace) || input.isControl('h')) {
+    } else if (input.isBackspace()) {
         joinPreviousEditBlock();
         m_justAutoIndented = 0;
         if (!m_lastInsertion.isEmpty() || hasConfig(ConfigBackspace, "start")) {
@@ -2345,6 +2600,7 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
                 m_lastInsertion.clear(); // FIXME
             } else {
                 m_tc.deletePreviousChar();
+                fixMarks(position(), -1);
                 m_lastInsertion.chop(1);
             }
             setTargetColumn();
@@ -2367,7 +2623,7 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
         const int col = physicalCursorColumnInDocument();
         QString str = QString(ts - col % ts, ' ');
         m_lastInsertion.append(str);
-        m_tc.insertText(str);
+        insertText(str);
         setTargetColumn();
     } else if (input.isControl('d')) {
         // remove one level of indentation from the current line
@@ -2390,33 +2646,21 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
     //} else if (key >= control('a') && key <= control('z')) {
     //    // ignore these
     } else if (!input.text().isEmpty()) {
-        const QString text = input.text();
-        if (m_beginEditBlock) {
-            beginEditBlock();
-            m_beginEditBlock = false;
-        } else {
-            joinPreviousEditBlock();
-        }
+        joinPreviousEditBlock();
         m_justAutoIndented = 0;
+        const QString text = input.text();
         m_lastInsertion.append(text);
-        if (m_submode == ReplaceSubMode) {
-            if (atEndOfLine())
-                m_submode = NoSubMode;
-            else
-                m_tc.deleteChar();
-        }
-        m_tc.insertText(text);
+        insertText(text);
         if (hasConfig(ConfigSmartIndent) && isElectricCharacter(text.at(0))) {
             const QString leftText = m_tc.block().text()
                    .left(m_tc.position() - 1 - m_tc.block().position());
             if (leftText.simplified().isEmpty()) {
-                Range range(position(), position());
-                range.rangemode = m_rangemode;
+                Range range(position(), position(), m_rangemode);
                 indentText(range, text.at(0));
             }
         }
 
-        if (!m_inReplay)
+        if (!g.inReplay)
             emit q->completionRequested();
         setTargetColumn();
         endEditBlock();
@@ -2427,15 +2671,15 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
     return EventHandled;
 }
 
-EventResult FakeVimHandler::Private::handleMiniBufferModes(const Input &input)
+EventResult FakeVimHandler::Private::handleExMode(const Input &input)
 {
-    if (input.isKey(Key_Escape) || input.isControl('c')
-            || input.isControl(Key_BracketLeft)) {
+    if (input.isEscape()) {
         m_commandBuffer.clear();
         enterCommandMode();
         updateMiniBuffer();
-    } else if (input.isKey(Key_Backspace)) {
+    } else if (input.isBackspace()) {
         if (m_commandBuffer.isEmpty()) {
+            m_commandPrefix.clear();
             enterCommandMode();
         } else {
             m_commandBuffer.chop(1);
@@ -2446,74 +2690,109 @@ EventResult FakeVimHandler::Private::handleMiniBufferModes(const Input &input)
         if (!m_commandBuffer.isEmpty())
             m_commandBuffer.chop(1);
         updateMiniBuffer();
-    } else if (input.isKey(Key_Return) && m_mode == ExMode) {
+    } else if (input.isReturn()) {
         if (!m_commandBuffer.isEmpty()) {
-            m_commandHistory.takeLast();
-            m_commandHistory.append(m_commandBuffer);
+            //g.commandHistory.takeLast();
+            g.commandHistory.append(m_commandBuffer);
             handleExCommand(m_commandBuffer);
-            if (m_textedit || m_plaintextedit) {
+            if (m_textedit || m_plaintextedit)
                 leaveVisualMode();
-            }
-        }
-    } else if (input.isKey(Key_Return) && isSearchMode()
-            && !hasConfig(ConfigIncSearch)) {
-        if (!m_commandBuffer.isEmpty()) {
-            m_searchHistory.takeLast();
-            m_searchHistory.append(m_commandBuffer);
-            m_lastSearchForward = (m_mode == SearchForwardMode);
-            search(lastSearchString(), m_lastSearchForward);
-            recordJump();
         }
-        enterCommandMode();
         updateMiniBuffer();
-    } else if ((input.isKey(Key_Up) || input.isKey(Key_PageUp)) && isSearchMode()) {
-        // FIXME: This and the three cases below are wrong as vim
-        // takes only matching entries in the history into account.
-        if (m_searchHistoryIndex > 0) {
-            --m_searchHistoryIndex;
-            showBlackMessage(m_searchHistory.at(m_searchHistoryIndex));
-        }
-    } else if ((input.isKey(Key_Up) || input.isKey(Key_PageUp)) && m_mode == ExMode) {
-        if (m_commandHistoryIndex > 0) {
-            --m_commandHistoryIndex;
-            showBlackMessage(m_commandHistory.at(m_commandHistoryIndex));
-        }
-    } else if ((input.isKey(Key_Down) || input.isKey(Key_PageDown)) && isSearchMode()) {
-        if (m_searchHistoryIndex < m_searchHistory.size() - 1) {
-            ++m_searchHistoryIndex;
-            showBlackMessage(m_searchHistory.at(m_searchHistoryIndex));
-        }
-    } else if ((input.isKey(Key_Down) || input.isKey(Key_PageDown)) && m_mode == ExMode) {
-        if (m_commandHistoryIndex < m_commandHistory.size() - 1) {
-            ++m_commandHistoryIndex;
-            showBlackMessage(m_commandHistory.at(m_commandHistoryIndex));
-        }
+    } else if (input.isKey(Key_Up) || input.isKey(Key_PageUp)) {
+        g.commandHistory.up();
+        m_commandBuffer = g.commandHistory.current();
+        updateMiniBuffer();
+    } else if (input.isKey(Key_Down) || input.isKey(Key_PageDown)) {
+        g.commandHistory.down();
+        m_commandBuffer = g.commandHistory.current();
+        updateMiniBuffer();
     } else if (input.isKey(Key_Tab)) {
         m_commandBuffer += QChar(9);
         updateMiniBuffer();
-    } else if (input.isKey(Key_Return) && isSearchMode()
-            && hasConfig(ConfigIncSearch)) {
+    } else if (!input.text().isEmpty()) {
+        m_commandBuffer += input.text();
+        updateMiniBuffer();
+    } else {
+        qDebug() << "IGNORED IN EX-MODE: " << input.key() << input.text();
+        return EventUnhandled;
+    }
+    return EventHandled;
+}
+
+EventResult FakeVimHandler::Private::handleSearchSubSubMode(const Input &input)
+{
+    if (input.isEscape()) {
+        m_commandBuffer.clear();
+        m_searchCursor = QTextCursor();
+        updateSelection();
+        enterCommandMode();
+        updateMiniBuffer();
+    } else if (input.isBackspace()) {
+        if (m_commandBuffer.isEmpty()) {
+            m_commandPrefix.clear();
+            m_searchCursor = QTextCursor();
+            enterCommandMode();
+        } else {
+            m_commandBuffer.chop(1);
+        }
+        updateMiniBuffer();
+    } else if (input.isKey(Key_Left)) {
+        if (!m_commandBuffer.isEmpty())
+            m_commandBuffer.chop(1);
+        updateMiniBuffer();
+    } else if (input.isReturn()) {
+        m_searchCursor = QTextCursor();
+        QString needle = m_commandBuffer;
+        if (!needle.isEmpty()) {
+            g.searchHistory.append(needle);
+            if (!hasConfig(ConfigIncSearch)) {
+                SearchData sd;
+                sd.needle = needle;
+                sd.forward = m_lastSearchForward;
+                sd.highlightCursor = false;
+                sd.highlightMatches = true;
+                search(sd);
+            }
+            finishMovement(m_commandPrefix + needle + "\n");
+        }
         enterCommandMode();
-        QString needle = m_commandBuffer.mid(1); // FIXME: why
         highlightMatches(needle);
         updateMiniBuffer();
-    } else if (isSearchMode() && hasConfig(ConfigIncSearch)) {
-        m_commandBuffer = m_commandBuffer.mid(1); // FIXME: why
-        QString needle = m_commandBuffer + input.text();
-        search(needle, m_lastSearchForward, true);
+    } else if (input.isKey(Key_Up) || input.isKey(Key_PageUp)) {
+        // FIXME: This and the three cases below are wrong as vim
+        // takes only matching entries in the history into account.
+        g.searchHistory.up();
+        showBlackMessage(g.searchHistory.current());
+    } else if (input.isKey(Key_Down) || input.isKey(Key_PageDown)) {
+        g.searchHistory.down();
+        showBlackMessage(g.searchHistory.current());
+    } else if (input.isKey(Key_Tab)) {
+        m_commandBuffer += QChar(9);
         updateMiniBuffer();
-        recordJump();
     } else if (!input.text().isEmpty()) {
         m_commandBuffer += input.text();
         updateMiniBuffer();
-    } else {
-        qDebug() << "IGNORED IN MINIBUFFER MODE: " << input.key() << input.text();
-        return EventUnhandled;
     }
+
+    if (hasConfig(ConfigIncSearch) && !input.isReturn() && !input.isEscape()) {
+        SearchData sd;
+        sd.needle = m_commandBuffer;
+        sd.forward = m_lastSearchForward;
+        sd.mustMove = false;
+        sd.highlightCursor = true;
+        sd.highlightMatches = false;
+        search(sd);
+    }
+
+    //else {
+    //   qDebug() << "IGNORED IN SEARCH MODE: " << input.key() << input.text();
+    //   return EventUnhandled;
+    //}
     return EventHandled;
 }
 
-// 1 based.
+// This uses 1 based line counting.
 int FakeVimHandler::Private::readLineCode(QString &cmd)
 {
     //qDebug() << "CMD: " << cmd;
@@ -2521,19 +2800,32 @@ int FakeVimHandler::Private::readLineCode(QString &cmd)
         return -1;
     QChar c = cmd.at(0);
     cmd = cmd.mid(1);
-    if (c == '.')
+    if (c == '.') {
+        if (cmd.isEmpty())
+            return cursorLineInDocument() + 1;
+        QChar c1 = cmd.at(0);
+        if (c1 == '+' || c1 == '-') {
+            // Repeat for things like  .+4
+            cmd = cmd.mid(1);
+            return cursorLineInDocument() + readLineCode(cmd);
+        }
         return cursorLineInDocument() + 1;
+    }
     if (c == '$')
         return linesInDocument();
     if (c == '\'' && !cmd.isEmpty()) {
-        int mark = m_marks.value(cmd.at(0).unicode());
-        if (!mark) {
-            showRedMessage(msgE20MarkNotSet(cmd.at(0)));
+        if (cmd.isEmpty()) {
+            showRedMessage(msgMarkNotSet(QString()));
+            return -1;
+        }
+        int m = mark(cmd.at(0).unicode());
+        if (m == -1) {
+            showRedMessage(msgMarkNotSet(cmd.at(0)));
             cmd = cmd.mid(1);
             return -1;
         }
         cmd = cmd.mid(1);
-        return lineForPosition(mark);
+        return lineForPosition(m);
     }
     if (c == '-') {
         int n = readLineCode(cmd);
@@ -2544,10 +2836,9 @@ int FakeVimHandler::Private::readLineCode(QString &cmd)
         return cursorLineInDocument() + 1 + (n == -1 ? 1 : n);
     }
     if (c == '\'' && !cmd.isEmpty()) {
-        int pos = m_marks.value(cmd.at(0).unicode(), -1);
-        //qDebug() << " MARK: " << cmd.at(0) << pos << lineForPosition(pos);
+        int pos = mark(cmd.at(0).unicode());
         if (pos == -1) {
-            showRedMessage(msgE20MarkNotSet(cmd.at(0)));
+            showRedMessage(msgMarkNotSet(cmd.at(0)));
             cmd = cmd.mid(1);
             return -1;
         }
@@ -2566,24 +2857,16 @@ int FakeVimHandler::Private::readLineCode(QString &cmd)
         //qDebug() << "N: " << n;
         return n;
     }
-    // not parsed
+    // Parsing failed.
     cmd = c + cmd;
     return -1;
 }
 
-void FakeVimHandler::Private::selectRange(int beginLine, int endLine)
+void FakeVimHandler::Private::setCurrentRange(const Range &range)
 {
-    if (beginLine == -1)
-        beginLine = cursorLineInDocument();
-    if (endLine == -1)
-        endLine = cursorLineInDocument();
-    if (beginLine > endLine)
-        qSwap(beginLine, endLine);
-    setAnchor(firstPositionInLine(beginLine));
-    if (endLine == linesInDocument())
-       setPosition(lastPositionInLine(endLine));
-    else
-       setPosition(firstPositionInLine(endLine + 1));
+    setAnchor(range.beginPos);
+    setPosition(range.endPos);
+    m_rangemode = range.rangemode;
 }
 
 // use handleExCommand for invoking commands that might move the cursor
@@ -2594,71 +2877,46 @@ void FakeVimHandler::Private::handleCommand(const QString &cmd)
     EDITOR(setTextCursor(m_tc));
 }
 
-QString FakeVimHandler::Private::extractCommand(const QString &line,
-    int *beginLine, int *endLine)
-{
-    QString cmd = line;
-    *beginLine = -1;
-    *endLine = -1;
-
-    // FIXME: that seems to be different for %w and %s
-    if (cmd.startsWith(QLatin1Char('%')))
-        cmd = "1,$" + cmd.mid(1);
-
-    int lineNumber = readLineCode(cmd);
-    if (lineNumber != -1)
-        *beginLine = lineNumber;
-
-    if (cmd.startsWith(',')) {
-        cmd = cmd.mid(1);
-        lineNumber = readLineCode(cmd);
-        if (lineNumber != -1)
-            *endLine = lineNumber;
-    }
-    //qDebug() << "RANGE: " << beginLine << endLine << cmd << lineNumber << m_marks;
-    return cmd;
-}
-
-bool FakeVimHandler::Private::handleExSubstituteCommand(const QString &line)
+bool FakeVimHandler::Private::handleExSubstituteCommand(const ExCommand &cmd)
     // :substitute
 {
-    int beginLine, endLine;
-    QString cmd = extractCommand(line, &beginLine, &endLine);
-
-    if (cmd.startsWith(QLatin1String("substitute")))
-        cmd = cmd.mid(10);
-    else if (cmd.startsWith('s') && line.size() > 1
-            && !isalpha(cmd.at(1).unicode()))
-        cmd = cmd.mid(1);
+    QString line = cmd.cmd + ' ' + cmd.args;
+    line = line.trimmed();
+    if (line.startsWith(_("substitute")))
+        line = line.mid(10);
+    else if (line.startsWith('s') && line.size() > 1
+            && !isalpha(line.at(1).unicode()))
+        line = line.mid(1);
     else
         return false;
+
     // we have /{pattern}/{string}/[flags]  now
-    if (cmd.isEmpty())
+    if (line.isEmpty())
         return false;
-    const QChar separator = cmd.at(0);
+    const QChar separator = line.at(0);
     int pos1 = -1;
     int pos2 = -1;
     int i;
-    for (i = 1; i < cmd.size(); ++i) {
-        if (cmd.at(i) == separator && cmd.at(i - 1) != '\\') {
+    for (i = 1; i < line.size(); ++i) {
+        if (line.at(i) == separator && line.at(i - 1) != '\\') {
             pos1 = i;
             break;
         }
     }
     if (pos1 == -1)
         return false;
-    for (++i; i < cmd.size(); ++i) {
-        if (cmd.at(i) == separator && cmd.at(i - 1) != '\\') {
+    for (++i; i < line.size(); ++i) {
+        if (line.at(i) == separator && line.at(i - 1) != '\\') {
             pos2 = i;
             break;
         }
     }
     if (pos2 == -1)
-        pos2 = cmd.size();
+        pos2 = line.size();
 
-    QString needle = cmd.mid(1, pos1 - 1);
-    const QString replacement = cmd.mid(pos1 + 1, pos2 - pos1 - 1);
-    QString flags = cmd.mid(pos2 + 1);
+    QString needle = line.mid(1, pos1 - 1);
+    const QString replacement = line.mid(pos1 + 1, pos2 - pos1 - 1);
+    QString flags = line.mid(pos2 + 1);
 
     needle.replace('$', '\n');
     needle.replace("\\\n", "\\$");
@@ -2666,6 +2924,8 @@ bool FakeVimHandler::Private::handleExSubstituteCommand(const QString &line)
     if (flags.contains('i'))
         pattern.setCaseSensitivity(Qt::CaseInsensitive);
     const bool global = flags.contains('g');
+    const int beginLine = lineForPosition(cmd.range.beginPos);
+    const int endLine = lineForPosition(cmd.range.endPos);
     beginEditBlock();
     for (int line = endLine; line >= beginLine; --line) {
         QString origText = lineContents(line);
@@ -2700,19 +2960,12 @@ bool FakeVimHandler::Private::handleExSubstituteCommand(const QString &line)
     return true;
 }
 
-bool FakeVimHandler::Private::handleExMapCommand(const QString &line) // :map
+bool FakeVimHandler::Private::handleExMapCommand(const ExCommand &cmd0) // :map
 {
-    int pos1 = line.indexOf(QLatin1Char(' '));
-    if (pos1 == -1)
-        return false;
-    int pos2 = line.indexOf(QLatin1Char(' '), pos1 + 1);
-    if (pos2 == -1)
-        return false;
-
     QByteArray modes;
     enum Type { Map, Noremap, Unmap } type;
 
-    QByteArray cmd = line.left(pos1).toLatin1();
+    QByteArray cmd = cmd0.cmd.toLatin1();
 
     // Strange formatting. But everything else is even uglier.
     if (cmd == "map") { modes = "nvo"; type = Map; } else
@@ -2750,45 +3003,48 @@ bool FakeVimHandler::Private::handleExMapCommand(const QString &line) // :map
     else
         return false;
 
-    QString lhs = line.mid(pos1 + 1, pos2 - pos1 - 1);
-    QString rhs = line.mid(pos2 + 1);
+    const int pos = cmd0.args.indexOf(QLatin1Char(' '));
+    if (pos == -1) {
+        // FIXME: Dump mappings here.
+        //qDebug() << g.mappings;
+        return true;;
+    }
+
+    QString lhs = cmd0.args.left(pos);
+    QString rhs = cmd0.args.mid(pos + 1);
     Inputs key;
-    foreach (QChar c, lhs)
-        key.append(Input(c));
+    key.parseFrom(lhs);
     //qDebug() << "MAPPING: " << modes << lhs << rhs;
     switch (type) {
         case Unmap:
             foreach (char c, modes)
-                if (m_mappings.contains(c))
-                    m_mappings[c].remove(key);
+                if (g.mappings.contains(c))
+                    g.mappings[c].remove(key);
             break;
         case Map:
             rhs = rhs; // FIXME: expand rhs.
             // Fall through.
         case Noremap: {
-            Inputs inputs;
-            foreach (QChar c, rhs)
-                inputs.append(Input(c));
+            Inputs inputs(rhs);
             foreach (char c, modes)
-                m_mappings[c].insert(key, inputs);
+                g.mappings[c].insert(key, inputs);
             break;
         }
     }
     return true;
 }
 
-bool FakeVimHandler::Private::handleExHistoryCommand(const QString &cmd) // :history
+bool FakeVimHandler::Private::handleExHistoryCommand(const ExCommand &cmd)
 {
-    static QRegExp reHistory("^his(tory)?( (.*))?$");
-    if (reHistory.indexIn(cmd) == -1)
+    // :history
+    if (cmd.cmd != "his" && cmd.cmd != "history")
         return false;
 
-    QString arg = reHistory.cap(3);
-    if (arg.isEmpty()) {
+    if (cmd.args.isEmpty()) {
         QString info;
         info += "#  command history\n";
         int i = 0;
-        foreach (const QString &item, m_commandHistory) {
+        foreach (const QString &item, g.commandHistory.items()) {
             ++i;
             info += QString("%1 %2\n").arg(i, -8).arg(item);
         }
@@ -2800,164 +3056,176 @@ bool FakeVimHandler::Private::handleExHistoryCommand(const QString &cmd) // :his
     return true;
 }
 
-bool FakeVimHandler::Private::handleExSetCommand(const QString &cmd) // :set
+bool FakeVimHandler::Private::handleExRegisterCommand(const ExCommand &cmd)
+{
+    // :reg and :di[splay]
+    if (cmd.cmd != "reg" && cmd.cmd != "registers"
+            && cmd.cmd != "di" && cmd.cmd != "display")
+        return false;
+
+    QByteArray regs = cmd.args.toLatin1();
+    if (regs.isEmpty()) {
+        regs = "\"0123456789";
+        QHashIterator<int, Register> it(g.registers);
+        while (it.hasNext()) {
+            it.next();
+            if (it.key() > '9')
+                regs += char(it.key());
+        }
+    }
+    QString info;
+    info += "--- Registers ---\n";
+    foreach (char reg, regs) {
+        QString value = quoteUnprintable(g.registers[reg].contents);
+        info += QString("\"%1   %2\n").arg(reg).arg(value);
+    }
+    emit q->extraInformationChanged(info);
+    updateMiniBuffer();
+    return true;
+}
+
+bool FakeVimHandler::Private::handleExSetCommand(const ExCommand &cmd)
 {
-    static QRegExp reSet("^set?( (.*))?$");
-    if (reSet.indexIn(cmd) == -1)
+    // :set
+    if (cmd.cmd != "se" && cmd.cmd != "set")
         return false;
 
     showBlackMessage(QString());
-    QString arg = reSet.cap(2);
-    SavedAction *act = theFakeVimSettings()->item(arg);
-    if (arg.isEmpty()) {
-        theFakeVimSetting(SettingsDialog)->trigger(QVariant());
-    } else if (act && act->value().type() == QVariant::Bool) {
-        // boolean config to be switched on
+    SavedAction *act = theFakeVimSettings()->item(cmd.args);
+    QTC_ASSERT(!cmd.args.isEmpty(), /**/); // Handled by plugin.
+    if (act && act->value().type() == QVariant::Bool) {
+        // Boolean config to be switched on.
         bool oldValue = act->value().toBool();
         if (oldValue == false)
             act->setValue(true);
         else if (oldValue == true)
             {} // nothing to do
     } else if (act) {
-        // non-boolean to show
-        showBlackMessage(arg + '=' + act->value().toString());
-    } else if (arg.startsWith(QLatin1String("no"))
-            && (act = theFakeVimSettings()->item(arg.mid(2)))) {
-        // boolean config to be switched off
+        // Non-boolean to show.
+        showBlackMessage(cmd.args + '=' + act->value().toString());
+    } else if (cmd.args.startsWith(_("no"))
+            && (act = theFakeVimSettings()->item(cmd.args.mid(2)))) {
+        // Boolean config to be switched off.
         bool oldValue = act->value().toBool();
         if (oldValue == true)
             act->setValue(false);
         else if (oldValue == false)
             {} // nothing to do
-    } else if (arg.contains('=')) {
-        // non-boolean config to set
-        int p = arg.indexOf('=');
-        act = theFakeVimSettings()->item(arg.left(p));
+    } else if (cmd.args.contains('=')) {
+        // Non-boolean config to set.
+        int p = cmd.args.indexOf('=');
+        act = theFakeVimSettings()->item(cmd.args.left(p));
         if (act)
-            act->setValue(arg.mid(p + 1));
+            act->setValue(cmd.args.mid(p + 1));
     } else {
-        passUnknownSetCommand(arg);
+        showRedMessage(FakeVimHandler::tr("Unknown option: ") + cmd.args);
     }
     updateMiniBuffer();
     updateEditor();
     return true;
 }
 
-bool FakeVimHandler::Private::handleExNormalCommand(const QString &cmd) // :normal
+bool FakeVimHandler::Private::handleExNormalCommand(const ExCommand &cmd)
 {
-    static QRegExp reNormal("^norm(al)?( (.*))?$");
-    if (reNormal.indexIn(cmd) == -1)
+    // :normal
+    if (cmd.cmd != "norm" && cmd.cmd != "normal") 
         return false;
-    //qDebug() << "REPLAY: " << reNormal.cap(3);
-    replay(reNormal.cap(3), 1);
+    //qDebug() << "REPLAY NORMAL: " << quoteUnprintable(reNormal.cap(3));
+    replay(cmd.args, 1);
     return true;
 }
 
-bool FakeVimHandler::Private::handleExDeleteCommand(const QString &line) // :d
+bool FakeVimHandler::Private::handleExDeleteCommand(const ExCommand &cmd)
 {
-    int beginLine, endLine;
-    QString cmd = extractCommand(line, &beginLine, &endLine);
-
-    static QRegExp reDelete("^d( (.*))?$");
-    if (reDelete.indexIn(cmd) != -1)
+    // :delete
+    if (cmd.cmd != "d" && cmd.cmd != "delete")
         return false;
 
-    selectRange(beginLine, endLine);
-    QString reg = reDelete.cap(2);
-    QString text = selectedText();
-    removeSelectedText();
+    setCurrentRange(cmd.range);
+    QString reg = cmd.args;
+    QString text = selectText(cmd.range);
+    removeText(currentRange());
     if (!reg.isEmpty()) {
-        Register &r = m_registers[reg.at(0).unicode()];
+        Register &r = g.registers[reg.at(0).unicode()];
         r.contents = text;
         r.rangemode = RangeLineMode;
     }
     return true;
 }
 
-bool FakeVimHandler::Private::handleExWriteCommand(const QString &line)
-    // :w, :x, :q, :wq, ...
+bool FakeVimHandler::Private::handleExWriteCommand(const ExCommand &cmd)
 {
-    int beginLine, endLine;
-    QString cmd = extractCommand(line, &beginLine, &endLine);
-
-    static QRegExp reWrite("^[wx]q?a?!?( (.*))?$");
-    if (reWrite.indexIn(cmd) == -1) // :w and :x
+    // :w, :x, :wq, ...
+    //static QRegExp reWrite("^[wx]q?a?!?( (.*))?$");
+    if (cmd.cmd != "w" && cmd.cmd != "x" && cmd.cmd != "wq")
         return false;
 
-    bool noArgs = (beginLine == -1);
+    int beginLine = lineForPosition(cmd.range.beginPos);
+    int endLine = lineForPosition(cmd.range.endPos);
+    const bool noArgs = (beginLine == -1);
     if (beginLine == -1)
         beginLine = 0;
     if (endLine == -1)
         endLine = linesInDocument();
     //qDebug() << "LINES: " << beginLine << endLine;
-    int indexOfSpace = cmd.indexOf(QChar(' '));
-    QString prefix;
-    if (indexOfSpace < 0)
-        prefix = cmd;
-    else
-        prefix = cmd.left(indexOfSpace);
-    bool forced = prefix.contains(QChar('!'));
-    bool quit = prefix.contains(QChar('q')) || prefix.contains(QChar('x'));
-    bool quitAll = quit && prefix.contains(QChar('a'));
-    QString fileName = reWrite.cap(2);
+    QString prefix = cmd.args;
+    const bool forced = cmd.hasBang;
+    //const bool quit = prefix.contains(QChar('q')) || prefix.contains(QChar('x'));
+    //const bool quitAll = quit && prefix.contains(QChar('a'));
+    QString fileName = cmd.args;
     if (fileName.isEmpty())
         fileName = m_currentFileName;
     QFile file1(fileName);
-    bool exists = file1.exists();
+    const bool exists = file1.exists();
     if (exists && !forced && !noArgs) {
         showRedMessage(FakeVimHandler::tr
-            ("File '%1' exists (add ! to override)").arg(fileName));
+            ("File \"%1\" exists (add ! to override)").arg(fileName));
     } else if (file1.open(QIODevice::ReadWrite)) {
+        // Nobody cared, so act ourselves.
         file1.close();
         QTextCursor tc = m_tc;
         Range range(firstPositionInLine(beginLine),
             firstPositionInLine(endLine), RangeLineMode);
-        QString contents = text(range);
+        QString contents = selectText(range);
         m_tc = tc;
-        //qDebug() << "LINES: " << beginLine << endLine;
-        bool handled = false;
-        emit q->writeFileRequested(&handled, fileName, contents);
-        // nobody cared, so act ourselves
-        if (!handled) {
-            //qDebug() << "HANDLING MANUAL SAVE TO " << fileName;
-            QFile::remove(fileName);
-            QFile file2(fileName);
-            if (file2.open(QIODevice::ReadWrite)) {
-                QTextStream ts(&file2);
-                ts << contents;
-            } else {
-                showRedMessage(FakeVimHandler::tr
-                   ("Cannot open file '%1' for writing").arg(fileName));
-            }
+        QFile::remove(fileName);
+        QFile file2(fileName);
+        if (file2.open(QIODevice::ReadWrite)) {
+            QTextStream ts(&file2);
+            ts << contents;
+        } else {
+            showRedMessage(FakeVimHandler::tr
+               ("Cannot open file \"%1\" for writing").arg(fileName));
         }
-        // check result by reading back
+        // Check result by reading back.
         QFile file3(fileName);
         file3.open(QIODevice::ReadOnly);
         QByteArray ba = file3.readAll();
         showBlackMessage(FakeVimHandler::tr("\"%1\" %2 %3L, %4C written")
             .arg(fileName).arg(exists ? " " : " [New] ")
             .arg(ba.count('\n')).arg(ba.size()));
-        if (quitAll)
-            passUnknownExCommand(forced ? "qa!" : "qa");
-        else if (quit)
-            passUnknownExCommand(forced ? "q!" : "q");
+        //if (quitAll)
+        //    passUnknownExCommand(forced ? "qa!" : "qa");
+        //else if (quit)
+        //    passUnknownExCommand(forced ? "q!" : "q");
     } else {
         showRedMessage(FakeVimHandler::tr
-            ("Cannot open file '%1' for reading").arg(fileName));
+            ("Cannot open file \"%1\" for reading").arg(fileName));
     }
     return true;
 }
 
-bool FakeVimHandler::Private::handleExReadCommand(const QString &line) // :r
+bool FakeVimHandler::Private::handleExReadCommand(const ExCommand &cmd)
 {
-    if (!line.startsWith(QLatin1String("r ")))
+    // :read
+    if (cmd.cmd != "r" && cmd.cmd != "read")
         return false;
 
     beginEditBlock();
     moveToStartOfLine();
     setTargetColumn();
     moveDown();
-    m_currentFileName = line.mid(2);
+    m_currentFileName = cmd.args;
     QFile file(m_currentFileName);
     file.open(QIODevice::ReadOnly);
     QTextStream ts(&file);
@@ -2969,28 +3237,28 @@ bool FakeVimHandler::Private::handleExReadCommand(const QString &line) // :r
     return true;
 }
 
-bool FakeVimHandler::Private::handleExBangCommand(const QString &line) // :!
+bool FakeVimHandler::Private::handleExBangCommand(const ExCommand &cmd) // :!
 {
-    int beginLine, endLine;
-    QString cmd = extractCommand(line, &beginLine, &endLine);
-
-    if (!cmd.startsWith(QLatin1Char('!')))
+    if (!cmd.cmd.startsWith(QLatin1Char('!')))
         return false;
 
-    selectRange(beginLine, endLine);
-    int targetPosition = firstPositionInLine(beginLine);
-    QString command = cmd.mid(1).trimmed();
-    QString text = selectedText();
+    setCurrentRange(cmd.range);
+    int targetPosition = firstPositionInLine(lineForPosition(cmd.range.beginPos));
+    QString command = QString(cmd.cmd.mid(1) + ' ' + cmd.args).trimmed();
+    QString text = selectText(cmd.range);
     QProcess proc;
-    proc.start(cmd.mid(1));
+    proc.start(command);
     proc.waitForStarted();
+#ifdef Q_OS_WIN
+    text.replace(_("\n"), _("\r\n"));
+#endif
     proc.write(text.toUtf8());
     proc.closeWriteChannel();
     proc.waitForFinished();
     QString result = QString::fromUtf8(proc.readAllStandardOutput());
     beginEditBlock(targetPosition);
-    removeSelectedText();
-    m_tc.insertText(result);
+    removeText(currentRange());
+    insertText(result);
     setPosition(targetPosition);
     endEditBlock();
     leaveVisualMode();
@@ -3000,26 +3268,29 @@ bool FakeVimHandler::Private::handleExBangCommand(const QString &line) // :!
     return true;
 }
 
-bool FakeVimHandler::Private::handleExShiftRightCommand(const QString &line) // :>
+bool FakeVimHandler::Private::handleExShiftCommand(const ExCommand &cmd)
 {
-    int beginLine, endLine;
-    QString cmd = extractCommand(line, &beginLine, &endLine);
-
-    if (!cmd.startsWith(QLatin1Char('>')))
+    if (cmd.cmd != "<" && cmd.cmd != ">")
         return false;
 
-    m_anchor = firstPositionInLine(beginLine);
-    setPosition(firstPositionInLine(endLine));
-    shiftRegionRight(1);
+    setCurrentRange(cmd.range);
+    int count = qMin(1, cmd.args.toInt());
+    if (cmd.cmd == "<")
+        shiftRegionLeft(count);
+    else
+        shiftRegionRight(count);
     leaveVisualMode();
-    showBlackMessage(FakeVimHandler::tr("%n lines >ed %1 time", 0,
-        (endLine - beginLine + 1)).arg(1));
+    const int beginLine = lineForPosition(cmd.range.beginPos);
+    const int endLine = lineForPosition(cmd.range.endPos);
+    showBlackMessage(FakeVimHandler::tr("%n lines %1ed %2 time", 0,
+        (endLine - beginLine + 1)).arg(cmd.cmd).arg(count));
     return true;
 }
 
-bool FakeVimHandler::Private::handleExRedoCommand(const QString &line) // :redo
+bool FakeVimHandler::Private::handleExRedoCommand(const ExCommand &cmd)
 {
-    if (line != "red" && line != "redo")
+    // :redo
+    if (cmd.cmd != "red" && cmd.cmd != "redo")
         return false;
 
     redo();
@@ -3027,26 +3298,25 @@ bool FakeVimHandler::Private::handleExRedoCommand(const QString &line) // :redo
     return true;
 }
 
-bool FakeVimHandler::Private::handleExGotoCommand(const QString &line) // :<nr>
+bool FakeVimHandler::Private::handleExGotoCommand(const ExCommand &cmd)
 {
-    int beginLine, endLine;
-    QString cmd = extractCommand(line, &beginLine, &endLine);
-
-    if (!cmd.isEmpty())
+    // :<nr>
+    if (!cmd.cmd.isEmpty())
         return false;
 
+    const int beginLine = lineForPosition(cmd.range.beginPos);
     setPosition(firstPositionInLine(beginLine));
     showBlackMessage(QString());
     return true;
 }
 
-bool FakeVimHandler::Private::handleExSourceCommand(const QString &line) // :source
+bool FakeVimHandler::Private::handleExSourceCommand(const ExCommand &cmd)
 {
-    int pos = line.indexOf(' ');
-    if (line.leftRef(pos) != "so" && line.leftRef(pos) != "source")
+    // :source
+    if (cmd.cmd != "so" && cmd.cmd != "source")
         return false;
 
-    QString fileName = line.mid(pos + 1);
+    QString fileName = cmd.args;
     QFile file(fileName);
     if (!file.open(QIODevice::ReadOnly)) {
         showRedMessage(FakeVimHandler::tr("Can't open file %1").arg(fileName));
@@ -3079,119 +3349,137 @@ bool FakeVimHandler::Private::handleExSourceCommand(const QString &line) // :sou
 void FakeVimHandler::Private::handleExCommand(const QString &line0)
 {
     QString line = line0; // Make sure we have a copy to prevent aliasing.
+    // FIXME: that seems to be different for %w and %s
+    if (line.startsWith(QLatin1Char('%')))
+        line = "1,$" + line.mid(1);
+
+    int beginLine = readLineCode(line);
+    int endLine = -1;
+    if (line.startsWith(',')) {
+        line = line.mid(1);
+        endLine = readLineCode(line);
+    }
+    if (beginLine != -1 && endLine == -1)
+        endLine = beginLine;
+    const int beginPos = firstPositionInLine(beginLine);
+    const int endPos = lastPositionInLine(endLine);
+    ExCommand cmd;
+    const QString arg0 = line.section(' ', 0, 0);
+    cmd.cmd = arg0;
+    cmd.args = line.mid(arg0.size() + 1).trimmed();
+    cmd.range = Range(beginPos, endPos, RangeLineMode);
+    cmd.hasBang = arg0.endsWith('!');
+    if (cmd.hasBang)
+        cmd.cmd.chop(1);
+    //qDebug() << "CMD: " << cmd;
+
     enterCommandMode();
     showBlackMessage(QString());
-    if (handleExCommandHelper(line))
-        return;
-    int beginLine, endLine;
-    passUnknownExCommand(extractCommand(line, &beginLine, &endLine));
+    if (!handleExCommandHelper(cmd))
+        showRedMessage(tr("Not an editor command: %1").arg(cmd.cmd));
 }
 
-bool FakeVimHandler::Private::handleExCommandHelper(const QString &line)
+bool FakeVimHandler::Private::handleExCommandHelper(const ExCommand &cmd)
 {
-    return handleExGotoCommand(line)
-        || handleExBangCommand(line)
-        || handleExHistoryCommand(line)
-        || handleExMapCommand(line)
-        || handleExNormalCommand(line)
-        || handleExReadCommand(line)
-        || handleExRedoCommand(line)
-        || handleExSetCommand(line)
-        || handleExShiftRightCommand(line)
-        || handleExSourceCommand(line)
-        || handleExSubstituteCommand(line)
-        || handleExWriteCommand(line);
+    return handleExPluginCommand(cmd)
+        || handleExGotoCommand(cmd)
+        || handleExBangCommand(cmd)
+        || handleExHistoryCommand(cmd)
+        || handleExRegisterCommand(cmd)
+        || handleExDeleteCommand(cmd)
+        || handleExMapCommand(cmd)
+        || handleExNormalCommand(cmd)
+        || handleExReadCommand(cmd)
+        || handleExRedoCommand(cmd)
+        || handleExSetCommand(cmd)
+        || handleExShiftCommand(cmd)
+        || handleExSourceCommand(cmd)
+        || handleExSubstituteCommand(cmd)
+        || handleExWriteCommand(cmd);
 }
 
-void FakeVimHandler::Private::passUnknownExCommand(const QString &cmd)
+bool FakeVimHandler::Private::handleExPluginCommand(const ExCommand &cmd)
 {
     EDITOR(setTextCursor(m_tc));
-    emit q->handleExCommandRequested(cmd);
+    bool handled = false;
+    emit q->handleExCommandRequested(&handled, cmd);
     if (m_plaintextedit || m_textedit)
         m_tc = EDITOR(textCursor());
-}
-
-void FakeVimHandler::Private::passUnknownSetCommand(const QString &arg)
-{
-    bool handled = false;
-    emit q->handleSetCommandRequested(&handled, arg);
-    if (!handled) {
-        showRedMessage(FakeVimHandler::tr("E512: Unknown option: ") + arg);
-    }
+    //qDebug() << "HANDLER REQUEST: " << cmd.cmd << handled;
+    return handled;
 }
 
 static void vimPatternToQtPattern(QString *needle, QTextDocument::FindFlags *flags)
 {
     // FIXME: Rough mapping of a common case
-    if (needle->startsWith(QLatin1String("\\<")) && needle->endsWith(QLatin1String("\\>")))
+    if (needle->startsWith(_("\\<")) && needle->endsWith(_("\\>")))
         (*flags) |= QTextDocument::FindWholeWords;
-    needle->remove(QLatin1String("\\<")); // start of word
-    needle->remove(QLatin1String("\\>")); // end of word
+    needle->remove(_("\\<")); // start of word
+    needle->remove(_("\\>")); // end of word
     //qDebug() << "NEEDLE " << needle0 << needle;
 }
 
-void FakeVimHandler::Private::search(const QString &needle0, bool forward,
-    bool incSearch)
+void FakeVimHandler::Private::search(const SearchData &sd)
 {
-    showBlackMessage((forward ? '/' : '?') + needle0);
-    CursorPosition origPosition = cursorPosition();
+    if (sd.needle.isEmpty())
+        return;
+
+    const bool incSearch = hasConfig(ConfigIncSearch);
     QTextDocument::FindFlags flags = QTextDocument::FindCaseSensitively;
-    if (!forward)
+    if (!sd.forward)
         flags |= QTextDocument::FindBackward;
 
-    QString needle = needle0;
+    QString needle = sd.needle;
     vimPatternToQtPattern(&needle, &flags);
 
-    if (forward)
-        m_tc.movePosition(Right, MoveAnchor, 1);
+    const int oldLine = cursorLineInDocument() - cursorLineOnScreen();
 
-    int oldLine = cursorLineInDocument() - cursorLineOnScreen();
+    int startPos = position();
+    if (sd.mustMove)
+        sd.forward ? ++startPos : --startPos;
 
-    EDITOR(setTextCursor(m_tc));
-    if (EDITOR(find(needle, flags))) {
-        m_tc = EDITOR(textCursor());
-        m_tc.setPosition(m_tc.anchor());
-        // making this unconditional feels better, but is not "vim like"
-        if (oldLine != cursorLineInDocument() - cursorLineOnScreen())
-            scrollToLineInDocument(cursorLineInDocument() - linesOnScreen() / 2);
-        if (!incSearch)
-            highlightMatches(needle);
-    } else {
-        m_tc.setPosition(forward ? 0 : lastPositionInDocument());
-        EDITOR(setTextCursor(m_tc));
-        if (EDITOR(find(needle, flags))) {
-            m_tc = EDITOR(textCursor());
-            m_tc.setPosition(m_tc.anchor());
-            if (oldLine != cursorLineInDocument() - cursorLineOnScreen())
-                scrollToLineInDocument(cursorLineInDocument() - linesOnScreen() / 2);
+    m_searchCursor = QTextCursor();
+    QTextCursor tc = m_tc.document()->find(needle, startPos, flags);
+    if (tc.isNull()) {
+        int startPos = sd.forward ? 0 : lastPositionInDocument();
+        tc = m_tc.document()->find(needle, startPos, flags);
+        if (tc.isNull()) {
             if (!incSearch) {
-                if (forward)
-                    showRedMessage(FakeVimHandler::tr("search hit BOTTOM, continuing at TOP"));
-                else
-                    showRedMessage(FakeVimHandler::tr("search hit TOP, continuing at BOTTOM"));
-                highlightMatches(needle);
-            }
-        } else {
-            if (!incSearch)
                 highlightMatches(QString());
-            setCursorPosition(origPosition);
-            if (!incSearch)
                 showRedMessage(FakeVimHandler::tr("Pattern not found: ") + needle);
+            }
+            updateSelection();
+            return;
+        }
+        if (!incSearch) {
+            QString msg = sd.forward
+                ? FakeVimHandler::tr("search hit BOTTOM, continuing at TOP")
+                : FakeVimHandler::tr("search hit TOP, continuing at BOTTOM");
+            showRedMessage(msg);
         }
     }
-    if (incSearch) {
-        QTextEdit::ExtraSelection sel;
-        sel.cursor = m_tc;
-        sel.format = m_tc.blockCharFormat();
-        sel.format.setForeground(Qt::white);
-        sel.format.setBackground(Qt::black);
-        sel.cursor.setPosition(m_tc.position(), MoveAnchor);
-        sel.cursor.setPosition(m_tc.position() + needle.size(), KeepAnchor);
-        QList<QTextEdit::ExtraSelection> selections = m_searchSelections;
-        selections.append(sel);
-        emit q->selectionChanged(selections);
+
+    // Set Cursor.
+    tc.setPosition(qMin(tc.position(), tc.anchor()), MoveAnchor);
+    tc.clearSelection();
+    m_tc = tc;
+    EDITOR(setTextCursor(m_tc));
+
+    // Making this unconditional feels better, but is not "vim like".
+    if (oldLine != cursorLineInDocument() - cursorLineOnScreen())
+        scrollToLineInDocument(cursorLineInDocument() - linesOnScreen() / 2);
+
+    if (incSearch && sd.highlightCursor) {
+        m_searchCursor = m_tc;
+        m_searchCursor.setPosition(m_tc.position(), MoveAnchor);
+        m_searchCursor.setPosition(m_tc.position() + needle.size(), KeepAnchor);
     }
     setTargetColumn();
+
+    if (sd.highlightMatches)
+        highlightMatches(needle);
+    updateSelection();
+    recordJump();
 }
 
 void FakeVimHandler::Private::highlightMatches(const QString &needle0)
@@ -3202,7 +3490,6 @@ void FakeVimHandler::Private::highlightMatches(const QString &needle0)
         return;
     m_oldNeedle = needle0;
     m_searchSelections.clear();
-
     if (!needle0.isEmpty()) {
         QTextCursor tc = m_tc;
         tc.movePosition(StartOfDocument, MoveAnchor);
@@ -3210,18 +3497,16 @@ void FakeVimHandler::Private::highlightMatches(const QString &needle0)
         QTextDocument::FindFlags flags = QTextDocument::FindCaseSensitively;
         QString needle = needle0;
         vimPatternToQtPattern(&needle, &flags);
-
-
-        EDITOR(setTextCursor(tc));
-        while (EDITOR(find(needle, flags))) {
-            tc = EDITOR(textCursor());
+        while (1) {
+            tc = tc.document()->find(needle, tc.position(), flags);
+            if (tc.isNull())
+                break;
             QTextEdit::ExtraSelection sel;
             sel.cursor = tc;
             sel.format = tc.blockCharFormat();
             sel.format.setBackground(QColor(177, 177, 0));
             m_searchSelections.append(sel);
             tc.movePosition(Right, MoveAnchor);
-            EDITOR(setTextCursor(tc));
         }
     }
     updateSelection();
@@ -3247,8 +3532,7 @@ void FakeVimHandler::Private::indentSelectedText(QChar typedChar)
     int beginLine = qMin(lineForPosition(position()), lineForPosition(anchor()));
     int endLine = qMax(lineForPosition(position()), lineForPosition(anchor()));
 
-    Range range(anchor(), position());
-    range.rangemode = m_rangemode;
+    Range range(anchor(), position(), m_rangemode);
     indentText(range, typedChar);
 
     setPosition(firstPositionInLine(beginLine));
@@ -3266,8 +3550,10 @@ int FakeVimHandler::Private::indentText(const Range &range, QChar typedChar)
 
     int amount = 0;
     // lineForPosition has returned 1-based line numbers
-    emit q->indentRegion(&amount, beginLine-1, endLine-1, typedChar);
-
+    emit q->indentRegion(&amount, beginLine - 1, endLine - 1, typedChar);
+    fixMarks(firstPositionInLine(beginLine), amount);
+    if (beginLine != endLine)
+        showBlackMessage("MARKS ARE OFF NOW");
     return amount;
 }
 
@@ -3313,7 +3599,7 @@ void FakeVimHandler::Private::shiftRegionLeft(int repeat)
     int targetPos = anchor();
     if (beginLine > endLine) {
         qSwap(beginLine, endLine);
-        targetPos = position(); 
+        targetPos = position();
     }
     const int shift = config(ConfigShiftWidth).toInt() * repeat;
     const int tab = config(ConfigTabStop).toInt();
@@ -3635,12 +3921,7 @@ int FakeVimHandler::Private::lastPositionInDocument() const
     return block.position() + block.length() - 1;
 }
 
-QString FakeVimHandler::Private::lastSearchString() const
-{
-     return m_searchHistory.empty() ? QString() : m_searchHistory.back();
-}
-
-QString FakeVimHandler::Private::text(const Range &range) const
+QString FakeVimHandler::Private::selectText(const Range &range) const
 {
     if (range.rangemode == RangeCharMode) {
         QTextCursor tc = m_tc;
@@ -3688,30 +3969,27 @@ QString FakeVimHandler::Private::text(const Range &range) const
     return contents;
 }
 
-void FakeVimHandler::Private::yankSelectedText()
-{
-    Range range(anchor(), position());
-    range.rangemode = m_rangemode;
-    yankText(range, m_register);
-}
-
 void FakeVimHandler::Private::yankText(const Range &range, int toregister)
 {
-    Register &reg = m_registers[toregister];
-    reg.contents = text(range);
+    Register &reg = g.registers[toregister];
+    reg.contents = selectText(range);
     reg.rangemode = range.rangemode;
     //qDebug() << "YANKED: " << reg.contents;
 }
 
 void FakeVimHandler::Private::transformText(const Range &range,
-    Transformation transformFunc)
+    Transformation transformFunc, const QVariant &extra)
 {
     QTextCursor tc = m_tc;
     switch (range.rangemode) {
         case RangeCharMode: {
             tc.setPosition(range.beginPos, MoveAnchor);
             tc.setPosition(range.endPos, KeepAnchor);
-            (this->*transformFunc)(range.beginPos, &tc);
+            TransformationData td(tc.selectedText(), extra);
+            (this->*transformFunc)(&td);
+            tc.removeSelectedText();
+            fixMarks(range.beginPos, td.to.size() - td.from.size());
+            tc.insertText(td.to);
             return;
         }
         case RangeLineMode:
@@ -3737,7 +4015,11 @@ void FakeVimHandler::Private::transformText(const Range &range,
                     tc.movePosition(Right, KeepAnchor, 1);
                 }
             }
-            (this->*transformFunc)(range.beginPos, &tc);
+            TransformationData td(tc.selectedText(), extra);
+            (this->*transformFunc)(&td);
+            tc.removeSelectedText();
+            fixMarks(range.beginPos, td.to.size() - td.from.size());
+            tc.insertText(td.to);
             return;
         }
         case RangeBlockAndTailMode:
@@ -3757,7 +4039,11 @@ void FakeVimHandler::Private::transformText(const Range &range,
                 int eCol = qMin(endColumn + 1, block.length() - 1);
                 tc.setPosition(block.position() + bCol, MoveAnchor);
                 tc.setPosition(block.position() + eCol, KeepAnchor);
-                (this->*transformFunc)(block.position() + bCol, &tc);
+                TransformationData td(tc.selectedText(), extra);
+                (this->*transformFunc)(&td);
+                tc.removeSelectedText();
+                fixMarks(block.position() + bCol, td.to.size() - td.from.size());
+                tc.insertText(td.to);
                 block = block.previous();
             }
             endEditBlock();
@@ -3765,11 +4051,12 @@ void FakeVimHandler::Private::transformText(const Range &range,
     }
 }
 
-void FakeVimHandler::Private::removeSelectedText()
+void FakeVimHandler::Private::insertText(const Register &reg)
 {
-    Range range(anchor(), position());
-    range.rangemode = m_rangemode;
-    removeText(range);
+    QTC_ASSERT(reg.rangemode == RangeCharMode,
+        qDebug() << "WRONG INSERT MODE: " << reg.rangemode; return);
+    fixMarks(position(), reg.contents.length());
+    m_tc.insertText(reg.contents);
 }
 
 void FakeVimHandler::Private::removeText(const Range &range)
@@ -3777,100 +4064,69 @@ void FakeVimHandler::Private::removeText(const Range &range)
     transformText(range, &FakeVimHandler::Private::removeTransform);
 }
 
-void FakeVimHandler::Private::removeTransform(int updateMarksAfter, QTextCursor *tc)
+void FakeVimHandler::Private::removeTransform(TransformationData *td)
 {
-    fixMarks(updateMarksAfter, tc->selectionStart() - tc->selectionEnd());
-    tc->removeSelectedText();
+    Q_UNUSED(td);
 }
 
-void FakeVimHandler::Private::downCaseSelectedText()
+void FakeVimHandler::Private::downCase(const Range &range)
 {
-    Range range(anchor(), position());
-    range.rangemode = m_rangemode;
     transformText(range, &FakeVimHandler::Private::downCaseTransform);
 }
 
-void FakeVimHandler::Private::downCaseTransform(int updateMarksAfter, QTextCursor *tc)
+void FakeVimHandler::Private::downCaseTransform(TransformationData *td)
 {
-    Q_UNUSED(updateMarksAfter);
-    QString str = tc->selectedText();
-    tc->removeSelectedText();
-    for (int i = str.size(); --i >= 0; ) {
-        QChar c = str.at(i);
-        str[i] = c.toLower();
-    }
-    tc->insertText(str);
+    td->to = td->from.toLower();
 }
 
-void FakeVimHandler::Private::upCaseSelectedText()
+void FakeVimHandler::Private::upCase(const Range &range)
 {
-    Range range(anchor(), position());
-    range.rangemode = m_rangemode;
     transformText(range, &FakeVimHandler::Private::upCaseTransform);
 }
 
-void FakeVimHandler::Private::upCaseTransform(int updateMarksAfter, QTextCursor *tc)
+void FakeVimHandler::Private::upCaseTransform(TransformationData *td)
 {
-    Q_UNUSED(updateMarksAfter);
-    QString str = tc->selectedText();
-    tc->removeSelectedText();
-    for (int i = str.size(); --i >= 0; ) {
-        QChar c = str.at(i);
-        str[i] = c.toUpper();
-    }
-    tc->insertText(str);
+    td->to = td->from.toUpper();
 }
 
-void FakeVimHandler::Private::invertCaseSelectedText()
+void FakeVimHandler::Private::invertCase(const Range &range)
 {
-    Range range(anchor(), position());
-    range.rangemode = m_rangemode;
     transformText(range, &FakeVimHandler::Private::invertCaseTransform);
 }
 
-void FakeVimHandler::Private::invertCaseTransform(int updateMarksAfter, QTextCursor *tc)
+void FakeVimHandler::Private::invertCaseTransform(TransformationData *td)
 {
-    Q_UNUSED(updateMarksAfter);
-    QString str = tc->selectedText();
-    tc->removeSelectedText();
-    for (int i = str.size(); --i >= 0; ) {
-        QChar c = str.at(i);
-        str[i] = c.isUpper() ? c.toLower() : c.toUpper();
-    }
-    tc->insertText(str);
+    foreach (QChar c, td->from)
+        td->to += c.isUpper() ? c.toLower() : c.toUpper();
 }
 
-void FakeVimHandler::Private::replaceSelectedText()
+void FakeVimHandler::Private::replaceText(const Range &range, const QString &str)
 {
-    Range range(anchor(), position());
-    range.rangemode = m_rangemode;
-    transformText(range, &FakeVimHandler::Private::replaceTransform);
+    transformText(range, &FakeVimHandler::Private::replaceTransform, str);
 }
 
-void FakeVimHandler::Private::replaceTransform(int updateMarksAfter, QTextCursor *tc)
+void FakeVimHandler::Private::replaceTransform(TransformationData *td)
 {
-    Q_UNUSED(updateMarksAfter);
-    QString str = tc->selectedText();
-    tc->removeSelectedText();
-    for (int i = str.size(); --i >= 0; ) {
-        QChar c = str.at(i);
-        str[i] = (c.toAscii() == '\n' || c.toAscii() == '\0') ? QChar('\n') : m_replacingCharacter;
+    for (int i = td->from.size(); --i >= 0; ) {
+        QChar c = td->from.at(i);
+        if (c.unicode() == '\n' || c.unicode() == '\0')
+            td->to += QLatin1Char('\n');
+        else
+            td->to += td->extraData.toString();
     }
-    tc->insertText(str);
 }
 
 void FakeVimHandler::Private::pasteText(bool afterCursor)
 {
-    const QString text = m_registers[m_register].contents;
+    const QString text = g.registers[m_register].contents;
     const QStringList lines = text.split(QChar('\n'));
-    switch (m_registers[m_register].rangemode) {
+    switch (g.registers[m_register].rangemode) {
         case RangeCharMode: {
             m_targetColumn = 0;
             for (int i = count(); --i >= 0; ) {
                 if (afterCursor && rightDist() > 0)
                     moveRight();
-                fixMarks(position(), text.length());
-                m_tc.insertText(text);
+                insertText(text);
                 if (!afterCursor && atEndOfLine())
                     moveLeft();
                 moveLeft();
@@ -3884,8 +4140,7 @@ void FakeVimHandler::Private::pasteText(bool afterCursor)
             for (int i = count(); --i >= 0; ) {
                 if (afterCursor)
                     moveDown();
-                fixMarks(position(), text.length());
-                m_tc.insertText(text);
+                insertText(text);
                 moveUp(lines.size() - 1);
             }
             moveToFirstNonBlankOnLine();
@@ -3910,8 +4165,8 @@ void FakeVimHandler::Private::pasteText(bool afterCursor)
                 } else {
                     tc.movePosition(Right, MoveAnchor, col - 1 + afterCursor);
                 }
-                qDebug() << "INSERT " << line << " AT " << tc.position()
-                    << "COL: " << col;
+                //qDebug() << "INSERT " << line << " AT " << tc.position()
+                //    << "COL: " << col;
                 fixMarks(position(), line.length());
                 tc.insertText(line);
                 tc.movePosition(StartOfLine, MoveAnchor);
@@ -3931,16 +4186,38 @@ void FakeVimHandler::Private::pasteText(bool afterCursor)
 }
 
 //FIXME: This needs to called after undo/insert
-void FakeVimHandler::Private::fixMarks(int positionAction, int positionChange)
-{
-    QHashIterator<int, int> i(m_marks);
-    while (i.hasNext()) {
-        i.next();
-        if (i.value() >= positionAction) {
-            if (i.value() + positionChange > 0)
-                m_marks[i.key()] = i.value() + positionChange;
-            else
-                m_marks.remove(i.key());
+// The position 'from' is the cursor position after the change. If 'delta'
+// is positive there was a string of size 'delta' inserted after 'from'
+// and consequently all marks beyond 'from + delta' need to be incremented
+// by 'delta'. If text was removed, 'delta' is negative. All marks between
+// 'from' and 'from - delta' need to be removed, everything behing
+// 'from - delta' adjusted by 'delta'.
+void FakeVimHandler::Private::fixMarks(int from, int delta)
+{
+    //qDebug() << "ADJUSTING MARKS FROM " << from << " BY " << delta;
+    if (delta == 0)
+        return;
+    QHashIterator<int, int> it(m_marks);
+    while (it.hasNext()) {
+        it.next();
+        int pos = it.value();
+        if (delta > 0) {
+            // Inserted text.
+            if (pos >= from) {
+                //qDebug() << "MODIFIED: " << it.key() << pos;
+                setMark(it.key(), pos + delta);
+            }
+        } else {
+            // Removed text.
+            if (pos < from) {
+                // Nothing to do.
+            } else if (pos < from - delta) {
+                //qDebug() << "GONE: " << it.key();
+                m_marks.remove(it.key());
+            } else {
+                //qDebug() << "MODIFIED: " << it.key() << pos;
+                setMark(it.key(), pos + delta);
+             }
         }
     }
 }
@@ -3950,13 +4227,14 @@ QString FakeVimHandler::Private::lineContents(int line) const
     return m_tc.document()->findBlockByNumber(line - 1).text();
 }
 
-void FakeVimHandler::Private::setLineContents(int line, const QString &contents) const
+void FakeVimHandler::Private::setLineContents(int line, const QString &contents)
 {
     QTextBlock block = m_tc.document()->findBlockByNumber(line - 1);
     QTextCursor tc = m_tc;
     tc.setPosition(block.position());
     tc.setPosition(block.position() + block.length() - 1, KeepAnchor);
     tc.removeSelectedText();
+    fixMarks(block.position(), block.length() - contents.size());
     tc.insertText(contents);
 }
 
@@ -3983,8 +4261,8 @@ void FakeVimHandler::Private::enterVisualMode(VisualMode visualMode)
     setAnchor();
     m_positionPastEnd = m_anchorPastEnd = false;
     m_visualMode = visualMode;
-    m_marks['<'] = m_tc.position();
-    m_marks['>'] = m_tc.position();
+    setMark('<', m_tc.position());
+    setMark('>', m_tc.position());
     updateMiniBuffer();
     updateSelection();
 }
@@ -4011,11 +4289,16 @@ QWidget *FakeVimHandler::Private::editor() const
 void FakeVimHandler::Private::undo()
 {
     //qDebug() << " CURSOR POS: " << m_undoCursorPosition;
-    int current = m_tc.document()->availableUndoSteps();
-    //endEditBlock();
+    QTextDocument *doc = m_tc.document();
+    // FIXME: That's only an approximaxtion. The real solution might
+    // be to store marks and old userData with QTextBlock setUserData
+    // and retrieve them afterward.
+    const int current = doc->availableUndoSteps();
+    const int oldCount = doc->characterCount();
     EDITOR(undo());
-    //beginEditBlock();
-    int rev = m_tc.document()->availableUndoSteps();
+    const int delta = doc->characterCount() - oldCount;
+    fixMarks(position(), delta);
+    const int rev = doc->availableUndoSteps();
     if (current == rev)
         showBlackMessage(FakeVimHandler::tr("Already at oldest change"));
     else
@@ -4023,17 +4306,20 @@ void FakeVimHandler::Private::undo()
 
     if (m_undoCursorPosition.contains(rev))
         m_tc.setPosition(m_undoCursorPosition[rev]);
+    setTargetColumn();
     if (atEndOfLine())
         moveLeft();
 }
 
 void FakeVimHandler::Private::redo()
 {
-    int current = m_tc.document()->availableUndoSteps();
-    //endEditBlock();
+    QTextDocument *doc = m_tc.document();
+    const int current = m_tc.document()->availableUndoSteps();
+    const int oldCount = doc->characterCount();
     EDITOR(redo());
-    //beginEditBlock();
-    int rev = m_tc.document()->availableUndoSteps();
+    const int delta = doc->characterCount() - oldCount;
+    fixMarks(position(), delta);
+    const int rev = doc->availableUndoSteps();
     if (rev == current)
         showBlackMessage(FakeVimHandler::tr("Already at newest change"));
     else
@@ -4041,32 +4327,63 @@ void FakeVimHandler::Private::redo()
 
     if (m_undoCursorPosition.contains(rev))
         m_tc.setPosition(m_undoCursorPosition[rev]);
+    setTargetColumn();
+}
+
+void FakeVimHandler::Private::updateCursor()
+{
+    if (m_mode == ExMode || m_subsubmode == SearchSubSubMode) {
+        EDITOR(setCursorWidth(0));
+        EDITOR(setOverwriteMode(false));
+    } else if (m_mode == InsertMode) {
+        EDITOR(setCursorWidth(m_cursorWidth));
+        EDITOR(setOverwriteMode(false));
+    } else {
+        EDITOR(setCursorWidth(m_cursorWidth));
+        EDITOR(setOverwriteMode(true));
+    }
+}
+
+void FakeVimHandler::Private::enterReplaceMode()
+{
+    m_mode = ReplaceMode;
+    m_submode = NoSubMode;
+    m_subsubmode = NoSubSubMode;
+    m_commandPrefix.clear();
+    m_lastInsertion.clear();
+    m_lastDeletion.clear();
+    updateCursor();
 }
 
 void FakeVimHandler::Private::enterInsertMode()
 {
-    EDITOR(setCursorWidth(m_cursorWidth));
-    EDITOR(setOverwriteMode(false));
-    //leaveVisualMode();
     m_mode = InsertMode;
+    m_submode = NoSubMode;
+    m_subsubmode = NoSubSubMode;
+    m_commandPrefix.clear();
     m_lastInsertion.clear();
-    m_beginEditBlock = true;
+    m_lastDeletion.clear();
+    updateCursor();
 }
 
 void FakeVimHandler::Private::enterCommandMode()
 {
-    EDITOR(setCursorWidth(m_cursorWidth));
-    EDITOR(setOverwriteMode(true));
     if (atEndOfLine())
         moveLeft();
     m_mode = CommandMode;
+    m_submode = NoSubMode;
+    m_subsubmode = NoSubSubMode;
+    m_commandPrefix.clear();
+    updateCursor();
 }
 
 void FakeVimHandler::Private::enterExMode()
 {
-    EDITOR(setCursorWidth(0));
-    EDITOR(setOverwriteMode(false));
     m_mode = ExMode;
+    m_submode = NoSubMode;
+    m_subsubmode = NoSubSubMode;
+    m_commandPrefix = ":";
+    updateCursor();
 }
 
 void FakeVimHandler::Private::recordJump()
@@ -4076,13 +4393,6 @@ void FakeVimHandler::Private::recordJump()
     UNDO_DEBUG("jumps: " << m_jumpListUndo);
 }
 
-void FakeVimHandler::Private::recordNewUndo()
-{
-    //endEditBlock();
-    UNDO_DEBUG("---- BREAK ----");
-    //beginEditBlock();
-}
-
 Column FakeVimHandler::Private::indentation(const QString &line) const
 {
     int ts = config(ConfigTabStop).toInt();
@@ -4128,7 +4438,7 @@ void FakeVimHandler::Private::insertAutomaticIndentation(bool goingDown)
             ++pos;
         text.truncate(pos);
         // FIXME: handle 'smartindent' and 'cindent'
-        m_tc.insertText(text);
+        insertText(text);
         m_justAutoIndented = text.size();
     }
 }
@@ -4139,6 +4449,7 @@ bool FakeVimHandler::Private::removeAutomaticIndentation()
         return false;
     m_tc.movePosition(StartOfLine, KeepAnchor);
     m_tc.removeSelectedText();
+    fixMarks(m_tc.position(), -m_justAutoIndented);
     m_lastInsertion.chop(m_justAutoIndented);
     m_justAutoIndented = 0;
     return true;
@@ -4152,18 +4463,17 @@ void FakeVimHandler::Private::handleStartOfLine()
 
 void FakeVimHandler::Private::replay(const QString &command, int n)
 {
-    //qDebug() << "REPLAY: " << command;
-    m_inReplay = true;
+    //qDebug() << "REPLAY: " << quoteUnprintable(command);
+    g.inReplay = true;
     for (int i = n; --i >= 0; ) {
         foreach (QChar c, command) {
             //qDebug() << "  REPLAY: " << QString(c);
             handleKey(Input(c));
         }
     }
-    m_inReplay = false;
+    g.inReplay = false;
 }
 
-
 void FakeVimHandler::Private::selectWordTextObject(bool inner)
 {
     Q_UNUSED(inner); // FIXME
@@ -4172,7 +4482,7 @@ void FakeVimHandler::Private::selectWordTextObject(bool inner)
     setAnchor();
     // FIXME: Rework the 'anchor' concept.
     if (isVisualMode())
-        m_marks['<'] = m_tc.position();
+        setMark('<', m_tc.position());
     moveToWordBoundary(false, true, true);
     m_movetype = MoveInclusive;
 }
@@ -4185,7 +4495,7 @@ void FakeVimHandler::Private::selectWORDTextObject(bool inner)
     setAnchor();
     // FIXME: Rework the 'anchor' concept.
     if (isVisualMode())
-        m_marks['<'] = m_tc.position();
+        setMark('<', m_tc.position());
     moveToWordBoundary(true, true, true);
     m_movetype = MoveInclusive;
 }
@@ -4213,6 +4523,18 @@ void FakeVimHandler::Private::selectQuotedStringTextObject(bool inner, int type)
     Q_UNUSED(type);
 }
 
+int FakeVimHandler::Private::mark(int code) const
+{
+    // FIXME: distinguish local and global marks.
+    //qDebug() << "MARK: " << code << m_marks.value(code, -1) << m_marks;
+    return m_marks.value(code, -1);
+}
+
+void FakeVimHandler::Private::setMark(int code, int position)
+{
+    // FIXME: distinguish local and global marks.
+    m_marks[code] = position;
+}
 
 ///////////////////////////////////////////////////////////////////////
 //
@@ -4240,6 +4562,30 @@ bool FakeVimHandler::eventFilter(QObject *ob, QEvent *ev)
 {
     bool active = theFakeVimSetting(ConfigUseFakeVim)->value().toBool();
 
+    // Catch mouse events on the viewport.
+    QWidget *viewport = 0;
+    if (d->m_plaintextedit)
+        viewport = d->m_plaintextedit->viewport();
+    else if (d->m_textedit)
+        viewport = d->m_textedit->viewport();
+    if (ob == viewport) {
+        if (active && ev->type() == QEvent::MouseButtonRelease) {
+            QMouseEvent *mev = static_cast<QMouseEvent *>(ev);
+            if (mev->button() == Qt::LeftButton) {
+                d->importSelection();
+                //return true;
+            }
+        }
+        if (active && ev->type() == QEvent::MouseButtonPress) {
+            QMouseEvent *mev = static_cast<QMouseEvent *>(ev);
+            if (mev->button() == Qt::LeftButton) {
+                d->m_visualMode = NoVisualMode;
+                d->updateSelection();
+            }
+        }
+        return QObject::eventFilter(ob, ev);
+    }
+
     if (active && ev->type() == QEvent::Shortcut) {
         d->passShortcuts(false);
         return false;
@@ -4314,6 +4660,11 @@ void FakeVimHandler::setCurrentFileName(const QString &fileName)
    d->m_currentFileName = fileName;
 }
 
+QString FakeVimHandler::currentFileName() const
+{
+    return d->m_currentFileName;
+}
+
 void FakeVimHandler::showBlackMessage(const QString &msg)
 {
    d->showBlackMessage(msg);
index 7543d8c..4e877d3 100644 (file)
 namespace FakeVim {
 namespace Internal {
 
+enum RangeMode
+{
+    RangeCharMode,         // v
+    RangeLineMode,         // V
+    RangeLineModeExclusive,
+    RangeBlockMode,        // Ctrl-v
+    RangeBlockAndTailMode, // Ctrl-v for D and X
+};
+
+struct Range
+{
+    Range();
+    Range(int b, int e, RangeMode m = RangeCharMode);
+    QString toString() const;
+
+    int beginPos;
+    int endPos;
+    RangeMode rangemode;
+};
+
+struct ExCommand
+{
+    ExCommand() : hasBang(false) {}
+    ExCommand(const QString &cmd, const QString &args = QString(),
+        const Range &range = Range());
+
+    QString cmd;
+    bool hasBang;
+    QString args;
+    Range range;
+};
+
 class FakeVimHandler : public QObject
 {
     Q_OBJECT
@@ -53,6 +85,8 @@ public:
 
 public slots:
     void setCurrentFileName(const QString &fileName);
+    QString currentFileName() const;
+
     void showBlackMessage(const QString &msg);
     void showRedMessage(const QString &msg);
 
@@ -76,8 +110,6 @@ signals:
     void statusDataChanged(const QString &msg);
     void extraInformationChanged(const QString &msg);
     void selectionChanged(const QList<QTextEdit::ExtraSelection> &selection);
-    void writeFileRequested(bool *handled,
-        const QString &fileName, const QString &contents);
     void writeAllRequested(QString *error);
     void moveToMatchingParenthesis(bool *moved, bool *forward, QTextCursor *cursor);
     void checkForElectricCharacter(bool *result, QChar c);
@@ -86,8 +118,7 @@ signals:
     void windowCommandRequested(int key);
     void findRequested(bool reverse);
     void findNextRequested(bool reverse);
-    void handleExCommandRequested(const QString &cmd);
-    void handleSetCommandRequested(bool *handled, const QString &cmd);
+    void handleExCommandRequested(bool *handled, const ExCommand &cmd);
 
 public:
     class Private;
@@ -101,4 +132,7 @@ private:
 } // namespace Internal
 } // namespace FakeVim
 
+Q_DECLARE_METATYPE(FakeVim::Internal::ExCommand);
+
+
 #endif // FAKEVIM_HANDLER_H
index 6a9f52b..450a862 100644 (file)
         </property>
        </widget>
       </item>
+      <item row="2" column="2">
+       <widget class="QCheckBox" name="checkBoxShowMarks">
+        <property name="text">
+         <string>Show position of text marks</string>
+        </property>
+       </widget>
+      </item>
       <item row="3" column="0" colspan="2">
        <widget class="QCheckBox" name="checkBoxSmartTab">
         <property name="text">
index a698cb0..eac4a65 100644 (file)
@@ -73,9 +73,9 @@
 #include <indenter.h>
 
 #include <QtCore/QDebug>
+#include <QtCore/QFile>
 #include <QtCore/QtPlugin>
 #include <QtCore/QObject>
-#include <QtCore/QPoint>
 #include <QtCore/QSettings>
 #include <QtCore/QTextStream>
 
@@ -120,6 +120,8 @@ const char * const CMD_FILE_PREV                  = "FakeVim.SwitchFilePrev";
 namespace FakeVim {
 namespace Internal {
 
+typedef QMap<QString, QRegExp> CommandMap;
+
 class FakeVimOptionPage : public Core::IOptionsPage
 {
     Q_OBJECT
@@ -168,6 +170,8 @@ QWidget *FakeVimOptionPage::createPage(QWidget *parent)
         m_ui.checkBoxHlSearch);
     m_group.insert(theFakeVimSetting(ConfigShiftWidth),
         m_ui.spinBoxShiftWidth);
+    m_group.insert(theFakeVimSetting(ConfigShowMarks),
+        m_ui.checkBoxShowMarks);
 
     m_group.insert(theFakeVimSetting(ConfigSmartTab),
         m_ui.checkBoxSmartTab);
@@ -199,8 +203,8 @@ QWidget *FakeVimOptionPage::createPage(QWidget *parent)
         QTextStream(&m_searchKeywords)
             << ' ' << m_ui.checkBoxAutoIndent->text()
             << ' ' << m_ui.checkBoxExpandTab->text()
+            << ' ' << m_ui.checkBoxShowMarks->text()
             << ' ' << m_ui.checkBoxSmartIndent->text()
-            << ' ' << m_ui.checkBoxExpandTab->text()
             << ' ' << m_ui.checkBoxHlSearch->text()
             << ' ' << m_ui.checkBoxIncSearch->text()
             << ' ' << m_ui.checkBoxSmartTab->text()
@@ -278,16 +282,12 @@ Q_DECLARE_METATYPE(CommandItem*);
 namespace FakeVim {
 namespace Internal {
 
-static QMap<QString, QRegExp> s_exCommandMap;
-static QMap<QString, QRegExp> s_defaultExCommandMap;
-
-
 class FakeVimExCommandsPage : public Core::CommandMappings
 {
     Q_OBJECT
 
 public:
-    FakeVimExCommandsPage() {}
+    FakeVimExCommandsPage(FakeVimPluginPrivate *q) : m_q(q) {}
 
     // IOptionsPage
     QString id() const { return QLatin1String(Constants::SETTINGS_EX_CMDS_ID); }
@@ -298,6 +298,8 @@ public:
 
     QWidget *createPage(QWidget *parent);
     void initialize();
+    CommandMap &exCommandMap();
+    CommandMap &defaultExCommandMap();
 
 public slots:
     void commandChanged(QTreeWidgetItem *current);
@@ -309,6 +311,7 @@ public slots:
 private:
     void setRegex(const QString &regex);
     QList<CommandItem *> m_citems;
+    FakeVimPluginPrivate *m_q;
 };
 
 QWidget *FakeVimExCommandsPage::createPage(QWidget *parent)
@@ -341,15 +344,16 @@ void FakeVimExCommandsPage::initialize()
         QTreeWidgetItem *item = new QTreeWidgetItem;
         ci->m_cmd = c;
         ci->m_item = item;
-        m_citems << ci;
+        m_citems.append(ci);
 
         const QString name = uidm->stringForUniqueIdentifier(c->id());
         const int pos = name.indexOf(QLatin1Char('.'));
         const QString section = name.left(pos);
-        const QString subId = name.mid(pos+1);
+        const QString subId = name.mid(pos + 1);
 
         if (!sections.contains(section)) {
-            QTreeWidgetItem *categoryItem = new QTreeWidgetItem(commandList(), QStringList() << section);
+            QTreeWidgetItem *categoryItem =
+                new QTreeWidgetItem(commandList(), QStringList() << section);
             QFont f = categoryItem->font(0);
             f.setBold(true);
             categoryItem->setFont(0, f);
@@ -361,14 +365,16 @@ void FakeVimExCommandsPage::initialize()
         item->setText(0, subId);
 
         if (c->action()) {
-            QString text = c->hasAttribute(Command::CA_UpdateText) && !c->defaultText().isNull() ? c->defaultText() : c->action()->text();
+            QString text = c->hasAttribute(Command::CA_UpdateText)
+                    && !c->defaultText().isNull()
+                ? c->defaultText() : c->action()->text();
             text.remove(QRegExp("&(?!&)"));
             item->setText(1, text);
         } else {
             item->setText(1, c->shortcut()->whatsThis());
         }
-        if (s_exCommandMap.contains(name)) {
-            ci->m_regex = s_exCommandMap[name].pattern();
+        if (exCommandMap().contains(name)) {
+            ci->m_regex = exCommandMap()[name].pattern();
         } else {
             ci->m_regex.clear();
         }
@@ -376,7 +382,7 @@ void FakeVimExCommandsPage::initialize()
         item->setText(2, ci->m_regex);
         item->setData(0, Qt::UserRole, qVariantFromValue(ci));
 
-        if (ci->m_regex != s_defaultExCommandMap[name].pattern())
+        if (ci->m_regex != defaultExCommandMap()[name].pattern())
             setModified(item, true);
     }
 
@@ -407,10 +413,10 @@ void FakeVimExCommandsPage::targetIdentifierChanged()
     if (current->data(0, Qt::UserRole).isValid()) {
         citem->m_regex = targetEdit()->text();
         current->setText(2, citem->m_regex);
-        s_exCommandMap[name] = QRegExp(citem->m_regex);
+        exCommandMap()[name] = QRegExp(citem->m_regex);
     }
 
-    if (citem->m_regex != s_defaultExCommandMap[name].pattern())
+    if (citem->m_regex != defaultExCommandMap()[name].pattern())
         setModified(current, true);
     else
         setModified(current, false);
@@ -429,8 +435,8 @@ void FakeVimExCommandsPage::resetTargetIdentifier()
     if (current && current->data(0, Qt::UserRole).isValid()) {
         CommandItem *citem = qVariantValue<CommandItem *>(current->data(0, Qt::UserRole));
         const QString &name = uidm->stringForUniqueIdentifier(citem->m_cmd->id());
-        if (s_defaultExCommandMap.contains(name))
-            setRegex(s_defaultExCommandMap[name].pattern());
+        if (defaultExCommandMap().contains(name))
+            setRegex(defaultExCommandMap()[name].pattern());
         else
             setRegex(QString());
     }
@@ -446,8 +452,8 @@ void FakeVimExCommandsPage::defaultAction()
     UniqueIDManager *uidm = UniqueIDManager::instance();
     foreach (CommandItem *item, m_citems) {
         const QString &name = uidm->stringForUniqueIdentifier(item->m_cmd->id());
-        if (s_defaultExCommandMap.contains(name)) {
-            item->m_regex = s_defaultExCommandMap[name].pattern();
+        if (defaultExCommandMap().contains(name)) {
+            item->m_regex = defaultExCommandMap()[name].pattern();
         } else {
             item->m_regex.clear();
         }
@@ -479,6 +485,7 @@ public:
     FakeVimPluginPrivate(FakeVimPlugin *);
     ~FakeVimPluginPrivate();
     friend class FakeVimPlugin;
+    friend class FakeVimExCommandsPage;
 
     bool initialize();
     void aboutToShutdown();
@@ -499,12 +506,10 @@ private slots:
     void showCommandBuffer(const QString &contents);
     void showExtraInformation(const QString &msg);
     void changeSelection(const QList<QTextEdit::ExtraSelection> &selections);
-    void writeFile(bool *handled, const QString &fileName, const QString &contents);
     void moveToMatchingParenthesis(bool *moved, bool *forward, QTextCursor *cursor);
     void checkForElectricCharacter(bool *result, QChar c);
     void indentRegion(int *amount, int beginLine, int endLine,  QChar typedChar);
-    void handleExCommand(const QString &cmd);
-    void handleSetCommand(bool *handled, QString cmd);
+    void handleExCommand(bool *handled, const ExCommand &cmd);
 
     void handleDelayedQuitAll(bool forced);
     void handleDelayedQuit(bool forced, Core::IEditor *editor);
@@ -523,11 +528,16 @@ private:
     FakeVimExCommandsPage *m_fakeVimExCommandsPage;
     QHash<Core::IEditor *, FakeVimHandler *> m_editorToHandler;
 
-    void triggerAction(const QStringcode);
-    void setActionChecked(const QStringcode, bool check);
+    void triggerAction(const QString &code);
+    void setActionChecked(const QString &code, bool check);
 
     void readSettings(QSettings *settings);
     void writeSettings(QSettings *settings);
+
+    CommandMap &exCommandMap() { return m_exCommandMap; }
+    CommandMap &defaultExCommandMap() { return m_exCommandMap; }
+    CommandMap m_exCommandMap;
+    CommandMap m_defaultExCommandMap;
 };
 
 } // namespace Internal
@@ -538,23 +548,22 @@ FakeVimPluginPrivate::FakeVimPluginPrivate(FakeVimPlugin *plugin)
     q = plugin;
     m_fakeVimOptionsPage = 0;
     m_fakeVimExCommandsPage = 0;
-
-    s_defaultExCommandMap[Constants::CMD_FILE_NEXT] =
+    defaultExCommandMap()[Constants::CMD_FILE_NEXT] =
         QRegExp("^n(ext)?!?( (.*))?$");
-    s_defaultExCommandMap[Constants::CMD_FILE_PREV] =
+    defaultExCommandMap()[Constants::CMD_FILE_PREV] =
         QRegExp("^(N(ext)?|prev(ious)?)!?( (.*))?$");
-    s_defaultExCommandMap[CppTools::Constants::SWITCH_HEADER_SOURCE] =
+    defaultExCommandMap()[CppTools::Constants::SWITCH_HEADER_SOURCE] =
         QRegExp("^A$");
-    s_defaultExCommandMap[ProjectExplorer::Constants::BUILD] =
-        QRegExp("^make$");
-    s_defaultExCommandMap["Coreplugin.OutputPane.previtem"] =
+    defaultExCommandMap()["Coreplugin.OutputPane.previtem"] =
         QRegExp("^(cN(ext)?|cp(revious)?)!?( (.*))?$");
-    s_defaultExCommandMap["Coreplugin.OutputPane.nextitem"] =
+    defaultExCommandMap()["Coreplugin.OutputPane.nextitem"] =
         QRegExp("^cn(ext)?!?( (.*))?$");
-    s_defaultExCommandMap[CppEditor::Constants::JUMP_TO_DEFINITION] =
+    defaultExCommandMap()[CppEditor::Constants::JUMP_TO_DEFINITION] =
         QRegExp("^tag?$");
-    s_defaultExCommandMap[Core::Constants::GO_BACK] =
+    defaultExCommandMap()[Core::Constants::GO_BACK] =
         QRegExp("^pop?$");
+    defaultExCommandMap()[QLatin1String("QtCreator.Locate")] =
+        QRegExp("^e$");
 }
 
 FakeVimPluginPrivate::~FakeVimPluginPrivate()
@@ -587,7 +596,7 @@ bool FakeVimPluginPrivate::initialize()
     q->addObject(m_fakeVimOptionsPage);
     theFakeVimSettings()->readSettings(Core::ICore::instance()->settings());
 
-    m_fakeVimExCommandsPage = new FakeVimExCommandsPage;
+    m_fakeVimExCommandsPage = new FakeVimExCommandsPage(this);
     q->addObject(m_fakeVimExCommandsPage);
     readSettings(Core::ICore::instance()->settings());
 
@@ -607,8 +616,6 @@ bool FakeVimPluginPrivate::initialize()
     connect(editorManager, SIGNAL(editorOpened(Core::IEditor*)),
         this, SLOT(editorOpened(Core::IEditor*)));
 
-    connect(theFakeVimSetting(SettingsDialog), SIGNAL(triggered()),
-        this, SLOT(showSettingsDialog()));
     connect(theFakeVimSetting(ConfigUseFakeVim), SIGNAL(valueChanged(QVariant)),
         this, SLOT(setUseFakeVim(QVariant)));
     connect(theFakeVimSetting(ConfigReadVimRc), SIGNAL(valueChanged(QVariant)),
@@ -624,7 +631,7 @@ bool FakeVimPluginPrivate::initialize()
     cmd->setAttribute(Command::CA_Hide);
     connect(switchFilePrevAction, SIGNAL(triggered()), this, SLOT(switchFilePrev()));
 
-    // Delayed operatiosn
+    // Delayed operations.
     connect(this, SIGNAL(delayedQuitRequested(bool,Core::IEditor*)),
         this, SLOT(handleDelayedQuit(bool,Core::IEditor*)), Qt::QueuedConnection);
     connect(this, SIGNAL(delayedQuitAllRequested(bool)),
@@ -644,14 +651,14 @@ void FakeVimPluginPrivate::writeSettings(QSettings *settings)
     settings->beginWriteArray(QLatin1String(exCommandMapGroup));
 
     int count = 0;
-    typedef QMap<QString, QRegExp>::const_iterator Iterator;
-    const Iterator end = s_exCommandMap.constEnd();
-    for (Iterator it = s_exCommandMap.constBegin(); it != end; ++it) {
+    typedef CommandMap::const_iterator Iterator;
+    const Iterator end = exCommandMap().constEnd();
+    for (Iterator it = exCommandMap().constBegin(); it != end; ++it) {
         const QString &id = it.key();
         const QRegExp &re = it.value();
 
-        if ((s_defaultExCommandMap.contains(id) && s_defaultExCommandMap[id] != re)
-            || (!s_defaultExCommandMap.contains(id) && !re.pattern().isEmpty())) {
+        if ((defaultExCommandMap().contains(id) && defaultExCommandMap()[id] != re)
+            || (!defaultExCommandMap().contains(id) && !re.pattern().isEmpty())) {
             settings->setArrayIndex(count);
             settings->setValue(QLatin1String(idKey), id);
             settings->setValue(QLatin1String(reKey), re.pattern());
@@ -664,14 +671,14 @@ void FakeVimPluginPrivate::writeSettings(QSettings *settings)
 
 void FakeVimPluginPrivate::readSettings(QSettings *settings)
 {
-    s_exCommandMap = s_defaultExCommandMap;
+    exCommandMap() = defaultExCommandMap();
 
     int size = settings->beginReadArray(QLatin1String(exCommandMapGroup));
     for (int i = 0; i < size; ++i) {
         settings->setArrayIndex(i);
         const QString id = settings->value(QLatin1String(idKey)).toString();
         const QString re = settings->value(QLatin1String(reKey)).toString();
-        s_exCommandMap[id] = QRegExp(re);
+        exCommandMap()[id] = QRegExp(re);
     }
     settings->endArray();
 }
@@ -702,18 +709,18 @@ void FakeVimPluginPrivate::showSettingsDialog()
         QLatin1String(Constants::SETTINGS_ID));
 }
 
-void FakeVimPluginPrivate::triggerAction(const QStringcode)
+void FakeVimPluginPrivate::triggerAction(const QString &code)
 {
     Core::ActionManager *am = Core::ICore::instance()->actionManager();
     QTC_ASSERT(am, return);
     Core::Command *cmd = am->command(code);
-    QTC_ASSERT(cmd, return);
+    QTC_ASSERT(cmd, qDebug() << "UNKNOW CODE: " << code; return);
     QAction *action = cmd->action();
     QTC_ASSERT(action, return);
     action->trigger();
 }
 
-void FakeVimPluginPrivate::setActionChecked(const QStringcode, bool check)
+void FakeVimPluginPrivate::setActionChecked(const QString &code, bool check)
 {
     Core::ActionManager *am = Core::ICore::instance()->actionManager();
     QTC_ASSERT(am, return);
@@ -826,8 +833,6 @@ void FakeVimPluginPrivate::editorOpened(Core::IEditor *editor)
         this, SLOT(showExtraInformation(QString)));
     connect(handler, SIGNAL(commandBufferChanged(QString)),
         this, SLOT(showCommandBuffer(QString)));
-    connect(handler, SIGNAL(writeFileRequested(bool*,QString,QString)),
-        this, SLOT(writeFile(bool*,QString,QString)));
     connect(handler, SIGNAL(selectionChanged(QList<QTextEdit::ExtraSelection>)),
         this, SLOT(changeSelection(QList<QTextEdit::ExtraSelection>)));
     connect(handler, SIGNAL(moveToMatchingParenthesis(bool*,bool*,QTextCursor*)),
@@ -845,10 +850,8 @@ void FakeVimPluginPrivate::editorOpened(Core::IEditor *editor)
     connect(handler, SIGNAL(findNextRequested(bool)),
         this, SLOT(findNext(bool)));
 
-    connect(handler, SIGNAL(handleExCommandRequested(QString)),
-        this, SLOT(handleExCommand(QString)));
-    connect(handler, SIGNAL(handleSetCommandRequested(bool *,QString)),
-        this, SLOT(handleSetCommand(bool *,QString)));
+    connect(handler, SIGNAL(handleExCommandRequested(bool*,ExCommand)),
+        this, SLOT(handleExCommand(bool*,ExCommand)));
 
     handler->setCurrentFileName(editor->file()->fileName());
     handler->installEventFilter();
@@ -909,33 +912,12 @@ void FakeVimPluginPrivate::checkForElectricCharacter(bool *result, QChar c)
         *result = bt->isElectricCharacter(c);
 }
 
-void FakeVimPluginPrivate::writeFile(bool *handled,
-    const QString &fileName, const QString &contents)
+void FakeVimPluginPrivate::handleExCommand(bool *handled, const ExCommand &cmd)
 {
-    Q_UNUSED(contents)
-
-    FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
-    if (!handler)
-        return;
-
-    Core::IEditor *editor = m_editorToHandler.key(handler);
-    if (editor && editor->file()->fileName() == fileName) {
-        // Handle that as a special case for nicer interaction with core
-        Core::IFile *file = editor->file();
-        Core::ICore::instance()->fileManager()->blockFileChange(file);
-        file->save(fileName);
-        Core::ICore::instance()->fileManager()->unblockFileChange(file);
-        *handled = true;
-    }
-}
-
-void FakeVimPluginPrivate::handleExCommand(const QString &cmd)
-{
-    static QRegExp reWriteAll("^wa(ll)?!?$");
-    static QRegExp reQuit("^q!?$");
-    static QRegExp reQuitAll("^qa!?$");
-
     using namespace Core;
+    //qDebug() << "PLUGIN HANDLE: " << cmd.cmd;
+
+    *handled = false;
 
     FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
     if (!handler)
@@ -944,7 +926,27 @@ void FakeVimPluginPrivate::handleExCommand(const QString &cmd)
     EditorManager *editorManager = EditorManager::instance();
     QTC_ASSERT(editorManager, return);
 
-    if (reWriteAll.indexIn(cmd) != -1) {
+    *handled = true;
+    if (cmd.cmd == "w" || cmd.cmd == "write") {
+        Core::IEditor *editor = m_editorToHandler.key(handler);
+        const QString fileName = handler->currentFileName();
+        if (editor && editor->file()->fileName() == fileName) {
+            // Handle that as a special case for nicer interaction with core
+            Core::IFile *file = editor->file();
+            Core::ICore::instance()->fileManager()->blockFileChange(file);
+            file->save(fileName);
+            Core::ICore::instance()->fileManager()->unblockFileChange(file);
+            // Check result by reading back.
+            QFile file3(fileName);
+            file3.open(QIODevice::ReadOnly);
+            QByteArray ba = file3.readAll();
+            handler->showBlackMessage(FakeVimHandler::tr("\"%1\" %2 %3L, %4C written")
+                .arg(fileName).arg(" ")
+                .arg(ba.count('\n')).arg(ba.size()));
+        } else {
+            handler->showRedMessage(tr("File not saved"));
+        }
+    } else if (cmd.cmd == "wa" || cmd.cmd == "wall") {
         // :wa
         FileManager *fm = ICore::instance()->fileManager();
         QList<IFile *> toSave = fm->modifiedFiles();
@@ -953,43 +955,47 @@ void FakeVimPluginPrivate::handleExCommand(const QString &cmd)
             handler->showBlackMessage(tr("Saving succeeded"));
         else
             handler->showRedMessage(tr("%n files not saved", 0, failed.size()));
-    } else if (reQuit.indexIn(cmd) != -1) {
-        // :q
-        bool forced = cmd.contains(QChar('!'));
-        emit delayedQuitRequested(forced, m_editorToHandler.key(handler));
-    } else if (reQuitAll.indexIn(cmd) != -1) {
+    } else if (cmd.cmd == "q" || cmd.cmd == "quit") {
+        // :q[uit]
+        emit delayedQuitRequested(cmd.hasBang, m_editorToHandler.key(handler));
+    } else if (cmd.cmd == "qa" || cmd.cmd == "qall") {
         // :qa
-        bool forced = cmd.contains(QChar('!'));
-        emit delayedQuitAllRequested(forced);
+        emit delayedQuitAllRequested(cmd.hasBang);
+    } else if (cmd.cmd == "sp" || cmd.cmd == "split") {
+        // :sp[lit]
+        triggerAction(Core::Constants::SPLIT);
+    } else if (cmd.cmd == "vs" || cmd.cmd == "vsplit") {
+        // :vs[plit]
+        triggerAction(Core::Constants::SPLIT_SIDE_BY_SIDE);
+    } else if (cmd.cmd == "mak" || cmd.cmd == "make") {
+        // :mak[e][!] [arguments]
+        triggerAction(ProjectExplorer::Constants::BUILD);
+    } else if (cmd.cmd == "se" || cmd.cmd == "set") {
+        if (cmd.args.isEmpty()) {
+            // :set
+            showSettingsDialog();
+        } else if (cmd.args == "ic" || cmd.args == "ignorecase") {
+            // :set noic
+            setActionChecked(Find::Constants::CASE_SENSITIVE, false);
+            *handled = false; // Let the handler see it as well.
+        } else if (cmd.args == "noic" || cmd.args == "noignorecase") {
+            // :set noic
+            setActionChecked(Find::Constants::CASE_SENSITIVE, true);
+            *handled = false; // Let the handler see it as well.
+        }
     } else {
-        typedef QMap<QString, QRegExp>::const_iterator Iterator;
-        const Iterator end = s_exCommandMap.constEnd();
-        for (Iterator it = s_exCommandMap.constBegin(); it != end; ++it) {
+        // Check whether one of the configure commands matches.
+        typedef CommandMap::const_iterator Iterator;
+        const Iterator end = exCommandMap().constEnd();
+        for (Iterator it = exCommandMap().constBegin(); it != end; ++it) {
             const QString &id = it.key();
             const QRegExp &re = it.value();
-
-            if (!re.pattern().isEmpty() && re.indexIn(cmd) != -1) {
+            if (!re.pattern().isEmpty() && re.indexIn(cmd.cmd) != -1) {
                 triggerAction(id);
                 return;
             }
         }
-
-        handler->showRedMessage(tr("Not an editor command: %1").arg(cmd));
-    }
-}
-
-void FakeVimPluginPrivate::handleSetCommand(bool *handled, QString cmd)
-{
-    *handled = false;
-    bool value = true;
-    if (cmd.startsWith("no")) {
-        value = false;
-        cmd = cmd.mid(2);
-    }
-
-    if (cmd == "ic" || cmd == "ignorecase") {
-        setActionChecked(Find::Constants::CASE_SENSITIVE, value);
-        *handled = true;
+        *handled = false;
     }
 }
 
@@ -1130,6 +1136,17 @@ void FakeVimPluginPrivate::switchFilePrev()
     switchFile(true);
 }
 
+CommandMap &FakeVimExCommandsPage::exCommandMap()
+{
+    return m_q->exCommandMap();
+}
+
+CommandMap &FakeVimExCommandsPage::defaultExCommandMap()
+{
+    return m_q->defaultExCommandMap();
+}
+
+
 ///////////////////////////////////////////////////////////////////////
 //
 // FakeVimPlugin
index 22f29ad..bcf92e7 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="Find" version="1.3.84" compatVersion="1.3.84">
+<plugin name="Find" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,6 +14,6 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Provides the find widget and the hooks for find implementations.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="Core" version="1.3.84"/>
+        <dependency name="Core" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 0ca72b8..18c625b 100644 (file)
@@ -240,7 +240,6 @@ void CurrentDocumentFind::aggregationChanged()
             }
             else {
                 clearFindSupport();
-                m_currentFind = 0;
             }
         }
     }
@@ -248,7 +247,7 @@ void CurrentDocumentFind::aggregationChanged()
 
 void CurrentDocumentFind::candidateAggregationChanged()
 {
-    if (m_candidateWidget && m_candidateWidget!=m_currentWidget) {
+    if (m_candidateWidget && m_candidateWidget != m_currentWidget) {
         m_candidateFind = Aggregation::query<IFindSupport>(m_candidateWidget);
         emit candidateChanged();
     }
index c279e46..3667a23 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="GenericProjectManager" version="1.3.84" compatVersion="1.3.84">
+<plugin name="GenericProjectManager" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,9 +14,9 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Generic support</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="TextEditor" version="1.3.84"/>
-        <dependency name="ProjectExplorer" version="1.3.84"/>
-        <dependency name="CppTools" version="1.3.84"/>
-        <dependency name="CppEditor" version="1.3.84"/>
+        <dependency name="TextEditor" version="2.0.80"/>
+        <dependency name="ProjectExplorer" version="2.0.80"/>
+        <dependency name="CppTools" version="2.0.80"/>
+        <dependency name="CppEditor" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 1fa74df..ef22438 100644 (file)
@@ -591,6 +591,13 @@ bool GenericProjectFile::isSaveAsAllowed() const
     return false;
 }
 
+void GenericProjectFile::rename(const QString &newName)
+{
+    // Can't happen
+    Q_UNUSED(newName);
+    Q_ASSERT(false);
+}
+
 Core::IFile::ReloadBehavior GenericProjectFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
 {
     Q_UNUSED(state)
index 8e7b0bd..d912192 100644 (file)
@@ -161,6 +161,7 @@ public:
     virtual bool isModified() const;
     virtual bool isReadOnly() const;
     virtual bool isSaveAsAllowed() const;
+    virtual void rename(const QString &newName);
 
     ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
     void reload(ReloadFlag flag, ChangeType type);
index 2a2397e..26b1593 100644 (file)
@@ -170,8 +170,9 @@ bool GenericProjectNode::hasBuildTargets() const
     return true;
 }
 
-QList<ProjectExplorer::ProjectNode::ProjectAction> GenericProjectNode::supportedActions() const
+QList<ProjectExplorer::ProjectNode::ProjectAction> GenericProjectNode::supportedActions(Node *node) const
 {
+    Q_UNUSED(node);
     return QList<ProjectAction>()
         << AddFile
         << RemoveFile;
index 272785d..39859a8 100644 (file)
@@ -55,7 +55,7 @@ public:
 
     virtual bool hasBuildTargets() const;
 
-    virtual QList<ProjectExplorer::ProjectNode::ProjectAction> supportedActions() const;
+    virtual QList<ProjectExplorer::ProjectNode::ProjectAction> supportedActions(Node *node) const;
 
     virtual bool addSubProjects(const QStringList &proFilePaths);
     virtual bool removeSubProjects(const QStringList &proFilePaths);
index be3b659..0d6b2f1 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="ScmGit" version="1.3.84" compatVersion="1.3.84">
+<plugin name="ScmGit" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,9 +14,9 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Git integration.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="TextEditor" version="1.3.84"/>
-        <dependency name="ProjectExplorer" version="1.3.84"/>
-        <dependency name="Core" version="1.3.84"/>
-        <dependency name="VCSBase" version="1.3.84"/>
+        <dependency name="TextEditor" version="2.0.80"/>
+        <dependency name="ProjectExplorer" version="2.0.80"/>
+        <dependency name="Core" version="2.0.80"/>
+        <dependency name="VCSBase" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 15e12d4..d613a60 100644 (file)
@@ -522,6 +522,27 @@ bool GitClient::synchronousDelete(const QString &workingDirectory,
     return rc;
 }
 
+bool GitClient::synchronousMove(const QString &workingDirectory,
+                                const QString &from,
+                                const QString &to)
+{
+    if (Git::Constants::debug)
+        qDebug() << Q_FUNC_INFO << workingDirectory << from << to;
+    QByteArray outputText;
+    QByteArray errorText;
+    QStringList arguments;
+    arguments << QLatin1String("mv");
+    arguments << (from);
+    arguments << (to);
+    const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText);
+    if (!rc) {
+        const QString errorMessage = tr("Unable to move from %1 to %2: %3").
+                                     arg(from, to, commandOutputFromLocal8Bit(errorText));
+        outputWindow()->appendError(errorMessage);
+    }
+    return rc;
+}
+
 bool GitClient::synchronousReset(const QString &workingDirectory,
                                  const QStringList &files,
                                  QString *errorMessage)
index 3d65928..26423fc 100644 (file)
@@ -98,6 +98,9 @@ public:
     bool synchronousDelete(const QString &workingDirectory,
                            bool force,
                            const QStringList &files);
+    bool synchronousMove(const QString &workingDirectory,
+                         const QString &from,
+                         const QString &to);
     bool synchronousReset(const QString &workingDirectory,
                           const QStringList &files = QStringList(),
                           QString *errorMessage = 0);
index 07ff952..370e20b 100644 (file)
@@ -75,6 +75,9 @@ bool GitVersionControl::supportsOperation(Operation operation) const
     case DeleteOperation:
         rc = true;
         break;
+    case MoveOperation:
+        rc = true;
+        break;
     case OpenOperation:
         break;
     case CreateRepositoryOperation:
@@ -107,6 +110,13 @@ bool GitVersionControl::vcsDelete(const QString & fileName)
     return gitClient()->synchronousDelete(fi.absolutePath(), true, QStringList(fi.fileName()));
 }
 
+bool GitVersionControl::vcsMove(const QString &from, const QString &to)
+{
+    const QFileInfo fromInfo(from);
+    const QFileInfo toInfo(to);
+    return gitClient()->synchronousMove(fromInfo.absolutePath(), fromInfo.absoluteFilePath(), toInfo.absoluteFilePath());
+}
+
 bool GitVersionControl::vcsCreateRepository(const QString &directory)
 {
     return gitClient()->synchronousInit(directory);
@@ -196,14 +206,12 @@ bool GitVersionControl::vcsRemoveSnapshot(const QString &topLevel, const QString
             && gitClient()->synchronousStashRemove(topLevel, stashName);
 }
 
-bool GitVersionControl::managesDirectory(const QString &directory) const
-{
-    return !GitClient::findRepositoryForDirectory(directory).isEmpty();
-}
-
-QString GitVersionControl::findTopLevelForDirectory(const QString &directory) const
+bool GitVersionControl::managesDirectory(const QString &directory, QString *topLevel) const
 {
-    return GitClient::findRepositoryForDirectory(directory);
+    const QString topLevelFound = GitClient::findRepositoryForDirectory(directory);
+    if (topLevel)
+        *topLevel = topLevelFound;
+    return !topLevelFound.isEmpty();
 }
 
 bool GitVersionControl::vcsAnnotate(const QString &file, int line)
index c53c1f2..3550474 100644 (file)
@@ -46,13 +46,13 @@ public:
 
     virtual QString displayName() const;
 
-    bool managesDirectory(const QString &directory) const;
-    virtual QString findTopLevelForDirectory(const QString &directory) const;
+    virtual bool managesDirectory(const QString &directory, QString *topLevel) const;
 
     virtual bool supportsOperation(Operation operation) const;
     virtual bool vcsOpen(const QString &fileName);
     virtual bool vcsAdd(const QString &fileName);
     virtual bool vcsDelete(const QString &filename);
+    virtual bool vcsMove(const QString &from, const QString &to);
     virtual bool vcsCreateRepository(const QString &directory);
     virtual QString vcsCreateSnapshot(const QString &topLevel);
     virtual QStringList vcsSnapshots(const QString &topLevel);
index cf2a4d2..7b435e7 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="HelloWorld" version="1.3.84" compatVersion="1.3.84">
+<plugin name="HelloWorld" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -13,6 +13,6 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Hello World sample plugin.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="Core" version="1.3.84"/>
+        <dependency name="Core" version="2.0.80"/>
     </dependencyList>
 </plugin>
index d8b9d4b..f2058be 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="Help" version="1.3.84" compatVersion="1.3.84">
+<plugin name="Help" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,8 +14,8 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Help system.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="Core" version="1.3.84"/>
-        <dependency name="Find" version="1.3.84"/>
-        <dependency name="Locator" version="1.3.84"/>
+        <dependency name="Core" version="2.0.80"/>
+        <dependency name="Find" version="2.0.80"/>
+        <dependency name="Locator" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 95fe434..47c683e 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="Locator" version="1.3.84" compatVersion="1.3.84">
+<plugin name="Locator" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,6 +14,6 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Provides the Locator widget and the hooks for Locator filter implementations.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="Core" version="1.3.84"/>
+        <dependency name="Core" version="2.0.80"/>
     </dependencyList>
 </plugin>
index f1cf1dd..b3c1968 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="Mercurial" version="1.3.84" compatVersion="1.3.84">
+<plugin name="Mercurial" version="2.0.80" compatVersion="2.0.80">
     <vendor>Brian McGillion</vendor>
     <copyright>(C) 2008-2009 Brian McGillion</copyright>
     <license>
@@ -14,9 +14,9 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Mercurial integration.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="TextEditor" version="1.3.84"/>
-        <dependency name="ProjectExplorer" version="1.3.84"/>
-        <dependency name="Core" version="1.3.84"/>
-        <dependency name="VCSBase" version="1.3.84"/>
+        <dependency name="TextEditor" version="2.0.80"/>
+        <dependency name="ProjectExplorer" version="2.0.80"/>
+        <dependency name="Core" version="2.0.80"/>
+        <dependency name="VCSBase" version="2.0.80"/>
     </dependencyList>
 </plugin>
index caf4f0b..ff78f0d 100644 (file)
@@ -95,6 +95,14 @@ bool MercurialClient::remove(const QString &workingDir, const QString &filename)
     return executeHgSynchronously(workingDir, args, &stdOut);
 }
 
+bool MercurialClient::move(const QString &workingDir, const QString &from, const QString &to)
+{
+    QStringList args;
+    args << QLatin1String("rename") << from << to;
+    QByteArray stdOut;
+    return executeHgSynchronously(workingDir, args, &stdOut);
+}
+
 bool MercurialClient::manifestSync(const QString &repository, const QString &relativeFilename)
 {
     // This  only works when called from the repo and outputs paths relative to it.
index 9e0daab..215b24f 100644 (file)
@@ -62,6 +62,7 @@ public:
     ~MercurialClient();
     bool add(const QString &workingDir, const QString &fileName);
     bool remove(const QString &workingDir, const QString &fileName);
+    bool move(const QString &workingDir, const QString &from, const QString &to);
     bool manifestSync(const QString &repository, const QString &filename);
     QString branchQuerySync(const QString &repositoryRoot);
     bool parentRevisionsSync(const QString &workingDirectory,
index 1b707b9..61342dc 100644 (file)
@@ -47,16 +47,13 @@ QString MercurialControl::displayName() const
     return tr("Mercurial");
 }
 
-bool MercurialControl::managesDirectory(const QString &directory) const
+bool MercurialControl::managesDirectory(const QString &directory, QString *topLevel) const
 {
     QFileInfo dir(directory);
-    return !mercurialClient->findTopLevelForFile(dir).isEmpty();
-}
-
-QString MercurialControl::findTopLevelForDirectory(const QString &directory) const
-{
-    QFileInfo dir(directory);
-    return mercurialClient->findTopLevelForFile(dir);
+    const QString topLevelFound = mercurialClient->findTopLevelForFile(dir);
+    if (topLevel)
+        *topLevel = topLevelFound;
+    return !topLevelFound.isEmpty();
 }
 
 bool MercurialControl::supportsOperation(Operation operation) const
@@ -65,6 +62,7 @@ bool MercurialControl::supportsOperation(Operation operation) const
     switch (operation) {
     case Core::IVersionControl::AddOperation:
     case Core::IVersionControl::DeleteOperation:
+    case Core::IVersionControl::MoveOperation:
     case Core::IVersionControl::CreateRepositoryOperation:
     case Core::IVersionControl::AnnotateOperation:
         break;
@@ -94,6 +92,13 @@ bool MercurialControl::vcsDelete(const QString &filename)
     return mercurialClient->remove(fi.absolutePath(), fi.fileName());
 }
 
+bool MercurialControl::vcsMove(const QString &from, const QString &to)
+{
+    const QFileInfo fromInfo(from);
+    const QFileInfo toInfo(to);
+    return mercurialClient->move(fromInfo.absolutePath(), fromInfo.absoluteFilePath(), toInfo.absoluteFilePath());
+}
+
 bool MercurialControl::vcsCreateRepository(const QString &directory)
 {
     return mercurialClient->createRepositorySync(directory);
@@ -129,8 +134,9 @@ bool MercurialControl::vcsAnnotate(const QString &file, int line)
 bool MercurialControl::sccManaged(const QString &filename)
 {
     const QFileInfo fi(filename);
-    const QString topLevel = findTopLevelForDirectory(fi.absolutePath());
-    if (topLevel.isEmpty())
+    QString topLevel;
+    const bool managed = managesDirectory(fi.absolutePath(), &topLevel);
+    if (!managed || topLevel.isEmpty())
         return false;
     const QDir topLevelDir(topLevel);
     return mercurialClient->manifestSync(topLevel, topLevelDir.relativeFilePath(filename));
index b6ee396..b74fce9 100644 (file)
@@ -50,12 +50,12 @@ public:
     explicit MercurialControl(MercurialClient *mercurialClient);
 
     QString displayName() const;
-    bool managesDirectory(const QString &filename) const;
-    QString findTopLevelForDirectory(const QString &directory) const;
+    bool managesDirectory(const QString &filename, QString *topLevel = 0) const;
     bool supportsOperation(Operation operation) const;
     bool vcsOpen(const QString &fileName);
     bool vcsAdd(const QString &filename);
     bool vcsDelete(const QString &filename);
+    bool vcsMove(const QString &from, const QString &to);
     bool vcsCreateRepository(const QString &directory);
     QString vcsCreateSnapshot(const QString &topLevel);
     QStringList vcsSnapshots(const QString &topLevel);
index d59d0af..90956c4 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="Perforce" version="1.3.84" compatVersion="1.3.84">
+<plugin name="Perforce" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,9 +14,9 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Perforce integration.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="TextEditor" version="1.3.84"/>
-        <dependency name="ProjectExplorer" version="1.3.84"/>
-        <dependency name="Core" version="1.3.84"/>
-        <dependency name="VCSBase" version="1.3.84"/>
+        <dependency name="TextEditor" version="2.0.80"/>
+        <dependency name="ProjectExplorer" version="2.0.80"/>
+        <dependency name="Core" version="2.0.80"/>
+        <dependency name="VCSBase" version="2.0.80"/>
     </dependencyList>
 </plugin>
index eef5f68..4a44dc4 100644 (file)
@@ -848,7 +848,20 @@ void PerforcePlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as)
     m_updateAllAction->setEnabled(true);
 }
 
-bool PerforcePlugin::managesDirectory(const QString &directory)
+bool PerforcePlugin::managesDirectory(const QString &directory, QString *topLevel /* = 0 */)
+{
+    const bool rc = managesDirectoryFstat(directory);
+    if (topLevel) {
+        if (rc) {
+            *topLevel = m_settings.topLevelSymLinkTarget();
+        } else {
+            topLevel->clear();
+        }
+    }
+    return rc;
+}
+
+bool PerforcePlugin::managesDirectoryFstat(const QString &directory)
 {
     if (!m_settings.isValid())
         return false;
@@ -875,13 +888,6 @@ bool PerforcePlugin::managesDirectory(const QString &directory)
     return managed;
 }
 
-QString PerforcePlugin::findTopLevelForDirectory(const QString &dir)
-{
-    if (!m_settings.isValid())
-        return QString();
-    return managesDirectory(dir) ? m_settings.topLevelSymLinkTarget() : QString();
-}
-
 bool PerforcePlugin::vcsOpen(const QString &workingDir, const QString &fileName)
 {
     if (Perforce::Constants::debug)
@@ -925,6 +931,22 @@ bool PerforcePlugin::vcsDelete(const QString &workingDir, const QString &fileNam
     return !deleteResult.error;
 }
 
+bool PerforcePlugin::vcsMove(const QString &workingDir, const QString &from, const QString &to)
+{
+    // TODO verify this works
+    QStringList args;
+    args << QLatin1String("edit") << from;
+    const PerforceResponse editResult = runP4Cmd(workingDir, args,
+                                                 CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
+    if (editResult.error)
+        return false;
+    args.clear();
+    args << QLatin1String("move") << from << to;
+    const PerforceResponse moveResult = runP4Cmd(workingDir, args,
+                                                 CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
+    return !moveResult.error;
+}
+
 static QString formatCommand(const QString &cmd, const QStringList &args)
 {
     const QChar blank = QLatin1Char(' ');
index 7c88bae..1e9cceb 100644 (file)
@@ -84,11 +84,11 @@ public:
     bool initialize(const QStringList &arguments, QString *error_message);
     void extensionsInitialized();
 
-    bool managesDirectory(const QString &directory);
-    QString findTopLevelForDirectory(const QString &directory);
+    bool managesDirectory(const QString &directory, QString *topLevel = 0);
     bool vcsOpen(const QString &workingDir, const QString &fileName);
     bool vcsAdd(const QString &workingDir, const QString &fileName);
     bool vcsDelete(const QString &workingDir, const QString &filename);
+    bool vcsMove(const QString &workingDir, const QString &from, const QString &to);
 
     void p4Diff(const QString &workingDir, const QStringList &files);
 
@@ -193,6 +193,7 @@ private:
     void updateCheckout(const QString &workingDir = QString(),
                         const QStringList &dirs = QStringList());
     bool revertProject(const QString &workingDir, const QStringList &args, bool unchangedOnly);
+    bool managesDirectoryFstat(const QString &directory);
 
     inline PerforceVersionControl *perforceVersionControl() const;
 
index ecd75e7..2dc414f 100644 (file)
@@ -53,6 +53,7 @@ bool PerforceVersionControl::supportsOperation(Operation operation) const
     switch (operation) {
     case AddOperation:
     case DeleteOperation:
+    case MoveOperation:
     case OpenOperation:
     case AnnotateOperation:
         return true;
@@ -81,6 +82,13 @@ bool PerforceVersionControl::vcsDelete(const QString &fileName)
     return m_plugin->vcsDelete(fi.absolutePath(), fi.fileName());
 }
 
+bool PerforceVersionControl::vcsMove(const QString &from, const QString &to)
+{
+    const QFileInfo fromInfo(from);
+    const QFileInfo toInfo(to);
+    return m_plugin->vcsMove(fromInfo.absolutePath(), fromInfo.absoluteFilePath(), toInfo.absoluteFilePath());
+}
+
 bool PerforceVersionControl::vcsCreateRepository(const QString &)
 {
     return false;
@@ -112,19 +120,15 @@ bool PerforceVersionControl::vcsAnnotate(const QString &file, int line)
     return true;
 }
 
-bool PerforceVersionControl::managesDirectory(const QString &directory) const
-{
-    const bool rc = m_plugin->managesDirectory(directory);
-    if (Perforce::Constants::debug)
-        qDebug() << "managesDirectory" << directory << rc;
-    return rc;
-}
-
-QString PerforceVersionControl::findTopLevelForDirectory(const QString &directory) const
+bool PerforceVersionControl::managesDirectory(const QString &directory, QString *topLevel) const
 {
-    const QString rc = m_plugin->findTopLevelForDirectory(directory);
-    if (Perforce::Constants::debug)
-        qDebug() << "findTopLevelForDirectory" << directory << rc;
+    const bool rc = m_plugin->managesDirectory(directory, topLevel);
+    if (Perforce::Constants::debug) {
+        QDebug nsp = qDebug().nospace();
+        nsp << "managesDirectory" << directory << rc;
+        if (topLevel)
+            nsp << topLevel;
+    }
     return rc;
 }
 
index 5be2ac9..1e14cd2 100644 (file)
@@ -45,13 +45,14 @@ public:
 
     virtual QString displayName() const;
 
-    bool managesDirectory(const QString &directory) const;
-    virtual QString findTopLevelForDirectory(const QString &directory) const;
+    virtual bool managesDirectory(const QString &directory, QString *topLevel = 0) const;
+
 
     virtual bool supportsOperation(Operation operation) const;
     virtual bool vcsOpen(const QString &fileName);
     virtual bool vcsAdd(const QString &fileName);
     virtual bool vcsDelete(const QString &filename);
+    virtual bool vcsMove(const QString &from, const QString &to);
     virtual bool vcsCreateRepository(const QString &directory);
     virtual QString vcsCreateSnapshot(const QString &topLevel);
     virtual QStringList vcsSnapshots(const QString &topLevel);
index 3db853d..ed71982 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="ProjectExplorer" version="1.3.84" compatVersion="1.3.84">
+<plugin name="ProjectExplorer" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,10 +14,10 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>ProjectExplorer framework that can be extended with different kind of project types.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="Core" version="1.3.84"/>
-        <dependency name="Find" version="1.3.84"/>
-        <dependency name="Locator" version="1.3.84"/>
-        <dependency name="TextEditor" version="1.3.84"/>
+        <dependency name="Core" version="2.0.80"/>
+        <dependency name="Find" version="2.0.80"/>
+        <dependency name="Locator" version="2.0.80"/>
+        <dependency name="TextEditor" version="2.0.80"/>
     </dependencyList>
     <argumentList>
         <argument name="-customwizard-verbose">Verbose loading of custom wizards</argument>
index cd08212..bb35f7c 100644 (file)
@@ -82,10 +82,13 @@ void ApplicationLauncher::start(Mode mode, const QString &program, const QString
 
 void ApplicationLauncher::stop()
 {
+    if (!isRunning())
+        return;
     if (m_currentMode == Gui) {
         m_winGuiProcess->stop();
     } else {
         m_consoleProcess->stop();
+        processStopped();
     }
 }
 
index cf15d0c..12a3a5e 100644 (file)
@@ -87,6 +87,8 @@ void ApplicationLauncher::start(Mode mode, const QString &program, const QString
 
 void ApplicationLauncher::stop()
 {
+    if (!isRunning())
+        return;
     if (m_currentMode == Gui) {
         m_guiProcess->terminate();
         if (!m_guiProcess->waitForFinished(1000)) { // This is blocking, so be fast.
@@ -95,6 +97,7 @@ void ApplicationLauncher::stop()
         }
     } else {
         m_consoleProcess->stop();
+        processStopped();
     }
 }
 
index aab7a56..05ae8f8 100644 (file)
@@ -80,7 +80,7 @@ QString LocalApplicationRunControlFactory::displayName() const
 RunControl *LocalApplicationRunControlFactory::create(ProjectExplorer::RunConfiguration *runConfiguration, const QString &mode)
 {
     QTC_ASSERT(canRun(runConfiguration, mode), return 0);
-    return new LocalApplicationRunControl(qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration));
+    return new LocalApplicationRunControl(qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration), mode);
 }
 
 QWidget *LocalApplicationRunControlFactory::createConfigurationWidget(RunConfiguration *runConfiguration)
@@ -91,8 +91,8 @@ QWidget *LocalApplicationRunControlFactory::createConfigurationWidget(RunConfigu
 
 // ApplicationRunControl
 
-LocalApplicationRunControl::LocalApplicationRunControl(LocalApplicationRunConfiguration *runConfiguration)
-    : RunControl(runConfiguration)
+LocalApplicationRunControl::LocalApplicationRunControl(LocalApplicationRunConfiguration *runConfiguration, QString mode)
+    : RunControl(runConfiguration, mode)
 {
     m_applicationLauncher.setEnvironment(runConfiguration->environment().toStringList());
     m_applicationLauncher.setWorkingDirectory(runConfiguration->workingDirectory());
index 4151260..a9c4241 100644 (file)
@@ -81,7 +81,7 @@ class LocalApplicationRunControl : public RunControl
 {
     Q_OBJECT
 public:
-    LocalApplicationRunControl(LocalApplicationRunConfiguration *runConfiguration);
+    LocalApplicationRunControl(LocalApplicationRunConfiguration *runConfiguration, QString mode);
     virtual ~LocalApplicationRunControl();
     virtual void start();
     virtual void stop();
diff --git a/src/plugins/projectexplorer/buildconfigurationmodel.cpp b/src/plugins/projectexplorer/buildconfigurationmodel.cpp
new file mode 100644 (file)
index 0000000..a9f93b6
--- /dev/null
@@ -0,0 +1,180 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "buildconfigurationmodel.h"
+#include "target.h"
+#include "buildconfiguration.h"
+
+using namespace ProjectExplorer;
+
+///
+/// RunConfigurationsModel
+///
+
+class BuildConfigurationComparer
+{
+public:
+    bool operator()(BuildConfiguration *a, BuildConfiguration *b)
+    {
+        return a->displayName() < b->displayName();
+    }
+};
+
+BuildConfigurationModel::BuildConfigurationModel(Target *target, QObject *parent)
+    : QAbstractListModel(parent),
+      m_target(target)
+{
+    m_buildConfigurations = m_target->buildConfigurations();
+    qSort(m_buildConfigurations.begin(), m_buildConfigurations.end(), BuildConfigurationComparer());
+
+    connect(target, SIGNAL(addedBuildConfiguration(ProjectExplorer::BuildConfiguration*)),
+            this, SLOT(addedBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
+    connect(target, SIGNAL(removedBuildConfiguration(ProjectExplorer::BuildConfiguration*)),
+            this, SLOT(removedBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
+
+    foreach (BuildConfiguration *bc, m_buildConfigurations)
+        connect(bc, SIGNAL(displayNameChanged()),
+                this, SLOT(displayNameChanged()));
+}
+
+int BuildConfigurationModel::rowCount(const QModelIndex &parent) const
+{
+    return parent.isValid() ? 0 : m_buildConfigurations.size();
+}
+
+int BuildConfigurationModel::columnCount(const QModelIndex &parent) const
+{
+    return parent.isValid() ? 0 : 1;
+}
+
+void BuildConfigurationModel::displayNameChanged()
+{
+    BuildConfiguration *rc = qobject_cast<BuildConfiguration *>(sender());
+    if (!rc)
+        return;
+
+    BuildConfigurationComparer compare;
+    // Find the old position
+    int oldPos = m_buildConfigurations.indexOf(rc);
+
+    if (oldPos >= 1 && compare(m_buildConfigurations.at(oldPos), m_buildConfigurations.at(oldPos - 1))) {
+        // We need to move up
+        int newPos = oldPos - 1;
+        while (newPos >= 0 && compare(m_buildConfigurations.at(oldPos), m_buildConfigurations.at(newPos))) {
+            --newPos;
+        }
+        ++newPos;
+
+        beginMoveRows(QModelIndex(), oldPos, oldPos, QModelIndex(), newPos);
+        m_buildConfigurations.insert(newPos, rc);
+        m_buildConfigurations.removeAt(oldPos + 1);
+        endMoveRows();
+        // Not only did we move, we also changed...
+        emit dataChanged(index(newPos, 0), index(newPos,0));
+    } else if  (oldPos < m_buildConfigurations.size() - 1
+                && compare(m_buildConfigurations.at(oldPos + 1), m_buildConfigurations.at(oldPos))) {
+        // We need to move down
+        int newPos = oldPos + 1;
+        while (newPos < m_buildConfigurations.size()
+            && compare(m_buildConfigurations.at(newPos), m_buildConfigurations.at(oldPos))) {
+            ++newPos;
+        }
+        beginMoveRows(QModelIndex(), oldPos, oldPos, QModelIndex(), newPos);
+        m_buildConfigurations.insert(newPos, rc);
+        m_buildConfigurations.removeAt(oldPos);
+        endMoveRows();
+
+        // We need to subtract one since removing at the old place moves the newIndex down
+        emit dataChanged(index(newPos - 1, 0), index(newPos - 1, 0));
+    } else {
+        emit dataChanged(index(oldPos, 0), index(oldPos, 0));
+    }
+}
+
+QVariant BuildConfigurationModel::data(const QModelIndex &index, int role) const
+{
+    if (role == Qt::DisplayRole) {
+        const int row = index.row();
+        if (row < m_buildConfigurations.size()) {
+            return m_buildConfigurations.at(row)->displayName();
+        }
+    }
+
+    return QVariant();
+}
+
+BuildConfiguration *BuildConfigurationModel::buildConfigurationAt(int i)
+{
+    if (i > m_buildConfigurations.size() || i < 0)
+        return 0;
+    return m_buildConfigurations.at(i);
+}
+
+BuildConfiguration *BuildConfigurationModel::buildConfigurationFor(const QModelIndex &idx)
+{
+    if (idx.row() > m_buildConfigurations.size() || idx.row() < 0)
+        return 0;
+    return m_buildConfigurations.at(idx.row());
+}
+
+QModelIndex BuildConfigurationModel::indexFor(BuildConfiguration *rc)
+{
+    int idx = m_buildConfigurations.indexOf(rc);
+    if (idx == -1)
+        return QModelIndex();
+    return index(idx, 0);
+}
+
+void BuildConfigurationModel::addedBuildConfiguration(ProjectExplorer::BuildConfiguration *bc)
+{
+    // Find the right place to insert
+    BuildConfigurationComparer compare;
+    int i = 0;
+    for (; i < m_buildConfigurations.size(); ++i) {
+        if (compare(bc, m_buildConfigurations.at(i))) {
+            break;
+        }
+    }
+
+    beginInsertRows(QModelIndex(), i, i);
+    m_buildConfigurations.insert(i, bc);
+    endInsertRows();
+
+
+    connect(bc, SIGNAL(displayNameChanged()),
+            this, SLOT(displayNameChanged()));
+}
+
+void BuildConfigurationModel::removedBuildConfiguration(ProjectExplorer::BuildConfiguration *bc)
+{
+    int i = m_buildConfigurations.indexOf(bc);
+    beginRemoveRows(QModelIndex(), i, i);
+    m_buildConfigurations.removeAt(i);
+    endRemoveRows();
+}
diff --git a/src/plugins/projectexplorer/buildconfigurationmodel.h b/src/plugins/projectexplorer/buildconfigurationmodel.h
new file mode 100644 (file)
index 0000000..5f14552
--- /dev/null
@@ -0,0 +1,69 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef BUILDCONFIGURATIONMODEL_H
+#define BUILDCONFIGURATIONMODEL_H
+
+#include <QtCore/QAbstractItemModel>
+
+namespace ProjectExplorer {
+class Target;
+class BuildConfiguration;
+
+/*! A model to represent the build configurations of a target.
+    To be used in for the drop down of comboboxes
+    Does automatically adjust itself to added and removed BuildConfigurations
+    Very similar to the Run Configuration Model
+    TOOD might it possible to share code without making the code a complete mess
+*/
+class BuildConfigurationModel : public QAbstractListModel
+{
+    Q_OBJECT
+public:
+    BuildConfigurationModel(Target *target, QObject *parent = 0);
+
+    int rowCount(const QModelIndex &parent = QModelIndex()) const;
+    int columnCount(const QModelIndex &parent = QModelIndex()) const;
+    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+    BuildConfiguration *buildConfigurationAt(int i);
+    BuildConfiguration *buildConfigurationFor(const QModelIndex &idx);
+    QModelIndex indexFor(BuildConfiguration *rc);
+private slots:
+    void addedBuildConfiguration(ProjectExplorer::BuildConfiguration*);
+    void removedBuildConfiguration(ProjectExplorer::BuildConfiguration*);
+    void displayNameChanged();
+private:
+    Target *m_target;
+    QList<BuildConfiguration *> m_buildConfigurations;
+};
+
+}
+
+#endif // RUNCONFIGURATIONMODEL_H
index 5cd7c3b..cc8f99c 100644 (file)
@@ -33,6 +33,7 @@
 #include "project.h"
 #include "target.h"
 #include "buildconfiguration.h"
+#include "buildconfigurationmodel.h"
 
 #include <coreplugin/coreconstants.h>
 #include <extensionsystem/pluginmanager.h>
@@ -148,6 +149,7 @@ void BuildSettingsWidget::setupUi()
         hbox->addWidget(new QLabel(tr("Edit build configuration:"), this));
         m_buildConfigurationComboBox = new QComboBox(this);
         m_buildConfigurationComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
+        m_buildConfigurationComboBox->setModel(new BuildConfigurationModel(m_target, this));
         hbox->addWidget(m_buildConfigurationComboBox);
 
         m_addButton = new QPushButton(this);
@@ -167,6 +169,8 @@ void BuildSettingsWidget::setupUi()
     }
 
     m_buildConfiguration = m_target->activeBuildConfiguration();
+    BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildConfigurationComboBox->model());
+    m_buildConfigurationComboBox->setCurrentIndex(model->indexFor(m_buildConfiguration).row());
 
     updateAddButtonMenu();
     updateBuildSettings();
@@ -180,42 +184,11 @@ void BuildSettingsWidget::setupUi()
     connect(m_target, SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)),
             this, SLOT(updateActiveConfiguration()));
 
-    connect(m_target, SIGNAL(addedBuildConfiguration(ProjectExplorer::BuildConfiguration*)),
-            this, SLOT(addedBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
-
-    connect(m_target, SIGNAL(removedBuildConfiguration(ProjectExplorer::BuildConfiguration*)),
-            this, SLOT(removedBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
-
-    foreach (BuildConfiguration *bc, m_target->buildConfigurations()) {
-        connect(bc, SIGNAL(displayNameChanged()),
-                this, SLOT(buildConfigurationDisplayNameChanged()));
-    }
-
     if (m_target->buildConfigurationFactory())
         connect(m_target->buildConfigurationFactory(), SIGNAL(availableCreationIdsChanged()),
                 SLOT(updateAddButtonMenu()));
 }
 
-void BuildSettingsWidget::addedBuildConfiguration(BuildConfiguration *bc)
-{
-    connect(bc, SIGNAL(displayNameChanged()),
-            this, SLOT(buildConfigurationDisplayNameChanged()));
-}
-
-void BuildSettingsWidget::removedBuildConfiguration(BuildConfiguration *bc)
-{
-    disconnect(bc, SIGNAL(displayNameChanged()),
-               this, SLOT(buildConfigurationDisplayNameChanged()));
-}
-
-void BuildSettingsWidget::buildConfigurationDisplayNameChanged()
-{
-    for (int i = 0; i < m_buildConfigurationComboBox->count(); ++i) {
-        BuildConfiguration *bc = m_buildConfigurationComboBox->itemData(i).value<BuildConfiguration *>();
-        m_buildConfigurationComboBox->setItemText(i, bc->displayName());
-    }
-}
-
 void BuildSettingsWidget::addSubWidget(const QString &name, BuildConfigWidget *widget)
 {
     widget->setContentsMargins(m_leftMargin, 10, 0, 0);
@@ -268,9 +241,6 @@ void BuildSettingsWidget::updateAddButtonMenu()
 
 void BuildSettingsWidget::updateBuildSettings()
 {
-    // Delete old tree items
-    bool blocked = m_buildConfigurationComboBox->blockSignals(true);
-    m_buildConfigurationComboBox->clear();
     clear();
 
     // update buttons
@@ -287,22 +257,14 @@ void BuildSettingsWidget::updateBuildSettings()
     foreach (BuildConfigWidget *subConfigWidget, subConfigWidgets)
         addSubWidget(subConfigWidget->displayName(), subConfigWidget);
 
-    // Add tree items
-    foreach (BuildConfiguration *bc, m_target->buildConfigurations()) {
-        m_buildConfigurationComboBox->addItem(bc->displayName(), QVariant::fromValue<BuildConfiguration *>(bc));
-        if (bc == m_buildConfiguration)
-            m_buildConfigurationComboBox->setCurrentIndex(m_buildConfigurationComboBox->count() - 1);
-    }
-
     foreach (BuildConfigWidget *widget, subWidgets())
         widget->init(m_buildConfiguration);
-
-    m_buildConfigurationComboBox->blockSignals(blocked);
 }
 
 void BuildSettingsWidget::currentIndexChanged(int index)
 {
-    BuildConfiguration *buildConfiguration = m_buildConfigurationComboBox->itemData(index).value<BuildConfiguration *>();
+    BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildConfigurationComboBox->model());
+    BuildConfiguration *buildConfiguration = model->buildConfigurationAt(index);
     m_target->setActiveBuildConfiguration(buildConfiguration);
 }
 
@@ -313,12 +275,8 @@ void BuildSettingsWidget::updateActiveConfiguration()
 
     m_buildConfiguration = m_target->activeBuildConfiguration();
 
-    for (int i = 0; i < m_buildConfigurationComboBox->count(); ++i) {
-        if (m_buildConfigurationComboBox->itemData(i).value<BuildConfiguration *>() == m_buildConfiguration) {
-            m_buildConfigurationComboBox->setCurrentIndex(i);
-            break;
-        }
-    }
+    BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildConfigurationComboBox->model());
+    m_buildConfigurationComboBox->setCurrentIndex(model->indexFor(m_buildConfiguration).row());
 
     foreach (QWidget *widget, subWidgets()) {
         if (BuildConfigWidget *buildStepWidget = qobject_cast<BuildConfigWidget*>(widget)) {
index 5a38dba..e93f849 100644 (file)
@@ -102,9 +102,6 @@ private slots:
     void deleteConfiguration();
     void updateAddButtonMenu();
 
-    void addedBuildConfiguration(ProjectExplorer::BuildConfiguration *bc);
-    void removedBuildConfiguration(ProjectExplorer::BuildConfiguration *bc);
-    void buildConfigurationDisplayNameChanged();
     void updateActiveConfiguration();
 
 private:
index bb33911..3779161 100644 (file)
@@ -42,6 +42,7 @@
 #include <QtGui/QLabel>
 #include <QtGui/QRegExpValidator>
 #include <QtGui/QComboBox>
+#include <QtGui/QTextEdit>
 
 enum { debug = 0 };
 
@@ -69,6 +70,11 @@ CustomWizardFieldPage::LineEditData::LineEditData(QLineEdit* le, const QString &
 {
 }
 
+CustomWizardFieldPage::TextEditData::TextEditData(QTextEdit* le, const QString &defText) :
+    textEdit(le), defaultText(defText)
+{
+}
+
 CustomWizardFieldPage::CustomWizardFieldPage(const QSharedPointer<CustomWizardContext> &ctx,
                                              const FieldList &fields,
                                              QWidget *parent) :
@@ -76,6 +82,7 @@ CustomWizardFieldPage::CustomWizardFieldPage(const QSharedPointer<CustomWizardCo
     m_context(ctx),
     m_formLayout(new QFormLayout)
 {
+    m_formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
     if (debug)
         qDebug() << Q_FUNC_INFO << fields.size();
     foreach(const CustomWizardField &f, fields)
@@ -105,6 +112,10 @@ void CustomWizardFieldPage::addField(const CustomWizardField &field)\
     QWidget *fieldWidget = 0;
     if (className == QLatin1String("QComboBox")) {
         fieldWidget = registerComboBox(fieldName, field);
+    } else if (className == QLatin1String("QTextEdit")) {
+        fieldWidget = registerTextEdit(fieldName, field);
+    } else if (className == QLatin1String("Utils::PathChooser")) {
+        fieldWidget = registerPathChooser(fieldName, field);
     } else {
         fieldWidget = registerLineEdit(fieldName, field);
     }
@@ -133,6 +144,24 @@ QWidget *CustomWizardFieldPage::registerComboBox(const QString &fieldName,
     return combo;
 } // QComboBox
 
+QWidget *CustomWizardFieldPage::registerTextEdit(const QString &fieldName,
+                                                 const CustomWizardField &field)
+{
+    QTextEdit *textEdit = new QTextEdit;
+    registerField(fieldName, textEdit, "plainText", SIGNAL(textChanged(QString)));
+    const QString defaultText = field.controlAttributes.value(QLatin1String("defaulttext"));
+    m_textEdits.push_back(TextEditData(textEdit, defaultText));
+    return textEdit;
+} // QTextEdit
+
+QWidget *CustomWizardFieldPage::registerPathChooser(const QString &fieldName,
+                                                 const CustomWizardField &field)
+{
+    Utils::PathChooser *pathChooser = new Utils::PathChooser;
+    registerField(fieldName, pathChooser, "path", SIGNAL(changed(QString)));
+    return pathChooser;
+} // Utils::PathChooser
+
 QWidget *CustomWizardFieldPage::registerLineEdit(const QString &fieldName,
                                                  const CustomWizardField &field)
 {
@@ -167,6 +196,13 @@ void CustomWizardFieldPage::initializePage()
             led.lineEdit->setText(defaultText);
         }
     }
+    foreach(const TextEditData &ted, m_textEdits) {
+        if (!ted.defaultText.isEmpty()) {
+            QString defaultText = ted.defaultText;
+            CustomWizardContext::replaceFields(m_context->baseReplacements, &defaultText);
+            ted.textEdit->setText(defaultText);
+        }
+    }
 }
 
 bool CustomWizardFieldPage::validatePage()
index fe27a08..936c033 100644 (file)
@@ -37,6 +37,7 @@
 QT_BEGIN_NAMESPACE
 class QFormLayout;
 class QLineEdit;
+class QTextEdit;
 QT_END_NAMESPACE
 
 namespace Utils {
@@ -92,16 +93,24 @@ private:
         QLineEdit* lineEdit;
         QString defaultText;
     };
+    struct TextEditData {
+        explicit TextEditData(QTextEdit* le = 0, const QString &defText = QString());
+        QTextEdit* textEdit;
+        QString defaultText;
+    };
     typedef QList<LineEditData> LineEditDataList;
+    typedef QList<TextEditData> TextEditDataList;
 
     QWidget *registerLineEdit(const QString &fieldName, const CustomWizardField &field);
     QWidget *registerComboBox(const QString &fieldName, const CustomWizardField &field);
-
+    QWidget *registerTextEdit(const QString &fieldName, const CustomWizardField &field);
+    QWidget *registerPathChooser(const QString &fieldName, const CustomWizardField &field);
     void addField(const CustomWizardField &f);
 
     const QSharedPointer<CustomWizardContext> m_context;
     QFormLayout *m_formLayout;
     LineEditDataList m_lineEdits;
+    TextEditDataList m_textEdits;
 };
 
 // A custom wizard page presenting the fields to be used and a path chooser
index 326200a..1a2d69c 100644 (file)
@@ -196,7 +196,7 @@ QString Environment::searchInPath(QString executable) const
 #endif
     const QChar slash = QLatin1Char('/');
     foreach (const QString &p, path()) {
-//        qDebug()<<"trying"<<path + '/' + executable;
+//        qDebug()<<"trying"<<p + '/' + executable;
         QString fp = p;
         fp += slash;
         fp += executable;
@@ -216,7 +216,7 @@ QStringList Environment::path() const
 #else
     const QChar sep = QLatin1Char(':');
 #endif
-    return m_values.value(QLatin1String("PATH")).split(sep);
+    return m_values.value(QLatin1String("PATH")).split(sep, QString::SkipEmptyParts);
 }
 
 QString Environment::value(const QString &key) const
index b71e78f..66e50df 100644 (file)
@@ -28,6 +28,8 @@
 **************************************************************************/
 
 #include "miniprojecttargetselector.h"
+#include "buildconfigurationmodel.h"
+#include "runconfigurationmodel.h"
 
 #include <utils/qtcassert.h>
 #include <utils/styledbar.h>
@@ -186,6 +188,7 @@ MiniTargetWidget::MiniTargetWidget(Target *target, QWidget *parent) :
         m_buildComboBox->setProperty("hideborder", true);
         m_buildComboBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
         m_buildComboBox->setToolTip(tr("Select active build configuration"));
+        m_buildComboBox->setModel(new BuildConfigurationModel(m_target, this));
     } else {
         m_buildComboBox = 0;
     }
@@ -195,6 +198,8 @@ MiniTargetWidget::MiniTargetWidget(Target *target, QWidget *parent) :
     m_runComboBox ->setProperty("hideborder", true);
     m_runComboBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
     m_runComboBox->setToolTip(tr("Select active run configuration"));
+    RunConfigurationModel *model = new RunConfigurationModel(m_target, this);
+    m_runComboBox->setModel(model);
     int fontSize = font().pointSize();
     setStyleSheet(QString::fromLatin1("QLabel { font-size: %2pt; color: white; } "
                                       "#target { font: bold %1pt;} "
@@ -212,6 +217,9 @@ MiniTargetWidget::MiniTargetWidget(Target *target, QWidget *parent) :
         Q_FOREACH(BuildConfiguration* bc, m_target->buildConfigurations())
                 addBuildConfiguration(bc);
 
+        BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildComboBox->model());
+        m_buildComboBox->setCurrentIndex(model->indexFor(m_target->activeBuildConfiguration()).row());
+
         connect(m_target, SIGNAL(addedBuildConfiguration(ProjectExplorer::BuildConfiguration*)),
                 SLOT(addBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
         connect(m_target, SIGNAL(removedBuildConfiguration(ProjectExplorer::BuildConfiguration*)),
@@ -222,8 +230,8 @@ MiniTargetWidget::MiniTargetWidget(Target *target, QWidget *parent) :
         connect(m_buildComboBox, SIGNAL(currentIndexChanged(int)), SLOT(setActiveBuildConfiguration(int)));
     }
 
-    Q_FOREACH(RunConfiguration* rc, m_target->runConfigurations())
-            addRunConfiguration(rc);
+    m_runComboBox->setEnabled(m_target->runConfigurations().count() > 1);
+    m_runComboBox->setCurrentIndex(model->indexFor(m_target->activeRunConfiguration()).row());
 
     connect(m_target, SIGNAL(addedRunConfiguration(ProjectExplorer::RunConfiguration*)),
             SLOT(addRunConfiguration(ProjectExplorer::RunConfiguration*)));
@@ -280,79 +288,57 @@ ProjectExplorer::Target *MiniTargetWidget::target() const
 
 void MiniTargetWidget::setActiveBuildConfiguration(int index)
 {
-    ProjectExplorer::BuildConfiguration* bc =
-            m_buildComboBox->itemData(index).value<ProjectExplorer::BuildConfiguration*>();
-    m_target->setActiveBuildConfiguration(bc);
+    BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildComboBox->model());
+    m_target->setActiveBuildConfiguration(model->buildConfigurationAt(index));
     emit changed();
 }
 
 void MiniTargetWidget::setActiveRunConfiguration(int index)
 {
-    m_target->setActiveRunConfiguration(
-            m_runComboBox->itemData(index).value<ProjectExplorer::RunConfiguration*>());
+    RunConfigurationModel *model = static_cast<RunConfigurationModel *>(m_runComboBox->model());
+    m_target->setActiveRunConfiguration(model->runConfigurationAt(index));
     updateIcon();
     emit changed();
 }
+
 void MiniTargetWidget::setActiveBuildConfiguration()
 {
-    QTC_ASSERT(m_buildComboBox, return)
-    m_buildComboBox->setCurrentIndex(m_buildComboBox->findData(
-            QVariant::fromValue(m_target->activeBuildConfiguration())));
+    QTC_ASSERT(m_buildComboBox, return);
+    BuildConfigurationModel *model = static_cast<BuildConfigurationModel *>(m_buildComboBox->model());
+    m_buildComboBox->setCurrentIndex(model->indexFor(m_target->activeBuildConfiguration()).row());
 }
 
 void MiniTargetWidget::setActiveRunConfiguration()
 {
-    m_runComboBox->setCurrentIndex(m_runComboBox->findData(
-            QVariant::fromValue(m_target->activeRunConfiguration())));
+    RunConfigurationModel *model = static_cast<RunConfigurationModel *>(m_runComboBox->model());
+    m_runComboBox->setCurrentIndex(model->indexFor(m_target->activeRunConfiguration()).row());
 }
 
 void MiniTargetWidget::addRunConfiguration(ProjectExplorer::RunConfiguration* rc)
 {
-    connect(rc, SIGNAL(displayNameChanged()), SLOT(updateDisplayName()));
-    m_runComboBox->addItem(rc->displayName(), QVariant::fromValue(rc));
-    if (m_target->activeRunConfiguration() == rc)
-        m_runComboBox->setCurrentIndex(m_runComboBox->count()-1);
-
-    m_runComboBox->setEnabled(m_runComboBox->count()>1);
+    Q_UNUSED(rc);
+    m_runComboBox->setEnabled(m_target->runConfigurations().count()>1);
 }
 
 void MiniTargetWidget::removeRunConfiguration(ProjectExplorer::RunConfiguration* rc)
 {
-    m_runComboBox->removeItem(m_runComboBox->findData(QVariant::fromValue(rc)));
-    m_runComboBox->setEnabled(m_runComboBox->count()>1);
+    Q_UNUSED(rc);
+    m_runComboBox->setEnabled(m_target->runConfigurations().count()>1);
 }
 
 void MiniTargetWidget::addBuildConfiguration(ProjectExplorer::BuildConfiguration* bc)
 {
+    Q_UNUSED(bc);
     QTC_ASSERT(m_buildComboBox, return);
-    connect(bc, SIGNAL(displayNameChanged()), SLOT(updateDisplayName()));
-    m_buildComboBox->addItem(bc->displayName(), QVariant::fromValue(bc));
-    if (m_target->activeBuildConfiguration() == bc)
-        m_buildComboBox->setCurrentIndex(m_buildComboBox->count()-1);
-
-    m_buildComboBox->setEnabled(m_buildComboBox->count() > 1);
+    connect(bc, SIGNAL(displayNameChanged()), SIGNAL(changed()), Qt::UniqueConnection);
+    m_buildComboBox->setEnabled(m_target->buildConfigurations().count() > 1);
 }
 
 void MiniTargetWidget::removeBuildConfiguration(ProjectExplorer::BuildConfiguration* bc)
 {
+    Q_UNUSED(bc);
     QTC_ASSERT(m_buildComboBox, return);
-    m_buildComboBox->removeItem(m_buildComboBox->findData(QVariant::fromValue(bc)));
-    m_buildComboBox->setEnabled(m_buildComboBox->count() > 1);
-}
-
-void MiniTargetWidget::updateDisplayName()
-{
-    QObject *obj = sender();
-    RunConfiguration *rc = qobject_cast<RunConfiguration*>(obj);
-    BuildConfiguration *bc = qobject_cast<BuildConfiguration*>(obj);
-    if (rc) {
-        m_runComboBox->setItemText(m_runComboBox->findData(QVariant::fromValue(rc)),
-                                   rc->displayName());
-    } else if (bc) {
-        m_buildComboBox->setItemText(m_buildComboBox->findData(QVariant::fromValue(bc)),
-                                     bc->displayName());
-    }
-    emit changed();
+    m_buildComboBox->setEnabled(m_target->buildConfigurations().count() > 1);
 }
 
 bool MiniTargetWidget::hasBuildConfiguration() const
index faffe3d..adaff96 100644 (file)
@@ -81,7 +81,7 @@ public:
 
 private slots:
     void addRunConfiguration(ProjectExplorer::RunConfiguration *runConfig);
-    void removeRunConfiguration(ProjectExplorer::RunConfiguration *buildConfig);
+    void removeRunConfiguration(ProjectExplorer::RunConfiguration *runConfig);
     void addBuildConfiguration(ProjectExplorer::BuildConfiguration *buildConfig);
     void removeBuildConfiguration(ProjectExplorer::BuildConfiguration *buildConfig);
 
@@ -90,7 +90,6 @@ private slots:
     void setActiveBuildConfiguration();
     void setActiveRunConfiguration();
 
-    void updateDisplayName();
     void updateIcon();
 
 signals:
index 3423d4b..45dfc83 100644 (file)
@@ -32,6 +32,7 @@
 #include "projectexplorer.h"
 #include "projectexplorersettings.h"
 #include "runconfiguration.h"
+#include "session.h"
 
 #include <coreplugin/actionmanager/actionmanager.h>
 #include <coreplugin/actionmanager/actioncontainer.h>
@@ -64,12 +65,15 @@ static const int MaxBlockCount = 100000;
 OutputPane::OutputPane()
     : m_mainWidget(new QWidget)
 {
-    QIcon runIcon(Constants::ICON_RUN);
-    runIcon.addFile(Constants::ICON_RUN_SMALL);
+    m_runIcon.addFile(Constants::ICON_RUN);
+    m_runIcon.addFile(Constants::ICON_RUN_SMALL);
+
+    m_debugIcon.addFile(Constants::ICON_DEBUG);
+    m_debugIcon.addFile(Constants::ICON_DEBUG_SMALL);
 
     // Rerun
     m_reRunButton = new QToolButton;
-    m_reRunButton->setIcon(runIcon);
+    m_reRunButton->setIcon(m_runIcon);
     m_reRunButton->setToolTip(tr("Re-run this run-configuration"));
     m_reRunButton->setAutoRaise(true);
     m_reRunButton->setEnabled(false);
@@ -111,6 +115,9 @@ OutputPane::OutputPane()
 
     connect(Core::ICore::instance(), SIGNAL(coreAboutToClose()),
             this, SLOT(coreAboutToClose()));
+
+    connect(ProjectExplorer::ProjectExplorerPlugin::instance()->session(), SIGNAL(aboutToUnloadSession()),
+            this, SLOT(aboutToUnloadSession()));
 }
 
 void OutputPane::coreAboutToClose()
@@ -123,6 +130,16 @@ void OutputPane::coreAboutToClose()
     }
 }
 
+void OutputPane::aboutToUnloadSession()
+{
+    int i = 0;
+    while (i < m_tabWidget->count()) {
+        bool closed = closeTab(i);
+        if (!closed) // skip to next one
+            ++i;
+    }
+}
+
 OutputPane::~OutputPane()
 {
     delete m_mainWidget;
@@ -256,7 +273,7 @@ void OutputPane::stopRunControl()
     rc->stop();
 }
 
-void OutputPane::closeTab(int index)
+bool OutputPane::closeTab(int index)
 {
     OutputWindow *ow = static_cast<OutputWindow *>(m_tabWidget->widget(index));
     RunControl *rc = m_outputWindows.key(ow);
@@ -264,15 +281,16 @@ void OutputPane::closeTab(int index)
     if (rc->isRunning()) {
         QMessageBox messageBox(QMessageBox::Warning,
                                tr("Unable to close"),
-                               tr("The application is still running."),
+                               tr("%1 is still running.").arg(rc->displayName()),
                                QMessageBox::Cancel | QMessageBox::Yes,
                                ow->window());
         messageBox.setInformativeText(tr("Force it to quit?"));
         messageBox.setDefaultButton(QMessageBox::Yes);
         messageBox.button(QMessageBox::Yes)->setText(tr("Force Quit"));
+        messageBox.button(QMessageBox::Cancel)->setText(tr("Keep Running"));
 
         if (messageBox.exec() != QMessageBox::Yes)
-            return;
+            return false;
 
         rc->stop();
     }
@@ -280,6 +298,7 @@ void OutputPane::closeTab(int index)
     m_tabWidget->removeTab(index);
     delete ow;
     delete rc;
+    return true;
 }
 
 void OutputPane::projectRemoved()
@@ -296,6 +315,7 @@ void OutputPane::tabChanged(int i)
         RunControl *rc = runControlForTab(i);
         m_stopAction->setEnabled(rc->isRunning());
         m_reRunButton->setEnabled(!rc->isRunning());
+        m_reRunButton->setIcon( rc->runMode() == Constants::DEBUGMODE ? m_debugIcon : m_runIcon);
     }
 }
 
@@ -305,6 +325,7 @@ void OutputPane::runControlStarted()
     if (rc == qobject_cast<RunControl *>(sender())) {
         m_reRunButton->setEnabled(false);
         m_stopAction->setEnabled(true);
+        m_reRunButton->setIcon( rc->runMode() == Constants::DEBUGMODE ? m_debugIcon : m_runIcon);
     }
 }
 
@@ -314,6 +335,7 @@ void OutputPane::runControlFinished()
     if (rc == qobject_cast<RunControl *>(sender())) {
         m_reRunButton->setEnabled(rc);
         m_stopAction->setEnabled(false);
+        m_reRunButton->setIcon( rc->runMode() == Constants::DEBUGMODE ? m_debugIcon : m_runIcon);
     }
 }
 
index cc791a5..68ab239 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <QtCore/QObject>
 #include <QtCore/QHash>
+#include <QtGui/QIcon>
 #include <QtGui/QShowEvent>
 #include <QtGui/QPlainTextEdit>
 
@@ -101,11 +102,13 @@ public slots:
 private slots:
     void reRunRunControl();
     void stopRunControl();
-    void closeTab(int index);
+    bool closeTab(int index);
     void tabChanged(int);
     void runControlStarted();
     void runControlFinished();
 
+    void aboutToUnloadSession();
+
 private:
     RunControl *runControlForTab(int index) const;
 
@@ -115,6 +118,8 @@ private:
     QAction *m_stopAction;
     QToolButton *m_reRunButton;
     QToolButton *m_stopButton;
+    QIcon m_runIcon;
+    QIcon m_debugIcon;
 };
 
 
index 855b36e..a6c5961 100644 (file)
@@ -76,8 +76,6 @@ Core::IFile *ProjectFileFactory::open(const QString &fileName)
         SessionManager *session = pe->session();
         if (session->projects().count() == 1)
             fIFace = session->projects().first()->file();
-        else if (session->projects().count() > 1)
-            fIFace = session->file();  // TODO: Why return session file interface here ???
     }
     return fIFace;
 }
index 9e6f01b..25d31ab 100644 (file)
@@ -686,13 +686,15 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
                        globalcontext);
     mfilec->addAction(cmd, Constants::G_FILE_OTHER);
 
-    // renamefile action (TODO: Not supported yet)
+    // renamefile action
     d->m_renameFileAction = new QAction(tr("Rename"), this);
     cmd = am->registerAction(d->m_renameFileAction, ProjectExplorer::Constants::RENAMEFILE,
                        globalcontext);
     mfilec->addAction(cmd, Constants::G_FILE_OTHER);
-    d->m_renameFileAction->setEnabled(false);
-    d->m_renameFileAction->setVisible(false);
+    // Not yet used by anyone, so hide for now
+//    mfolder->addAction(cmd, Constants::G_FOLDER_FILES);
+//    msubProject->addAction(cmd, Constants::G_FOLDER_FILES);
+//    mproject->addAction(cmd, Constants::G_FOLDER_FILES);
 
     // target selector
     d->m_projectSelectorAction = new QAction(this);
@@ -969,7 +971,7 @@ void ProjectExplorerPlugin::savePersistentSettings()
 
     QSettings *s = Core::ICore::instance()->settings();
     if (s) {
-        s->setValue("ProjectExplorer/StartupSession", d->m_session->file()->fileName());
+        s->setValue("ProjectExplorer/StartupSession", d->m_session->currentSession());
         s->remove("ProjectExplorer/RecentProjects/Files");
 
         QStringList fileNames;
@@ -1228,7 +1230,7 @@ void ProjectExplorerPlugin::showContextMenu(const QPoint &globalPos, Node *node)
         contextMenu = d->m_sessionContextMenu;
     }
 
-    updateContextMenuActions();
+    updateContextMenuActions(d->m_currentNode);
     if (contextMenu && contextMenu->actions().count() > 0) {
         contextMenu->popup(globalPos);
     }
@@ -1900,19 +1902,24 @@ void ProjectExplorerPlugin::goToTaskWindow()
     d->m_buildManager->gotoTaskWindow();
 }
 
-void ProjectExplorerPlugin::updateContextMenuActions()
+void ProjectExplorerPlugin::updateContextMenuActions(Node *node)
 {
     d->m_addExistingFilesAction->setEnabled(false);
     d->m_addNewFileAction->setEnabled(false);
     d->m_removeFileAction->setEnabled(false);
 
-    if (FolderNode *folderNode = qobject_cast<FolderNode*>(d->m_currentNode)) {
-        const bool addFilesEnabled = folderNode->projectNode()->supportedActions().contains(ProjectNode::AddFile);
+    QList<ProjectNode::ProjectAction> actions =
+            d->m_currentNode->projectNode()->supportedActions(node);
+
+    if (qobject_cast<FolderNode*>(d->m_currentNode)) {
+        bool addFilesEnabled = actions.contains(ProjectNode::AddFile);
         d->m_addExistingFilesAction->setEnabled(addFilesEnabled);
         d->m_addNewFileAction->setEnabled(addFilesEnabled);
-    } else if (FileNode *fileNode = qobject_cast<FileNode*>(d->m_currentNode)) {
-        const bool removeFileEnabled = fileNode->projectNode()->supportedActions().contains(ProjectNode::RemoveFile);
+        d->m_renameFileAction->setEnabled(actions.contains(ProjectNode::Rename));
+    } else if (qobject_cast<FileNode*>(d->m_currentNode)) {
+        bool removeFileEnabled = actions.contains(ProjectNode::RemoveFile);
         d->m_removeFileAction->setEnabled(removeFileEnabled);
+        d->m_renameFileAction->setEnabled(actions.contains(ProjectNode::Rename));
     }
 }
 
@@ -2010,8 +2017,7 @@ void ProjectExplorerPlugin::removeFile()
     FileNode *fileNode = qobject_cast<FileNode*>(d->m_currentNode);
     Core::ICore *core = Core::ICore::instance();
 
-    const QString filePath = d->m_currentNode->path();
-    const QString fileDir = QFileInfo(filePath).dir().absolutePath();
+    QString filePath = d->m_currentNode->path();
     RemoveFileDialog removeFileDialog(filePath, core->mainWindow());
 
     if (removeFileDialog.exec() == QDialog::Accepted) {
@@ -2057,6 +2063,31 @@ void ProjectExplorerPlugin::renameFile()
     }
 }
 
+void ProjectExplorerPlugin::renameFile(Node *node, const QString &to)
+{
+    FileNode *fileNode = qobject_cast<FileNode *>(node);
+    if (!fileNode)
+        return;
+    QString orgFilePath = node->path();
+    QString dir = QFileInfo(orgFilePath).absolutePath();
+    QString newFilePath = dir + "/" + to;
+    Core::ICore *core = Core::ICore::instance();
+    Core::IVersionControl *vc = core->vcsManager()->findVersionControlForDirectory(dir);
+    bool result = false;
+    if (vc->supportsOperation(Core::IVersionControl::MoveOperation))
+        result = vc->vcsMove(orgFilePath, newFilePath);
+    if (!result) // The moving via vcs failed or the vcs does not support moving, fall back
+        result = QFile::rename(orgFilePath, newFilePath);
+    if (result) {
+        // yeah we moved, tell the filemanager about it
+        Core::ICore::instance()->fileManager()->renamedFile(orgFilePath, newFilePath);
+        // Tell the project plugin about it
+        ProjectNode *projectNode = fileNode->projectNode();
+        projectNode->renameFile(fileNode->fileType(), orgFilePath, newFilePath);
+        // TODO emit a signal?
+    }
+}
+
 void ProjectExplorerPlugin::populateOpenWithMenu(QMenu *menu, const QString &fileName)
 {
     typedef QList<Core::IEditorFactory*> EditorFactoryList;
index b25d640..4960dc9 100644 (file)
@@ -107,6 +107,9 @@ public:
 
     void startRunControl(RunControl *runControl, const QString &mode);
 
+    // internal public for FlatModel
+    void renameFile(Node *node, const QString &to);
+
 signals:
     void aboutToShowContextMenu(ProjectExplorer::Project *project,
                                 ProjectExplorer::Node *node);
@@ -159,7 +162,7 @@ private slots:
     void savePersistentSettings();
     void goToTaskWindow();
 
-    void updateContextMenuActions();
+    void updateContextMenuActions(Node *node);
     void addNewFile();
     void addExistingFiles();
     void openFile();
index 822a7b9..21ce772 100644 (file)
@@ -1,7 +1,8 @@
 TEMPLATE = lib
 TARGET = ProjectExplorer
 QT += xml \
-    script
+    script \
+    network
 include(../../qtcreatorplugin.pri)
 include(projectexplorer_dependencies.pri)
 include(../../shared/scriptwrapper/scriptwrapper.pri)
@@ -41,7 +42,6 @@ HEADERS += projectexplorer.h \
     buildsettingspropertiespage.h \
     environmenteditmodel.h \
     processstep.h \
-    abstractprocessstep.h \
     editorconfiguration.h \
     editorsettingspropertiespage.h \
     runconfiguration.h \
@@ -80,7 +80,10 @@ HEADERS += projectexplorer.h \
     buildconfigdialog.h \
     ldparser.h \
     linuxiccparser.h \
-    outputformatter.h
+    outputformatter.h \
+    runconfigurationmodel.h \
+    buildconfigurationmodel.h \
+    abstractprocessstep.h
 SOURCES += projectexplorer.cpp \
     projectwindow.cpp \
     buildmanager.cpp \
@@ -147,7 +150,9 @@ SOURCES += projectexplorer.cpp \
     buildconfigdialog.cpp \
     ldparser.cpp \
     linuxiccparser.cpp \
-    outputformatter.cpp
+    outputformatter.cpp \
+    runconfigurationmodel.cpp \
+    buildconfigurationmodel.cpp
 FORMS += processstep.ui \
     editorsettingspropertiespage.ui \
     runsettingspropertiespage.ui \
index 4483623..8acb805 100644 (file)
@@ -60,7 +60,8 @@ typedef QList<ProjectNode *> ProjectNodeList;
 
 namespace Internal {
 
-// AllProjectNodesVisitor: Retrieve all projects (*.pri/*.pro).
+// AllProjectNodesVisitor: Retrieve all projects (*.pri/*.pro)
+// which support adding files
 class AllProjectNodesVisitor : public NodesVisitor
 {
 public:
@@ -81,7 +82,7 @@ ProjectNodeList AllProjectNodesVisitor::allProjects()
 
 void AllProjectNodesVisitor::visitProjectNode(ProjectNode *node)
 {
-    if (node->supportedActions().contains(ProjectNode::AddFile))
+    if (node->supportedActions(node).contains(ProjectNode::AddFile))
         m_projectNodes.push_back(node);
 }
 
index d582a3f..0bdb627 100644 (file)
@@ -32,6 +32,7 @@
 #include "project.h"
 #include "projectexplorerconstants.h"
 #include "projectnodes.h"
+#include "projectexplorer.h"
 
 #include <coreplugin/fileiconprovider.h>
 #include <utils/qtcassert.h>
@@ -68,7 +69,7 @@ bool sortNodes(Node *n1, Node *n2)
             const QString fileName2 = QFileInfo(file2->path()).fileName();
 
             if (fileName1 != fileName2)
-                return fileName1 < fileName2;
+                return fileName1.compare(fileName2, Qt::CaseInsensitive) < 0;
             else
                 return file1 < file2;
         } else {
@@ -87,7 +88,7 @@ bool sortNodes(Node *n1, Node *n2)
             ProjectNode *project2 = static_cast<ProjectNode*>(n2);
 
             if (project1->displayName() != project2->displayName())
-                return project1->displayName() < project2->displayName(); // sort by name
+                return project1->displayName().compare(project2->displayName(), Qt::CaseInsensitive) < 0; // sort by name
             else
                 return project1 < project2; // sort by pointer value
         } else {
@@ -103,7 +104,7 @@ bool sortNodes(Node *n1, Node *n2)
             FolderNode *folder2 = static_cast<FolderNode*>(n2);
 
             if (folder1->displayName() != folder2->displayName())
-                return folder1->displayName() < folder2->displayName();
+                return folder1->displayName().compare(folder2->displayName(), Qt::CaseInsensitive) < 0;
             else
                 return folder1 < folder2;
         } else {
@@ -122,10 +123,10 @@ bool sortNodes(Node *n1, Node *n2)
         const QString fileName2 = QFileInfo(filePath2).fileName();
 
         if (fileName1 != fileName2) {
-            return fileName1 < fileName2; // sort by file names
+            return fileName1.compare(fileName2, Qt::CaseInsensitive) < 0; // sort by file names
         } else {
             if (filePath1 != filePath2) {
-                return filePath1 < filePath2; // sort by path names
+                return filePath1.compare(filePath2, Qt::CaseInsensitive) < 0; // sort by path names
             } else {
                 return n1 < n2; // sort by pointer value
             }
@@ -261,6 +262,27 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const
     return result;
 }
 
+Qt::ItemFlags FlatModel::flags(const QModelIndex &index) const
+{
+    if (!index.isValid())
+        return 0;
+    // We claim that everything is editable
+    // That's slightly wrong
+    // We control the only view, and that one does the checks
+    return Qt::ItemIsSelectable|Qt::ItemIsEnabled | Qt::ItemIsEditable;
+}
+
+bool FlatModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+    if (!index.isValid())
+        return false;
+    if (role != Qt::EditRole)
+        return false;
+
+    ProjectExplorerPlugin::instance()->renameFile(nodeForIndex(index), value.toString());
+    return true;
+}
+
 int FlatModel::rowCount(const QModelIndex &parent) const
 {
     int rows = 0;
index 9943c00..810c6d5 100644 (file)
@@ -43,7 +43,8 @@ class SessionNode;
 
 namespace Internal {
 
-class FlatModel : public QAbstractItemModel {
+class FlatModel : public QAbstractItemModel
+{
     Q_OBJECT
 public:
     FlatModel(SessionNode *rootNode, QObject *parent);
@@ -52,6 +53,8 @@ public:
     QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const;
     QModelIndex parent(const QModelIndex &index) const;
     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+    Qt::ItemFlags flags(const QModelIndex &index) const;
+    bool setData(const QModelIndex &index, const QVariant &value, int role);
 
     int rowCount(const QModelIndex & parent = QModelIndex()) const;
     int columnCount(const QModelIndex & parent = QModelIndex()) const;
index d9cd9b1..04ad845 100644 (file)
@@ -313,8 +313,8 @@ void ProjectNode::addProjectNodes(const QList<ProjectNode*> &subProjects)
             emit watcher->foldersAboutToBeAdded(this, folderNodes);
 
         foreach (ProjectNode *project, subProjects) {
-            QTC_ASSERT(!project->parentFolderNode(),
-                qDebug("Project node has already a parent"));
+            QTC_ASSERT(!project->parentFolderNode() || project->parentFolderNode() == this,
+                       qDebug("Project node has already a parent"));
             project->setParentFolderNode(this);
             foreach (NodesWatcher *watcher, m_watchers)
                 project->registerWatcher(watcher);
index 64d49e4..3a4511e 100644 (file)
@@ -159,7 +159,8 @@ public:
         AddSubProject,
         RemoveSubProject,
         AddFile,
-        RemoveFile
+        RemoveFile,
+        Rename
     };
 
     // all subFolders that are projects
@@ -169,7 +170,7 @@ public:
     // TODO find a better name
     virtual bool hasBuildTargets() const = 0;
 
-    virtual QList<ProjectAction> supportedActions() const = 0;
+    virtual QList<ProjectAction> supportedActions(Node *node) const = 0;
 
     virtual bool addSubProjects(const QStringList &proFilePaths) = 0;
 
index b758aa9..33b59d6 100644 (file)
@@ -215,8 +215,8 @@ IRunControlFactory::~IRunControlFactory()
 {
 }
 
-RunControl::RunControl(RunConfiguration *runConfiguration)
-    : m_runConfiguration(runConfiguration)
+RunControl::RunControl(RunConfiguration *runConfiguration, QString mode)
+    : m_runMode(mode), m_runConfiguration(runConfiguration)
 {
     if (runConfiguration)
         m_displayName  = runConfiguration->displayName();
@@ -227,6 +227,11 @@ RunControl::~RunControl()
 
 }
 
+QString RunControl::runMode() const
+{
+    return m_runMode;
+}
+
 QString RunControl::displayName() const
 {
     return m_displayName;
index 86efaf6..486bc18 100644 (file)
@@ -160,7 +160,7 @@ class PROJECTEXPLORER_EXPORT RunControl : public QObject
 {
     Q_OBJECT
 public:
-    explicit RunControl(RunConfiguration *runConfiguration);
+    explicit RunControl(RunConfiguration *runConfiguration, QString mode);
     virtual ~RunControl();
     virtual void start() = 0;
     virtual void stop() = 0; // Warning: assumed to be synchroneous!
@@ -170,6 +170,7 @@ public:
     bool sameRunConfiguration(RunControl *other);
 
     virtual OutputFormatter *createOutputFormatter(QObject *parent = 0);
+    QString runMode() const;
 
 signals:
     void addToOutputWindow(RunControl *, const QString &line, bool onStdErr);
@@ -186,6 +187,7 @@ private slots:
 
 private:
     QString m_displayName;
+    QString m_runMode;
     const QWeakPointer<RunConfiguration> m_runConfiguration;
 
 #ifdef Q_OS_MAC
diff --git a/src/plugins/projectexplorer/runconfigurationmodel.cpp b/src/plugins/projectexplorer/runconfigurationmodel.cpp
new file mode 100644 (file)
index 0000000..f5fa969
--- /dev/null
@@ -0,0 +1,180 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "runconfigurationmodel.h"
+#include "target.h"
+#include "runconfiguration.h"
+
+using namespace ProjectExplorer;
+
+///
+/// RunConfigurationsModel
+///
+
+class RunConfigurationComparer
+{
+public:
+    bool operator()(RunConfiguration *a, RunConfiguration *b)
+    {
+        return a->displayName() < b->displayName();
+    }
+};
+
+RunConfigurationModel::RunConfigurationModel(Target *target, QObject *parent)
+    : QAbstractListModel(parent),
+      m_target(target)
+{
+    m_runConfigurations = m_target->runConfigurations();
+    qSort(m_runConfigurations.begin(), m_runConfigurations.end(), RunConfigurationComparer());
+
+    connect(target, SIGNAL(addedRunConfiguration(ProjectExplorer::RunConfiguration*)),
+            this, SLOT(addedRunConfiguration(ProjectExplorer::RunConfiguration*)));
+    connect(target, SIGNAL(removedRunConfiguration(ProjectExplorer::RunConfiguration*)),
+            this, SLOT(removedRunConfiguration(ProjectExplorer::RunConfiguration*)));
+
+    foreach (RunConfiguration *rc, m_runConfigurations)
+        connect(rc, SIGNAL(displayNameChanged()),
+                this, SLOT(displayNameChanged()));
+}
+
+int RunConfigurationModel::rowCount(const QModelIndex &parent) const
+{
+    return parent.isValid() ? 0 : m_runConfigurations.size();
+}
+
+int RunConfigurationModel::columnCount(const QModelIndex &parent) const
+{
+    return parent.isValid() ? 0 : 1;
+}
+
+void RunConfigurationModel::displayNameChanged()
+{
+    RunConfiguration *rc = qobject_cast<RunConfiguration *>(sender());
+    if (!rc)
+        return;
+
+    RunConfigurationComparer compare;
+    // Find the old position
+    int oldPos = m_runConfigurations.indexOf(rc);
+
+    if (oldPos >= 1 && compare(m_runConfigurations.at(oldPos), m_runConfigurations.at(oldPos - 1))) {
+        // We need to move up
+        int newPos = oldPos - 1;
+        while (newPos >= 0 && compare(m_runConfigurations.at(oldPos), m_runConfigurations.at(newPos))) {
+            --newPos;
+        }
+        ++newPos;
+
+        beginMoveRows(QModelIndex(), oldPos, oldPos, QModelIndex(), newPos);
+        m_runConfigurations.insert(newPos, rc);
+        m_runConfigurations.removeAt(oldPos + 1);
+        endMoveRows();
+        // Not only did we move, we also changed...
+        emit dataChanged(index(newPos, 0), index(newPos,0));
+    } else if  (oldPos < m_runConfigurations.size() - 1
+                && compare(m_runConfigurations.at(oldPos + 1), m_runConfigurations.at(oldPos))) {
+        // We need to move down
+        int newPos = oldPos + 1;
+        while (newPos < m_runConfigurations.size()
+            && compare(m_runConfigurations.at(newPos), m_runConfigurations.at(oldPos))) {
+            ++newPos;
+        }
+        beginMoveRows(QModelIndex(), oldPos, oldPos, QModelIndex(), newPos);
+        m_runConfigurations.insert(newPos, rc);
+        m_runConfigurations.removeAt(oldPos);
+        endMoveRows();
+
+        // We need to subtract one since removing at the old place moves the newIndex down
+        emit dataChanged(index(newPos - 1, 0), index(newPos - 1, 0));
+    } else {
+        emit dataChanged(index(oldPos, 0), index(oldPos, 0));
+    }
+}
+
+QVariant RunConfigurationModel::data(const QModelIndex &index, int role) const
+{
+    if (role == Qt::DisplayRole) {
+        const int row = index.row();
+        if (row < m_runConfigurations.size()) {
+            return m_runConfigurations.at(row)->displayName();
+        }
+    }
+
+    return QVariant();
+}
+
+RunConfiguration *RunConfigurationModel::runConfigurationAt(int i)
+{
+    if (i > m_runConfigurations.size() || i < 0)
+        return 0;
+    return m_runConfigurations.at(i);
+}
+
+RunConfiguration *RunConfigurationModel::runConfigurationFor(const QModelIndex &idx)
+{
+    if (idx.row() > m_runConfigurations.size() || idx.row() < 0)
+        return 0;
+    return m_runConfigurations.at(idx.row());
+}
+
+QModelIndex RunConfigurationModel::indexFor(RunConfiguration *rc)
+{
+    int idx = m_runConfigurations.indexOf(rc);
+    if (idx == -1)
+        return QModelIndex();
+    return index(idx, 0);
+}
+
+void RunConfigurationModel::addedRunConfiguration(ProjectExplorer::RunConfiguration *rc)
+{
+    // Find the right place to insert
+    RunConfigurationComparer compare;
+    int i = 0;
+    for (; i < m_runConfigurations.size(); ++i) {
+        if (compare(rc, m_runConfigurations.at(i))) {
+            break;
+        }
+    }
+
+    beginInsertRows(QModelIndex(), i, i);
+    m_runConfigurations.insert(i, rc);
+    endInsertRows();
+
+
+    connect(rc, SIGNAL(displayNameChanged()),
+            this, SLOT(displayNameChanged()));
+}
+
+void RunConfigurationModel::removedRunConfiguration(ProjectExplorer::RunConfiguration *rc)
+{
+    int i = m_runConfigurations.indexOf(rc);
+    beginRemoveRows(QModelIndex(), i, i);
+    m_runConfigurations.removeAt(i);
+    endRemoveRows();
+}
diff --git a/src/plugins/projectexplorer/runconfigurationmodel.h b/src/plugins/projectexplorer/runconfigurationmodel.h
new file mode 100644 (file)
index 0000000..2439167
--- /dev/null
@@ -0,0 +1,67 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef RUNCONFIGURATIONMODEL_H
+#define RUNCONFIGURATIONMODEL_H
+
+#include <QtCore/QAbstractItemModel>
+
+namespace ProjectExplorer {
+class Target;
+class RunConfiguration;
+
+/*! A model to represent the run configurations of a target.
+    To be used in for the drop down of comboboxes
+    Does automatically adjust itself to added and removed RunConfigurations
+*/
+class RunConfigurationModel : public QAbstractListModel
+{
+    Q_OBJECT
+public:
+    RunConfigurationModel(Target *target, QObject *parent = 0);
+
+    int rowCount(const QModelIndex &parent = QModelIndex()) const;
+    int columnCount(const QModelIndex &parent = QModelIndex()) const;
+    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+    RunConfiguration *runConfigurationAt(int i);
+    RunConfiguration *runConfigurationFor(const QModelIndex &idx);
+    QModelIndex indexFor(RunConfiguration *rc);
+private slots:
+    void addedRunConfiguration(ProjectExplorer::RunConfiguration*);
+    void removedRunConfiguration(ProjectExplorer::RunConfiguration*);
+    void displayNameChanged();
+private:
+    Target *m_target;
+    QList<RunConfiguration *> m_runConfigurations;
+};
+
+}
+
+#endif // RUNCONFIGURATIONMODEL_H
index 1c56ccb..624b623 100644 (file)
@@ -28,6 +28,7 @@
 **************************************************************************/
 
 #include "runsettingspropertiespage.h"
+#include "runconfigurationmodel.h"
 #include "runconfiguration.h"
 #include "target.h"
 #include "project.h"
@@ -116,110 +117,12 @@ QIcon RunSettingsPanel::icon() const
 }
 
 ///
-/// RunConfigurationsModel
-///
-
-RunConfigurationsModel::RunConfigurationsModel(Target *target, QObject *parent)
-    : QAbstractListModel(parent),
-      m_target(target)
-{
-    m_runConfigurations = m_target->runConfigurations();
-    connect(target, SIGNAL(addedRunConfiguration(ProjectExplorer::RunConfiguration*)),
-            this, SLOT(addedRunConfiguration(ProjectExplorer::RunConfiguration*)));
-    connect(target, SIGNAL(removedRunConfiguration(ProjectExplorer::RunConfiguration*)),
-            this, SLOT(removedRunConfiguration(ProjectExplorer::RunConfiguration*)));
-
-    foreach (RunConfiguration *rc, m_runConfigurations)
-        connect(rc, SIGNAL(displayNameChanged()),
-                this, SLOT(displayNameChanged()));
-}
-
-int RunConfigurationsModel::rowCount(const QModelIndex &parent) const
-{
-    return parent.isValid() ? 0 : m_runConfigurations.size();
-}
-
-int RunConfigurationsModel::columnCount(const QModelIndex &parent) const
-{
-    return parent.isValid() ? 0 : 1;
-}
-
-void RunConfigurationsModel::displayNameChanged()
-{
-    RunConfiguration *rc = qobject_cast<RunConfiguration *>(sender());
-    QTC_ASSERT(rc, return);
-    for (int i = 0; i < m_runConfigurations.size(); ++i) {
-        if (m_runConfigurations.at(i) == rc) {
-            emit dataChanged(index(i, 0), index(i,0));
-            break;
-        }
-    }
-}
-
-QVariant RunConfigurationsModel::data(const QModelIndex &index, int role) const
-{
-    if (role == Qt::DisplayRole) {
-        const int row = index.row();
-        if (row < m_runConfigurations.size()) {
-            return m_runConfigurations.at(row)->displayName();
-        }
-    }
-
-    return QVariant();
-}
-
-RunConfiguration *RunConfigurationsModel::runConfigurationAt(int i)
-{
-    if (i > m_runConfigurations.size() || i < 0)
-        return 0;
-    return m_runConfigurations.at(i);
-}
-
-RunConfiguration *RunConfigurationsModel::runConfigurationFor(const QModelIndex &idx)
-{
-    if (idx.row() > m_runConfigurations.size() || idx.row() < 0)
-        return 0;
-    return m_runConfigurations.at(idx.row());
-}
-
-QModelIndex RunConfigurationsModel::indexFor(RunConfiguration *rc)
-{
-    int idx = m_runConfigurations.indexOf(rc);
-    if (idx == -1)
-        return QModelIndex();
-    return index(idx, 0);
-}
-
-void RunConfigurationsModel::addedRunConfiguration(ProjectExplorer::RunConfiguration *rc)
-{
-    int i = m_target->runConfigurations().indexOf(rc);
-    QTC_ASSERT(i > 0, return);
-    beginInsertRows(QModelIndex(), i, i);
-    m_runConfigurations.insert(i, rc);
-    endInsertRows();
-    QTC_ASSERT(m_runConfigurations == m_target->runConfigurations(), return);
-    connect(rc, SIGNAL(displayNameChanged()),
-            this, SLOT(displayNameChanged()));
-}
-
-void RunConfigurationsModel::removedRunConfiguration(ProjectExplorer::RunConfiguration *rc)
-{
-    int i = m_runConfigurations.indexOf(rc);
-    QTC_ASSERT(i >= 0, return);
-    beginRemoveRows(QModelIndex(), i, i);
-    m_runConfigurations.removeAt(i);
-    endRemoveRows();
-    QTC_ASSERT(m_runConfigurations == m_target->runConfigurations(), return);
-}
-
-
-///
 /// RunSettingsWidget
 ///
 
 RunSettingsWidget::RunSettingsWidget(Target *target)
     : m_target(target),
-      m_runConfigurationsModel(new RunConfigurationsModel(target, this)),
+      m_runConfigurationsModel(new RunConfigurationModel(target, this)),
       m_runConfigurationWidget(0),
       m_ignoreChange(false)
 {
@@ -233,7 +136,7 @@ RunSettingsWidget::RunSettingsWidget(Target *target)
     m_ui->removeToolButton->setText(tr("Remove"));
     m_ui->runConfigurationCombo->setModel(m_runConfigurationsModel);
     m_ui->runConfigurationCombo->setCurrentIndex(
-            m_target->runConfigurations().indexOf(m_target->activeRunConfiguration()));
+            m_runConfigurationsModel->indexFor(m_target->activeRunConfiguration()).row());
 
     m_ui->removeToolButton->setEnabled(m_target->runConfigurations().size() > 1);
 
index 9393437..29eeb04 100644 (file)
@@ -43,6 +43,7 @@ QT_END_NAMESPACE
 namespace ProjectExplorer {
 
 class RunConfiguration;
+class RunConfigurationModel;
 
 namespace Internal {
 
@@ -52,7 +53,6 @@ namespace Ui {
 class RunSettingsPropertiesPage;
 }
 
-class RunConfigurationsModel;
 class RunSettingsWidget;
 
 class RunSettingsPanelFactory : public ITargetPanelFactory
@@ -94,38 +94,13 @@ private slots:
     void activeRunConfigurationChanged();
 private:
     Target *m_target;
-    RunConfigurationsModel *m_runConfigurationsModel;
+    RunConfigurationModel *m_runConfigurationsModel;
     Ui::RunSettingsPropertiesPage *m_ui;
     QWidget *m_runConfigurationWidget;
     QMenu *m_addMenu;
     bool m_ignoreChange;
 };
 
-/*! A model to represent the run configurations of a target. */
-class RunConfigurationsModel : public QAbstractListModel
-{
-    Q_OBJECT
-public:
-    RunConfigurationsModel(Target *target, QObject *parent = 0);
-
-    int rowCount(const QModelIndex &parent = QModelIndex()) const;
-    int columnCount(const QModelIndex &parent = QModelIndex()) const;
-    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
-
-    RunConfiguration *runConfigurationAt(int i);
-    RunConfiguration *runConfigurationFor(const QModelIndex &idx);
-    QModelIndex indexFor(RunConfiguration *rc);
-private slots:
-    void addedRunConfiguration(ProjectExplorer::RunConfiguration*);
-    void removedRunConfiguration(ProjectExplorer::RunConfiguration*);
-    void displayNameChanged();
-private:
-    Target *m_target;
-    QList<RunConfiguration *> m_runConfigurations;
-};
-
-
-
 } // namespace Internal
 } // namespace ProjectExplorer
 
index 8992c43..78d11fd 100644 (file)
@@ -68,7 +68,7 @@ namespace {
 namespace ProjectExplorer {
 namespace Internal {
 
-class SessionFile : public Core::IFile
+class SessionFile : QObject
 {
     Q_OBJECT
 
@@ -81,23 +81,10 @@ public:
     QString fileName() const;
     void setFileName(const QString &fileName);
 
-    QString defaultPath() const;
-    QString suggestedFileName() const;
-    virtual QString mimeType() const;
-
-    bool isModified() const;
-    bool isReadOnly() const;
-    bool isSaveAsAllowed() const;
-
-    ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
-    void reload(ReloadFlag flag, ChangeType type);
-
 public slots:
     void sessionLoadingProgress();
 
-
 private:
-    const QString m_mimeType;
     Core::ICore *m_core;
 
     QString m_fileName;
@@ -125,17 +112,11 @@ void SessionFile::sessionLoadingProgress()
 }
 
 SessionFile::SessionFile()
-  : m_mimeType(QLatin1String(ProjectExplorer::Constants::SESSIONFILE_MIMETYPE)),
-    m_core(Core::ICore::instance()),
+  : m_core(Core::ICore::instance()),
     m_startupProject(0)
 {
 }
 
-QString SessionFile::mimeType() const
-{
-    return m_mimeType;
-}
-
 bool SessionFile::load(const QString &fileName)
 {
     Q_ASSERT(!fileName.isEmpty());
@@ -306,53 +287,8 @@ void SessionFile::setFileName(const QString &fileName)
     m_fileName = fileName;
 }
 
-bool SessionFile::isModified() const
-{
-    return true;
-}
-
-bool SessionFile::isReadOnly() const
-{
-    return false;
-}
-
-bool SessionFile::isSaveAsAllowed() const
-{
-    return true;
-}
-
-Core::IFile::ReloadBehavior SessionFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
-{
-    Q_UNUSED(state)
-    Q_UNUSED(type)
-    return BehaviorSilent;
-}
-
-void SessionFile::reload(ReloadFlag flag, ChangeType type)
-{
-    Q_UNUSED(flag)
-    Q_UNUSED(type)
-}
-
-QString SessionFile::defaultPath() const
-{
-    if (!m_projects.isEmpty()) {
-        const QFileInfo fi(m_projects.first()->file()->fileName());
-        return fi.absolutePath();
-    }
-    return QString();
-}
-
-QString SessionFile::suggestedFileName() const
-{
-    if (m_startupProject)
-        return m_startupProject->displayName();
-
-    return tr("Untitled", "default file name to display");
-}
-
 Internal::SessionNodeImpl::SessionNodeImpl(SessionManager *manager)
-        : ProjectExplorer::SessionNode(manager->file()->fileName(), manager)
+        : ProjectExplorer::SessionNode(manager->currentSession(), manager)
 {
     setFileName("session");
 }
@@ -894,9 +830,9 @@ void SessionManager::setEditorCodec(Core::IEditor *editor, const QString &fileNa
             textEditor->setTextCodec(project->editorConfiguration()->defaultTextCodec());
 }
 
-Core::IFile *SessionManager::file() const
+QString SessionManager::currentSession() const
 {
-    return m_file;
+    return m_file->fileName();
 }
 
 void SessionManager::handleCurrentEditorChange(Core::IEditor *editor)
index 2e3aa0b..69992fb 100644 (file)
@@ -128,7 +128,7 @@ public:
     bool addDependency(Project *project, Project *depProject);
     void removeDependency(Project *project, Project *depProject);
 
-    Core::IFile *file() const;
+    QString currentSession() const;
     Project *startupProject() const;
 
     const QList<Project *> &projects() const;
index 0cf21a6..4c86df6 100644 (file)
 #include "target.h"
 #include "toolchain.h"
 
+#include <coreplugin/icore.h>
+#include <coreplugin/mainwindow.h>
 #include <coreplugin/ifile.h>
 #include <utils/qtcassert.h>
 
-#include <QtCore/QCoreApplication>
+#include <QtGui/QApplication>
 #include <QtCore/QFile>
+#include <QtGui/QMessageBox>
+#include <QtNetwork/QHostInfo>
 
 using namespace ProjectExplorer;
 
 namespace {
-const char * const USER_FILE_VERSION("ProjectExplorer.Project.Updater.FileVersion");
-const char * const WAS_UPDATED("ProjectExplorer.Project.Updater.DidUpdate");
+const char * const USER_FILE_VERSION  = "ProjectExplorer.Project.Updater.FileVersion";
+const char * const USER_FILE_HOSTNAME = "ProjectExplorer.Project.Updater.Hostname";
+const char * const WAS_UPDATED        = "ProjectExplorer.Project.Updater.DidUpdate";
 const char * const PROJECT_FILE_POSTFIX(".user");
 
 // Version 0 is used in Qt Creator 1.3.x and
@@ -225,7 +230,7 @@ QVariantMap UserFileAccessor::restoreSettings(Project *project)
     if (m_lastVersion < 0 || !project)
         return QVariantMap();
 
-    QString fileName(fileNameFor(project->file()->fileName()));
+    QString fileName = fileNameFor(project->file()->fileName());
     if (!QFile::exists(fileName))
         return QVariantMap();
 
@@ -235,12 +240,35 @@ QVariantMap UserFileAccessor::restoreSettings(Project *project)
     QVariantMap map(reader.restoreValues());
 
     // Get and verify file version:
-    const int fileVersion(map.value(QLatin1String(USER_FILE_VERSION), 0).toInt());
+    const int fileVersion = map.value(QLatin1String(USER_FILE_VERSION), 0).toInt();
     if (fileVersion < m_firstVersion || fileVersion > m_lastVersion + 1) {
         qWarning() << "File version" << fileVersion << "is not supported.";
         return QVariantMap();
     }
 
+    // Verify hostname
+    const QString hostname = map.value(QLatin1String(USER_FILE_HOSTNAME)).toString();
+    if (!hostname.isEmpty() && hostname != QHostInfo::localHostName()) {
+        // Ask the user
+        // TODO tr, casing check
+        QMessageBox msgBox(QMessageBox::Question,
+                           QApplication::translate("ProjectExplorer::UserFileAccessor",
+                                                   "Project Settings File from a different Host?"),
+                           QApplication::translate("ProjectExplorer::UserFileAccessor",
+                                                   "Qt Creator has found a .user settings file from a host %1. "
+                                                   "The hostname for this computer is %2. \n\n"
+                                                   "The .user settings files contain machine specific settings. "
+                                                   "They should not be copied to a different environment. \n\n"
+                                                   "Still load the settigns file?").arg(hostname, QHostInfo::localHostName()),
+                           QMessageBox::Yes | QMessageBox::No,
+                           Core::ICore::instance()->mainWindow());
+        msgBox.setDefaultButton(QMessageBox::No);
+        msgBox.setEscapeButton(QMessageBox::No);
+        int result = msgBox.exec();
+        if (result == QMessageBox::No)
+            return QVariantMap();
+    }
+
     // Do we need to do a update?
     if (fileVersion != m_lastVersion + 1) {
         map.insert(QLatin1String(WAS_UPDATED), true);
@@ -269,6 +297,7 @@ bool UserFileAccessor::saveSettings(Project *project, const QVariantMap &map)
         writer.saveValue(i.key(), i.value());
 
     writer.saveValue(QLatin1String(USER_FILE_VERSION), m_lastVersion + 1);
+    writer.saveValue(QLatin1String(USER_FILE_HOSTNAME), QHostInfo::localHostName());
 
     return writer.save(fileNameFor(project->file()->fileName()), "QtCreatorProject");
 }
index c855dc9..2f59fbd 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="QmlDesigner" version="1.3.84" compatVersion="1.3.84" experimental="true">
+<plugin name="QmlDesigner" version="2.0.80" compatVersion="2.0.80" experimental="true">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -20,8 +20,8 @@ will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.</license>
     <description>Visual Designer for QML files.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="Core" version="1.3.84"/>
-        <dependency name="TextEditor" version="1.3.84"/>
-        <dependency name="QmlJSEditor" version="1.3.84"/>
+        <dependency name="Core" version="2.0.80"/>
+        <dependency name="TextEditor" version="2.0.80"/>
+        <dependency name="QmlJSEditor" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 56d9948..3c718fd 100644 (file)
@@ -54,6 +54,8 @@ public:
 
     ModelNode resolveToModelNode() const;
     AbstractProperty resolveToProperty() const;
+    bool isList() const;
+    QList<ModelNode> resolveToModelNodeList() const;
 
 protected:
     BindingProperty(const QString &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view);
index c03f780..5d3ac3f 100644 (file)
@@ -68,6 +68,7 @@ public:
     QString scopeAndName(const QString &combiner = QString("::")) const;
     QList<QString> elementNames() const;
     int elementValue(const QString &enumeratorName) const;
+    QString valueToString(int value) const;
 
 private:
     void setScope(const QString &scope);
index 5dd0ca6..63d6517 100644 (file)
@@ -89,6 +89,8 @@ public:
 
     bool isAncestorOf(const QmlObjectNode &objectNode) const;
 
+    static  QVariant instanceValue(const ModelNode &modelNode, const QString &name);
+
 protected:
     NodeInstance nodeInstance() const;
     QmlObjectNode nodeForInstance(const NodeInstance &instance) const;
index e77e29c..017a0f3 100644 (file)
@@ -38,6 +38,7 @@ namespace QmlDesigner {
 
 class QmlModelView;
 class QmlModelStateGroup;
+class QmlObjectNode;
 
 class CORESHARED_EXPORT QmlModelState : public QmlModelNodeFacade
 {
@@ -59,6 +60,7 @@ public:
     void removePropertyChanges(const ModelNode &node);
 
     bool affectsModelNode(const ModelNode &node) const;
+    QList<QmlObjectNode> allAffectedNodes() const;
     QString name() const;
     void setName(const QString &name);
     bool isValid() const;
index 157ad96..3288f2e 100644 (file)
@@ -118,6 +118,11 @@ int EnumeratorMetaInfo::elementValue(const QString &enumeratorName) const
     return m_data->elements.value(unscoped, -1);
 }
 
+QString EnumeratorMetaInfo::valueToString(int value) const
+{
+    return m_data->elements.key(value);
+}
+
 void EnumeratorMetaInfo::setScope(const QString &scope)
 {
     Q_ASSERT(!scope.isEmpty());
index f7c24d7..b2affa6 100644 (file)
     <element name="NonModal" value="0" />
     <element name="ApplicationModal" value="2" />
   </enumerator>
+  <enumerator name="Type" scope="QEasingCurve">
+     <element name="Linear" value="0" />
+     <element name="InQuad" value="1" />
+     <element name="OutQuad" value="2" />
+     <element name="InOutQuad" value="3" />
+     <element name="OutInQuad" value="4" />
+     <element name="InCubic" value="5" />
+     <element name="OutCubic" value="6" />
+     <element name="InOutCubic" value="7" />
+     <element name="OutInCubic" value="8" />
+     <element name="InQuart" value="9" />
+     <element name="OutQuart" value="10" />
+     <element name="InOutQuart" value="11" />
+     <element name="OutInQuart" value="12" />
+     <element name="InQuint" value="13" />
+     <element name="OutQuint" value="14" />
+     <element name="InOutQuint" value="15" />
+     <element name="OutInQuint" value="16" />
+     <element name="InSine" value="17" />
+     <element name="OutSine" value="18" />
+     <element name="InOutSine" value="19" />
+     <element name="OutInSine" value="20" />
+     <element name="InExpo" value="21" />
+     <element name="OutExpo" value="22" />
+     <element name="InOutExpo" value="23" />
+     <element name="OutInExpo" value="24" />
+     <element name="InCirc" value="25" />
+     <element name="OutCirc" value="26" />
+     <element name="InOutCirc" value="27" />
+     <element name="OutInCirc" value="28" />
+     <element name="InElastic" value="29" />
+     <element name="OutElastic" value="30" />
+     <element name="InOutElastic" value="31" />
+     <element name="OutInElastic" value="32" />
+     <element name="InBack" value="33" />
+     <element name="OutBack" value="34" />
+     <element name="InOutBack" value="35" />
+     <element name="OutInBack" value="36" />
+     <element name="InBounce" value="37" />
+     <element name="OutBounce" value="38" />
+     <element name="InOutBounce" value="39" />
+     <element name="OutInBounce" value="40" />
+     <element name="InCurve" value="41" />
+     <element name="OutCurve" value="42" />
+     <element name="SineCurve" value="43" />
+     <element name="CosineCurve" value="44" />
+     <element name="Custom" value="45" />
+     <element name="NCurveTypes" value="46" />
+  </enumerator>
   <flag name="Alignment" scope="Qt">
     <element name="AlignLeft" value="1" />
     <element name="AlignTrailing" value="2" />
index 1d01df7..a16740c 100644 (file)
@@ -114,8 +114,8 @@ void MetaInfoPrivate::initialize()
 
     parseQmlTypes();
     parseNonQmlTypes();
-    parseValueTypes();
     parseXmlFiles();
+    parseValueTypes();
 
     m_isInitialized = true;
 }
@@ -154,9 +154,9 @@ void MetaInfoPrivate::parseProperties(NodeMetaInfo &nodeMetaInfo, const QMetaObj
         propertyInfo.setFlagType(qProperty.isFlagType());
 
         if (propertyInfo.isEnumType()) {
-            EnumeratorMetaInfo enumerator;
-
             QMetaEnum qEnumerator = qProperty.enumerator();
+            EnumeratorMetaInfo enumerator = m_q->addEnumerator(qEnumerator.scope(), qEnumerator.name());
+
             enumerator.setValid(qEnumerator.isValid());
             enumerator.setIsFlagType(qEnumerator.isFlag());
             enumerator.setScope(qEnumerator.scope());
@@ -167,6 +167,7 @@ void MetaInfoPrivate::parseProperties(NodeMetaInfo &nodeMetaInfo, const QMetaObj
             }
 
             propertyInfo.setEnumerator(enumerator);
+            
         }
 
         nodeMetaInfo.addProperty(propertyInfo);
@@ -241,7 +242,8 @@ void MetaInfoPrivate::parseValueTypes()
                << "QRectF"
                << "QSize"
                << "QSizeF"
-               << "QVector3D";
+               << "QVector3D"
+               << "QEasingCurve";
 
     foreach (const QString &type, valueTypes) {
         NodeMetaInfo nodeMetaInfo(*m_q);
@@ -269,6 +271,12 @@ void MetaInfoPrivate::parseValueTypes()
                 propertyInfo.setType("int");
             } else if (type == ("QRect")) {
                 propertyInfo.setType("int");
+            } else if (type == ("QEasingCurve")) {
+                if (propertyName == "type") {
+                    propertyInfo.setEnumType("true");
+                    propertyInfo.setType("QEasingCurve::Type");
+                    propertyInfo.setEnumerator(m_q->enumerator("QEasingCurve::Type"));
+                }
             }
             propertyInfo.setValid(true);
             propertyInfo.setReadable(true);
index 543cfc3..6fa866a 100644 (file)
@@ -230,7 +230,7 @@ QmlObjectNode AbstractProperty::parentQmlObjectNode() const
 */
 PropertyMetaInfo AbstractProperty::metaInfo() const
 {
-    return ModelNode(m_internalNode, m_model.data(), view()).metaInfo().property(m_propertyName);
+    return ModelNode(m_internalNode, m_model.data(), view()).metaInfo().property(m_propertyName, true);
 }
 
 /*!
index 6688f11..80295d3 100644 (file)
@@ -136,6 +136,16 @@ ModelNode BindingProperty::resolveToModelNode() const
     return resolveBinding(expression(), parentModelNode(), view());
 }
 
+static inline QStringList commaSeparatedSimplifiedStringList(const QString &string)
+{
+    QStringList stringList = string.split(QLatin1String(","));
+    QStringList simpleList;
+    foreach (const QString &simpleString, stringList)
+        simpleList.append(simpleString.simplified());
+    return simpleList;
+}
+
+
 AbstractProperty BindingProperty::resolveToProperty() const
 {
     if (!isValid())
@@ -159,6 +169,33 @@ AbstractProperty BindingProperty::resolveToProperty() const
         return AbstractProperty();
 }
 
+bool BindingProperty::isList() const
+{
+    if (!isValid())
+        throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
+
+    return expression().startsWith('[') && expression().endsWith(']');
+}
+
+QList<ModelNode> BindingProperty::resolveToModelNodeList() const
+{
+    QList<ModelNode> returnList;
+    if (!isValid())
+        throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
+    if (isList()) {
+        QString string = expression();
+        string.chop(1);
+        string.remove(0, 1);
+        QStringList simplifiedList = commaSeparatedSimplifiedStringList(string);
+        foreach (const QString &nodeId, simplifiedList) {
+            ModelNode modelNode = view()->modelNodeForId(nodeId);
+            if (modelNode.isValid())
+                returnList.append(modelNode);
+        }
+    }
+    return returnList;
+}
+
 void BindingProperty::setDynamicTypeNameAndExpression(const QString &typeName, const QString &expression)
 
 {
index ef88ccf..69a70cb 100644 (file)
@@ -93,9 +93,8 @@ instanciated instance of this object.
 
 */
 QVariant  QmlObjectNode::instanceValue(const QString &name) const
-{
-    Q_ASSERT(qmlModelView()->hasInstanceForModelNode(modelNode()));
-    return qmlModelView()->instanceForModelNode(modelNode()).property(name);
+{    
+    return instanceValue(modelNode(), name);
 }
 
 
@@ -378,6 +377,15 @@ bool QmlObjectNode::isAncestorOf(const QmlObjectNode &objectNode) const
     return modelNode().isAncestorOf(objectNode.modelNode());
 }
 
+QVariant QmlObjectNode::instanceValue(const ModelNode &modelNode, const QString &name)
+{
+    QmlModelView *modelView = qobject_cast<QmlModelView*>(modelNode.view());
+    if (!modelView)
+        throw new InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
+    Q_ASSERT(modelView->hasInstanceForModelNode(modelNode));
+    return modelView->instanceForModelNode(modelNode).property(name);
+}
+
 NodeInstance QmlObjectNode::nodeInstance() const
 {
     return qmlModelView()->nodeInstanceView()->instanceForNode(modelNode());
index 5b6109e..2c21384 100644 (file)
@@ -189,6 +189,9 @@ void QmlModelState::removePropertyChanges(const ModelNode &node)
 {
     //### exception if not valid
 
+    if (!isValid())
+        throw new InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
+
     if (isBaseState())
         return;
 
@@ -211,6 +214,19 @@ bool QmlModelState::affectsModelNode(const ModelNode &node) const
     return !stateOperations(node).isEmpty();
 }
 
+QList<QmlObjectNode> QmlModelState::allAffectedNodes() const
+{
+    QList<QmlObjectNode> returnList;
+
+    foreach (const ModelNode &childNode, modelNode().nodeListProperty("changes").toModelNodeList()) {
+        //### exception if not valid QmlModelStateOperation
+        if (QmlModelStateOperation(childNode).isValid() &&
+            !returnList.contains(QmlModelStateOperation(childNode).target()))
+            returnList.append(QmlModelStateOperation(childNode).target());
+    }
+    return returnList;
+}
+
 QString QmlModelState::name() const
 {
     if (isBaseState())
index 2405dbb..f4c4ef8 100644 (file)
@@ -38,6 +38,7 @@
 #include <QSize>
 #include <QSizeF>
 #include <QVector3D>
+#include <QEasingCurve>
 #include <QMetaProperty>
 
 namespace QmlDesigner {
@@ -114,6 +115,8 @@ VariantParser VariantParser::create(const QString &type)
         return VariantParser(QVariant(QRectF()));
     if (type == "QVector3D")
         return VariantParser(QVariant(QVector3D()));
+    if (type == "QEasingCurve")
+        return VariantParser(QVariant(QEasingCurve()));
 
     return VariantParser(QVariant());
 }
@@ -135,7 +138,9 @@ void VariantParser::init(const QString &type)
     if (type == "QRectF")
         m_valueType  = QDeclarativeValueTypeFactory::valueType(QVariant::RectF);
     if (type == "QVector3D")
-        m_valueType  = QDeclarativeValueTypeFactory::valueType(QVariant::Vector3D);
+        m_valueType  = QDeclarativeValueTypeFactory::valueType(QVariant::Vector3D);    
+    if (type == "QEasingCurve")
+        m_valueType  = QDeclarativeValueTypeFactory::valueType(QVariant::EasingCurve);
 }
 
 bool VariantParser::isValid()
index ffe1ad2..f2531d8 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="QmlInspector" version="1.3.84" compatVersion="1.3.84">
+<plugin name="QmlInspector" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -20,11 +20,11 @@ will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.</license>
     <description>Debugger for QML files</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="QmlProjectManager" version="1.3.84"/>
-        <dependency name="ProjectExplorer" version="1.3.84"/>
-        <dependency name="CppTools" version="1.3.84"/>
-        <dependency name="CppEditor" version="1.3.84"/>
-        <dependency name="Debugger" version="1.3.84"/>
-        <dependency name="QmlJSEditor" version="1.3.84"/>
+        <dependency name="QmlProjectManager" version="2.0.80"/>
+        <dependency name="ProjectExplorer" version="2.0.80"/>
+        <dependency name="CppTools" version="2.0.80"/>
+        <dependency name="CppEditor" version="2.0.80"/>
+        <dependency name="Debugger" version="2.0.80"/>
+        <dependency name="QmlJSEditor" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 5527b0f..abbf2aa 100644 (file)
@@ -43,25 +43,27 @@ void ObjectTreeItem::setHasValidDebugId(bool value)
 // *************************************************************************
 //  PropertiesViewItem
 // *************************************************************************
-PropertiesViewItem::PropertiesViewItem(QTreeWidget *widget, Type type)
-    : QTreeWidgetItem(widget), type(type)
+PropertiesViewItem::PropertiesViewItem(QTreeWidget *widget, int type)
+    : QTreeWidgetItem(widget, type), m_disabled(false)
 {
+
 }
 
-PropertiesViewItem::PropertiesViewItem(QTreeWidgetItem *parent, Type type)
-    : QTreeWidgetItem(parent), type(type)
+PropertiesViewItem::PropertiesViewItem(QTreeWidgetItem *parent, int type)
+    : QTreeWidgetItem(parent, type), m_disabled(false)
 {
 }
 
 QVariant PropertiesViewItem::data (int column, int role) const
 {
-    if (column == 1) {
-        if (role == Qt::ForegroundRole) {
-            bool canEdit = data(0, CanEditRole).toBool();
-            return canEdit ? qApp->palette().color(QPalette::Foreground) : qApp->palette().color(QPalette::Disabled, QPalette::Foreground);
-        }
+    if (role == Qt::ForegroundRole) {
+        bool makeDisabledColor = m_disabled;
+        if (column == 1 && !data(0, CanEditRole).toBool())
+            makeDisabledColor = true;
+        return makeDisabledColor ? qApp->palette().color(QPalette::Disabled, QPalette::Foreground) : qApp->palette().color(QPalette::Foreground);
     }
 
+
     return QTreeWidgetItem::data(column, role);
 }
 
@@ -79,7 +81,15 @@ QString PropertiesViewItem::objectIdString() const
 {
     return data(0, ObjectIdStringRole).toString();
 }
+void PropertiesViewItem::setWatchingDisabled(bool disabled)
+{
+    m_disabled = disabled;
+}
 
+bool PropertiesViewItem::isWatchingDisabled() const
+{
+    return m_disabled;
+}
 
 } // Internal
 } // Qml
index b09ff80..dbc0aaa 100644 (file)
@@ -28,25 +28,27 @@ class PropertiesViewItem : public QTreeWidgetItem
 {
 public:
     enum Type {
-        BindingType,
-        OtherType,
-        ClassType,
+        BindingType = QTreeWidgetItem::UserType,
+        OtherType = QTreeWidgetItem::UserType + 1,
+        ClassType = QTreeWidgetItem::UserType + 2
     };
     enum DataRoles {
-        CanEditRole = Qt::UserRole + 1,
-        ObjectIdStringRole = Qt::UserRole + 50,
-        ClassDepthRole = Qt::UserRole + 51
+        CanEditRole = Qt::UserRole,
+        ObjectIdStringRole = Qt::UserRole + 1,
+        ClassDepthRole = Qt::UserRole + 2
     };
 
-    PropertiesViewItem(QTreeWidget *widget, Type type = OtherType);
-    PropertiesViewItem(QTreeWidgetItem *parent, Type type = OtherType);
+    PropertiesViewItem(QTreeWidget *widget, int type = OtherType);
+    PropertiesViewItem(QTreeWidgetItem *parent, int type = OtherType);
     QVariant data (int column, int role) const;
     void setData (int column, int role, const QVariant & value);
-
+    void setWatchingDisabled(bool disabled);
+    bool isWatchingDisabled() const;
     QDeclarativeDebugPropertyReference property;
-    Type type;
+
 private:
     QString objectIdString() const;
+    bool m_disabled;
 
 };
 
index 17a98d2..b0d1b12 100644 (file)
@@ -187,11 +187,13 @@ void ObjectPropertiesView::queryFinished()
     setObject(obj);
 }
 
-void ObjectPropertiesView::setPropertyValue(PropertiesViewItem *item, const QVariant &value, bool makeGray)
+void ObjectPropertiesView::setPropertyValue(PropertiesViewItem *item, const QVariant &value, bool isDisabled)
 {
+    item->setWatchingDisabled(isDisabled);
+
     if (value.type() == QVariant::List || value.type() == QVariant::StringList) {
         PropertiesViewItem *bindingItem = static_cast<PropertiesViewItem*>(item->takeChild(item->childCount() - 1));
-        if (bindingItem && bindingItem->type != PropertiesViewItem::BindingType) {
+        if (bindingItem && bindingItem->type() != PropertiesViewItem::BindingType) {
             delete bindingItem;
             bindingItem = 0;
         }
@@ -205,7 +207,7 @@ void ObjectPropertiesView::setPropertyValue(PropertiesViewItem *item, const QVar
         PropertiesViewItem *child;
         for (int i=0; i<variants.count(); ++i) {
             child = new PropertiesViewItem(item);
-            setPropertyValue(child, variants[i], makeGray);
+            setPropertyValue(child, variants[i], isDisabled);
         }
 
         if (bindingItem)
@@ -217,10 +219,6 @@ void ObjectPropertiesView::setPropertyValue(PropertiesViewItem *item, const QVar
         item->setExpanded(true);
     }
 
-    if (makeGray) {
-        for (int i=0; i<m_tree->columnCount(); ++i)
-            item->setForeground(i, Qt::gray);
-    }
 }
 
 QString ObjectPropertiesView::propertyBaseClass(const QDeclarativeDebugObjectReference &object, const QDeclarativeDebugPropertyReference &property, int &depth)
@@ -483,20 +481,29 @@ void ObjectPropertiesView::contextMenuEvent(QContextMenuEvent *event)
 {
     m_clickedItem = m_tree->itemAt(QPoint(event->pos().x(),
                                           event->pos().y() - m_tree->header()->height()));
+
     if (!m_clickedItem)
         return;
 
     PropertiesViewItem *propItem = static_cast<PropertiesViewItem *>(m_clickedItem);
 
+    bool isWatchableItem = propItem->type() != PropertiesViewItem::ClassType &&
+                    propItem->type() != PropertiesViewItem::BindingType;
+
     QMenu menu;
-    if (!isWatched(m_clickedItem)) {
-        m_addWatchAction->setText(tr("Watch expression '%1'").arg(propItem->property.name()));
-        menu.addAction(m_addWatchAction);
-    } else {
-        menu.addAction(m_removeWatchAction);
+    if (isWatchableItem) {
+        if (!isWatched(m_clickedItem)) {
+            m_addWatchAction->setText(tr("Watch expression '%1'").arg(propItem->property.name()));
+            m_addWatchAction->setDisabled(propItem->isWatchingDisabled());
+            menu.addAction(m_addWatchAction);
+        } else {
+            menu.addAction(m_removeWatchAction);
+            m_addWatchAction->setDisabled(propItem->isWatchingDisabled());
+        }
     }
     menu.addSeparator();
 
+
     if (m_showUnwatchableProperties)
         m_toggleUnwatchablePropertiesAction->setText(tr("Hide unwatchable properties"));
     else
index c4e7e28..b86ef9d 100644 (file)
@@ -90,7 +90,7 @@ private:
     void setObject(const QDeclarativeDebugObjectReference &object);
     bool isWatched(QTreeWidgetItem *item);
     void setWatched(const QString &property, bool watched);
-    void setPropertyValue(PropertiesViewItem *item, const QVariant &value, bool makeGray);
+    void setPropertyValue(PropertiesViewItem *item, const QVariant &value, bool isDisabled);
 
     QDeclarativeEngineDebug *m_client;
     QDeclarativeDebugObjectQuery *m_query;
index f5f242c..8ab4e72 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="QmlJSEditor" version="1.3.84" compatVersion="1.3.84">
+<plugin name="QmlJSEditor" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,8 +14,8 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Editor for QML and JavaScript.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="Core" version="1.3.84"/>
-        <dependency name="TextEditor" version="1.3.84"/>
-        <dependency name="ProjectExplorer" version="1.3.84"/>
+        <dependency name="Core" version="2.0.80"/>
+        <dependency name="TextEditor" version="2.0.80"/>
+        <dependency name="ProjectExplorer" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 685d7bb..0e4cf83 100644 (file)
@@ -44,6 +44,7 @@ Highlighter::Highlighter(QTextDocument *parent)
 {
     m_currentBlockParentheses.reserve(20);
     m_braceDepth = 0;
+    m_foldingIndent = 0;
 }
 
 Highlighter::~Highlighter()
@@ -102,27 +103,27 @@ void Highlighter::highlightBlock(const QString &text)
                 break;
 
             case Token::LeftParenthesis:
-                onOpeningParenthesis('(', token.offset);
+                onOpeningParenthesis('(', token.offset, index == 0);
                 break;
 
             case Token::RightParenthesis:
-                onClosingParenthesis(')', token.offset);
+                onClosingParenthesis(')', token.offset, index == tokens.size()-1);
                 break;
 
             case Token::LeftBrace:
-                onOpeningParenthesis('{', token.offset);
+                onOpeningParenthesis('{', token.offset, index == 0);
                 break;
 
             case Token::RightBrace:
-                onClosingParenthesis('}', token.offset);
+                onClosingParenthesis('}', token.offset, index == tokens.size()-1);
                 break;
 
             case Token::LeftBracket:
-                onOpeningParenthesis('[', token.offset);
+                onOpeningParenthesis('[', token.offset, index == 0);
                 break;
 
             case Token::RightBracket:
-                onClosingParenthesis(']', token.offset);
+                onClosingParenthesis(']', token.offset, index == tokens.size()-1);
                 break;
 
             case Token::Identifier: {
@@ -232,12 +233,8 @@ void Highlighter::highlightBlock(const QString &text)
 
     setFormat(previousTokenEnd, text.length() - previousTokenEnd, m_formats[VisualWhitespace]);
 
-    int firstNonSpace = 0;
-    if (! tokens.isEmpty())
-        firstNonSpace = tokens.first().offset;
-
     setCurrentBlockState(m_scanner.state());
-    onBlockEnd(m_scanner.state(), firstNonSpace);
+    onBlockEnd(m_scanner.state());
 }
 
 bool Highlighter::maybeQmlKeyword(const QStringRef &text) const
@@ -301,6 +298,12 @@ int Highlighter::onBlockStart()
 {
     m_currentBlockParentheses.clear();
     m_braceDepth = 0;
+    m_foldingIndent = 0;
+    if (TextEditor::TextBlockUserData *userData = TextEditor::BaseTextDocumentLayout::testUserData(currentBlock())) {
+        userData->setFoldingIndent(0);
+        userData->setFoldingStartIncluded(false);
+        userData->setFoldingEndIncluded(false);
+    }
 
     int state = 0;
     int previousState = previousBlockState();
@@ -308,56 +311,41 @@ int Highlighter::onBlockStart()
         state = previousState & 0xff;
         m_braceDepth = previousState >> 8;
     }
+    m_foldingIndent = m_braceDepth;
 
     return state;
 }
 
-void Highlighter::onBlockEnd(int state, int firstNonSpace)
+void Highlighter::onBlockEnd(int state)
 {
     typedef TextEditor::TextBlockUserData TextEditorBlockData;
 
     setCurrentBlockState((m_braceDepth << 8) | state);
-
-    // Set block data parentheses. Force creation of block data unless empty
-    TextEditorBlockData *blockData = 0;
-
-    if (QTextBlockUserData *userData = currentBlockUserData())
-        blockData = static_cast<TextEditorBlockData *>(userData);
-
-    if (!blockData && !m_currentBlockParentheses.empty()) {
-        blockData = new TextEditorBlockData;
-        setCurrentBlockUserData(blockData);
-    }
-    if (blockData) {
-        blockData->setParentheses(m_currentBlockParentheses);
-        blockData->setClosingCollapseMode(TextEditor::TextBlockUserData::NoClosingCollapse);
-        blockData->setCollapseMode(TextEditor::TextBlockUserData::NoCollapse);
-    }
-    if (!m_currentBlockParentheses.isEmpty()) {
-        QTC_ASSERT(blockData, return);
-        int collapse = Parenthesis::collapseAtPos(m_currentBlockParentheses);
-        if (collapse >= 0) {
-            if (collapse == firstNonSpace)
-                blockData->setCollapseMode(TextEditor::TextBlockUserData::CollapseThis);
-            else
-                blockData->setCollapseMode(TextEditor::TextBlockUserData::CollapseAfter);
-        }
-        if (Parenthesis::hasClosingCollapse(m_currentBlockParentheses))
-            blockData->setClosingCollapseMode(TextEditor::TextBlockUserData::NoClosingCollapse);
-    }
+    TextEditor::BaseTextDocumentLayout::setParentheses(currentBlock(), m_currentBlockParentheses);
+    TextEditor::BaseTextDocumentLayout::setFoldingIndent(currentBlock(), m_foldingIndent);
 }
 
-void Highlighter::onOpeningParenthesis(QChar parenthesis, int pos)
+void Highlighter::onOpeningParenthesis(QChar parenthesis, int pos, bool atStart)
 {
-    if (parenthesis == QLatin1Char('{') || parenthesis == QLatin1Char('['))
+    if (parenthesis == QLatin1Char('{') || parenthesis == QLatin1Char('[')) {
         ++m_braceDepth;
+        // if a folding block opens at the beginning of a line, treat the entire line
+        // as if it were inside the folding block
+        if (atStart)
+            TextEditor::BaseTextDocumentLayout::userData(currentBlock())->setFoldingStartIncluded(true);
+    }
     m_currentBlockParentheses.push_back(Parenthesis(Parenthesis::Opened, parenthesis, pos));
 }
 
-void Highlighter::onClosingParenthesis(QChar parenthesis, int pos)
+void Highlighter::onClosingParenthesis(QChar parenthesis, int pos, bool atEnd)
 {
-    if (parenthesis == QLatin1Char('}') || parenthesis == QLatin1Char(']'))
+    if (parenthesis == QLatin1Char('}') || parenthesis == QLatin1Char(']')) {
         --m_braceDepth;
+        if (atEnd)
+            TextEditor::BaseTextDocumentLayout::userData(currentBlock())->setFoldingEndIncluded(true);
+        else
+            m_foldingIndent = qMin(m_braceDepth, m_foldingIndent); // folding indent is the minimum brace depth of a block
+    }
     m_currentBlockParentheses.push_back(Parenthesis(Parenthesis::Closed, parenthesis, pos));
 }
 
index 974bbe9..cf59f5d 100644 (file)
@@ -78,12 +78,12 @@ protected:
     virtual void highlightBlock(const QString &text);
 
     int onBlockStart();
-    void onBlockEnd(int state, int firstNonSpace);
+    void onBlockEnd(int state);
 
     // The functions are notified whenever parentheses are encountered.
     // Custom behaviour can be added, for example storing info for indenting.
-    void onOpeningParenthesis(QChar parenthesis, int pos);
-    void onClosingParenthesis(QChar parenthesis, int pos);
+    void onOpeningParenthesis(QChar parenthesis, int pos, bool atStart);
+    void onClosingParenthesis(QChar parenthesis, int pos, bool atEnd);
 
     bool maybeQmlKeyword(const QStringRef &text) const;
     bool maybeQmlBuiltinType(const QStringRef &text) const;
@@ -94,6 +94,7 @@ private:
 
     bool m_qmlEnabled;
     int m_braceDepth;
+    int m_foldingIndent;
 
     QmlJS::Scanner m_scanner;
     Parentheses m_currentBlockParentheses;
index a1b7438..c6481be 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="QmlProjectManager" version="1.3.84" compatVersion="1.3.84">
+<plugin name="QmlProjectManager" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,9 +14,9 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Qt Quick support</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="ProjectExplorer" version="1.3.84"/>
-        <dependency name="TextEditor" version="1.3.84"/>
-        <dependency name="QmlJSEditor" version="1.3.84"/>
-        <dependency name="Debugger" version="1.3.84" />
+        <dependency name="ProjectExplorer" version="2.0.80"/>
+        <dependency name="TextEditor" version="2.0.80"/>
+        <dependency name="QmlJSEditor" version="2.0.80"/>
+        <dependency name="Debugger" version="2.0.80" />
     </dependencyList>
 </plugin>
index 3bc8278..c3f3025 100644 (file)
@@ -48,6 +48,13 @@ bool QmlProjectFile::save(const QString &)
     return false;
 }
 
+void QmlProjectFile::rename(const QString &newName)
+{
+    // Can't happen...
+    Q_UNUSED(newName);
+    Q_ASSERT(false);
+}
+
 QString QmlProjectFile::fileName() const
 {
     return m_fileName;
index b01c4f7..4a493b8 100644 (file)
@@ -48,6 +48,7 @@ public:
 
     virtual bool save(const QString &fileName = QString());
     virtual QString fileName() const;
+    virtual void rename(const QString &newName);
 
     virtual QString defaultPath() const;
     virtual QString suggestedFileName() const;
index 2569b5a..3131166 100644 (file)
@@ -172,8 +172,9 @@ bool QmlProjectNode::hasBuildTargets() const
     return true;
 }
 
-QList<ProjectExplorer::ProjectNode::ProjectAction> QmlProjectNode::supportedActions() const
+QList<ProjectExplorer::ProjectNode::ProjectAction> QmlProjectNode::supportedActions(Node *node) const
 {
+    Q_UNUSED(node);
     QList<ProjectAction> actions;
     actions.append(AddFile);
     return actions;
index 19adf63..60285ce 100644 (file)
@@ -56,7 +56,7 @@ public:
 
     virtual bool hasBuildTargets() const;
 
-    virtual QList<ProjectExplorer::ProjectNode::ProjectAction> supportedActions() const;
+    virtual QList<ProjectExplorer::ProjectNode::ProjectAction> supportedActions(Node *node) const;
 
     virtual bool addSubProjects(const QStringList &proFilePaths);
     virtual bool removeSubProjects(const QStringList &proFilePaths);
index de6e9bb..9d3cbbd 100644 (file)
@@ -52,11 +52,11 @@ using ProjectExplorer::RunControl;
 namespace QmlProjectManager {
 namespace Internal {
 
-QmlRunControl::QmlRunControl(QmlProjectRunConfiguration *runConfiguration, bool debugMode)
-    : RunControl(runConfiguration), m_debugMode(debugMode)
+QmlRunControl::QmlRunControl(QmlProjectRunConfiguration *runConfiguration, QString mode)
+    : RunControl(runConfiguration, mode)
 {
     ProjectExplorer::Environment environment = ProjectExplorer::Environment::systemEnvironment();
-    if (debugMode)
+    if (runMode() == ProjectExplorer::Constants::DEBUGMODE)
         environment.set(QmlProjectManager::Constants::E_QML_DEBUG_SERVER_PORT, QString::number(runConfiguration->debugServerPort()));
 
     m_applicationLauncher.setEnvironment(environment.toStringList());
@@ -121,7 +121,7 @@ void QmlRunControl::slotError(const QString &err, bool isError)
 
 void QmlRunControl::slotAddToOutputWindow(const QString &line, bool onStdErr)
 {
-    if (m_debugMode && line.startsWith("QDeclarativeDebugServer: Waiting for connection")) {
+    if (runMode() == ProjectExplorer::Constants::DEBUGMODE && line.startsWith("QDeclarativeDebugServer: Waiting for connection")) {
         Core::ICore *core = Core::ICore::instance();
         core->modeManager()->activateMode(Debugger::Constants::MODE_DEBUG);
     }
@@ -155,8 +155,7 @@ RunControl *QmlRunControlFactory::create(RunConfiguration *runConfiguration,
                                          const QString &mode)
 {
     QTC_ASSERT(canRun(runConfiguration, mode), return 0);
-    return new QmlRunControl(qobject_cast<QmlProjectRunConfiguration *>(runConfiguration),
-                             mode == ProjectExplorer::Constants::DEBUGMODE);
+    return new QmlRunControl(qobject_cast<QmlProjectRunConfiguration *>(runConfiguration), mode);
 }
 
 QString QmlRunControlFactory::displayName() const
index d6fe7e1..89d0d7d 100644 (file)
@@ -39,10 +39,11 @@ class QmlProjectRunConfiguration;
 
 namespace Internal {
 
-class QmlRunControl : public ProjectExplorer::RunControl {
+class QmlRunControl : public ProjectExplorer::RunControl
+{
     Q_OBJECT
 public:
-    explicit QmlRunControl(QmlProjectRunConfiguration *runConfiguration, bool debugMode);
+    explicit QmlRunControl(QmlProjectRunConfiguration *runConfiguration, QString mode);
     virtual ~QmlRunControl ();
 
     // RunControl
@@ -63,7 +64,6 @@ private:
 
     QString m_executable;
     QStringList m_commandLineArguments;
-    bool m_debugMode;
 };
 
 class QmlRunControlFactory : public ProjectExplorer::IRunControlFactory {
index ca250fa..91bf0fb 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="Qt4ProjectManager" version="1.3.84" compatVersion="1.3.84">
+<plugin name="Qt4ProjectManager" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,12 +14,12 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Provides project type for Qt 4 pro files and tools.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="TextEditor" version="1.3.84"/>
-        <dependency name="ProjectExplorer" version="1.3.84"/>
-        <dependency name="CppTools" version="1.3.84"/>
-        <dependency name="CppEditor" version="1.3.84"/>
-        <dependency name="Help" version="1.3.84"/>
-        <dependency name="Designer" version="1.3.84"/>
-        <dependency name="Debugger" version="1.3.84"/>
+        <dependency name="TextEditor" version="2.0.80"/>
+        <dependency name="ProjectExplorer" version="2.0.80"/>
+        <dependency name="CppTools" version="2.0.80"/>
+        <dependency name="CppEditor" version="2.0.80"/>
+        <dependency name="Help" version="2.0.80"/>
+        <dependency name="Designer" version="2.0.80"/>
+        <dependency name="Debugger" version="2.0.80"/>
     </dependencyList>
 </plugin>
index bfc1e54..9b42e38 100644 (file)
@@ -117,10 +117,10 @@ QStringList QMakeStep::allArguments()
         // This is a HACK, remove once the symbian make generator supports
         // shadow building
         arguments << QLatin1String("-after")
-                  << QLatin1String("OBJECTS_DIR=.obj")
-                  << QLatin1String("MOC_DIR=.moc")
-                  << QLatin1String("UI_DIR=.ui")
-                  << QLatin1String("RCC_DIR=.rcc");
+                  << QLatin1String("OBJECTS_DIR=obj")
+                  << QLatin1String("MOC_DIR=moc")
+                  << QLatin1String("UI_DIR=ui")
+                  << QLatin1String("RCC_DIR=rcc");
     }
 
     // Find out what flags we pass on to qmake
index 583552a..1185eaf 100644 (file)
@@ -33,6 +33,8 @@
 #include "maemotoolchain.h"
 
 #include <qt4projectmanager/qt4buildconfiguration.h>
+#include <qt4projectmanager/qt4project.h>
+#include <qt4projectmanager/qt4target.h>
 
 #include <QtCore/QDir>
 #include <QtCore/QFileInfo>
@@ -176,8 +178,14 @@ void MaemoPackageContents::fromMap(const QVariantMap &map)
 QString MaemoPackageContents::remoteExecutableFilePath() const
 {
     if (m_remoteExecutableFilePath.isEmpty()) {
-        m_remoteExecutableFilePath = QLatin1String("/usr/local/bin/")
-                                     + m_packageStep->executableFileName();
+        const Qt4ProjectType projectType
+            = m_packageStep->qt4BuildConfiguration()->qt4Target()->qt4Project()
+              ->rootProjectNode()->projectType();
+        const QString remoteDir = projectType == LibraryTemplate
+            ? QLatin1String("/usr/local/lib/")
+            : QLatin1String("/usr/local/bin/");
+        m_remoteExecutableFilePath
+            = remoteDir + m_packageStep->executableFileName();
     }
     return m_remoteExecutableFilePath;
 }
index c43a2f1..ee133b8 100644 (file)
@@ -262,14 +262,22 @@ QString MaemoPackageCreationStep::localExecutableFilePath() const
         ->qt4Project()->rootProjectNode()->targetInformation();
     if (!ti.valid)
         return QString();
-
     return QDir::toNativeSeparators(QDir::cleanPath(ti.workingDir
-        + QLatin1Char('/') + ti.target));
+        + QLatin1Char('/') + executableFileName()));
 }
 
 QString MaemoPackageCreationStep::executableFileName() const
 {
-    return QFileInfo(localExecutableFilePath()).fileName();
+    const Qt4Project * const project
+        = qt4BuildConfiguration()->qt4Target()->qt4Project();
+    const TargetInformation &ti
+        = project->rootProjectNode()->targetInformation();
+    if (!ti.valid)
+        return QString();
+
+    return project->rootProjectNode()->projectType() == LibraryTemplate
+        ? QLatin1String("lib") + ti.target + QLatin1String(".so")
+        : ti.target;
 }
 
 const MaemoToolChain *MaemoPackageCreationStep::maemoToolChain() const
index 60f2bbc..f0945db 100644 (file)
@@ -67,6 +67,7 @@ public:
     QString localExecutableFilePath() const;
     QString executableFileName() const;
     MaemoPackageContents *packageContents() const { return m_packageContents; }
+    const Qt4BuildConfiguration *qt4BuildConfiguration() const;
 
 private:
     MaemoPackageCreationStep(ProjectExplorer::BuildConfiguration *buildConfig,
@@ -81,7 +82,6 @@ private:
 
     bool createPackage();
     bool runCommand(QProcess &proc, const QString &command);
-    const Qt4BuildConfiguration *qt4BuildConfiguration() const;
     const MaemoToolChain *maemoToolChain() const;
     QString maddeRoot() const;
     QString targetRoot() const;
index bf00f03..0b331f3 100644 (file)
@@ -222,26 +222,6 @@ MaemoDeviceConfig MaemoRunConfiguration::deviceConfig() const
     return m_devConfig;
 }
 
-const QString MaemoRunConfiguration::sshCmd() const
-{
-    return cmd(QString::fromLocal8Bit("ssh"));
-}
-
-const QString MaemoRunConfiguration::scpCmd() const
-{
-    return cmd(QString::fromLocal8Bit("scp"));
-}
-
-const QString MaemoRunConfiguration::cmd(const QString &cmdName) const
-{
-    QString command(cmdName);
-#ifdef Q_OS_WIN
-    command = maddeRoot() + QLatin1String("/bin/") + command
-          + QLatin1String(".exe");
-#endif
-    return command;
-}
-
 const MaemoToolChain *MaemoRunConfiguration::toolchain() const
 {
     Qt4BuildConfiguration *qt4bc(activeQt4BuildConfiguration());
index 2b7c9e4..5542989 100644 (file)
@@ -88,8 +88,11 @@ public:
     MaemoDeviceConfig deviceConfig() const;
     QString runtimeGdbServerPort() const;
 
+<<<<<<< HEAD
+=======
     const QString sshCmd() const;
     const QString scpCmd() const;
+>>>>>>> origin/2.0
     const QString gdbCmd() const;
     const QString dumperLib() const;
 
@@ -110,7 +113,10 @@ private slots:
 
 private:
     void init();
+<<<<<<< HEAD
+=======
     const QString cmd(const QString &cmdName) const;
+>>>>>>> origin/2.0
     const MaemoToolChain *toolchain() const;
     bool fileNeedsDeployment(const QString &path, const QDateTime &lastDeployed) const;
     void addDeployTimesToMap(const QString &key,
index ee08c98..44b1bea 100644 (file)
@@ -45,6 +45,7 @@
 #include <extensionsystem/pluginmanager.h>
 #include <projectexplorer/toolchain.h>
 #include <utils/qtcassert.h>
+#include <projectexplorer/projectexplorerconstants.h>
 
 #include <QtCore/QDir>
 #include <QtCore/QFileInfo>
 namespace Qt4ProjectManager {
 namespace Internal {
 
+#define USE_GDBSERVER
+
 using ProjectExplorer::RunConfiguration;
 using ProjectExplorer::ToolChain;
 
-AbstractMaemoRunControl::AbstractMaemoRunControl(RunConfiguration *rc)
-    : RunControl(rc)
+AbstractMaemoRunControl::AbstractMaemoRunControl(RunConfiguration *rc, QString mode)
+    : RunControl(rc, mode)
     , m_runConfig(qobject_cast<MaemoRunConfiguration *>(rc))
     , m_devConfig(m_runConfig ? m_runConfig->deviceConfig() : MaemoDeviceConfig())
 {
@@ -107,7 +110,7 @@ void AbstractMaemoRunControl::handleInitialCleanupFinished()
         emit appendMessage(this, tr("Initial cleanup canceled by user."), false);
         emit finished();
     } else if (m_initialCleaner->hasError()) {
-        handleError(tr("Error running initial cleanup: %1.")
+        handleError(tr("Error running initial cleanup: %1")
                     .arg(m_initialCleaner->error()));
         emit finished();
     } else {
@@ -131,7 +134,7 @@ void AbstractMaemoRunControl::startDeployment(bool forDebugging)
             m_needsInstall = true;
         } else {
             m_needsInstall = false;
-        }
+        }        
         if (forDebugging
             && m_runConfig->debuggingHelpersNeedDeployment(m_devConfig.server.host)) {
             const QFileInfo &info(m_runConfig->dumperLib());
@@ -285,7 +288,7 @@ void AbstractMaemoRunControl::handleRunThreadFinished()
         emit appendMessage(this,
                  tr("Remote execution canceled due to user request."),
                  false);
-    } else if (m_sshRunner->hasError()) {
+    } else if (m_sshRunner && m_sshRunner->hasError()) {
         emit appendMessage(this, tr("Error running remote process: %1")
                                          .arg(m_sshRunner->error()),
                                true);
@@ -344,7 +347,7 @@ void AbstractMaemoRunControl::handleError(const QString &errString)
 
 
 MaemoRunControl::MaemoRunControl(RunConfiguration *runConfiguration)
-    : AbstractMaemoRunControl(runConfiguration)
+    : AbstractMaemoRunControl(runConfiguration, ProjectExplorer::Constants::RUNMODE)
 {
 }
 
@@ -376,28 +379,42 @@ void MaemoRunControl::handleRemoteOutput(const QString &output)
 
 
 MaemoDebugRunControl::MaemoDebugRunControl(RunConfiguration *runConfiguration)
-    : AbstractMaemoRunControl(runConfiguration)
+    : AbstractMaemoRunControl(runConfiguration, ProjectExplorer::Constants::DEBUGMODE)
     , m_debuggerManager(ExtensionSystem::PluginManager::instance()
                       ->getObject<Debugger::DebuggerManager>())
     , m_startParams(new Debugger::DebuggerStartParameters)
 {
     QTC_ASSERT(m_debuggerManager != 0, return);
-    m_startParams->startMode = Debugger::StartRemote;
+#ifdef USE_GDBSERVER
+    m_startParams->startMode = Debugger::AttachToRemote;
     m_startParams->executable = executableOnHost();
+    m_startParams->debuggerCommand = m_runConfig->gdbCmd();
     m_startParams->remoteChannel
         = m_devConfig.server.host % QLatin1Char(':') % gdbServerPort();
     m_startParams->remoteArchitecture = QLatin1String("arm");
+#else
+    m_startParams->startMode = Debugger::StartRemoteGdb;
+    m_startParams->executable = executableFilePathOnTarget();
+    m_startParams->debuggerCommand = QLatin1String("/usr/bin/gdb");
+    m_startParams->sshserver = m_devConfig.server;
+#endif
+    m_startParams->processArgs = m_runConfig->arguments();
     m_startParams->sysRoot = m_runConfig->sysRoot();
     m_startParams->toolChainType = ToolChain::GCC_MAEMO;
-    m_startParams->debuggerCommand = m_runConfig->gdbCmd();
     m_startParams->dumperLibrary = m_runConfig->dumperLib();
-    m_startParams->remoteDumperLib = QString::fromLocal8Bit("%1/%2")
-        .arg(remoteDir()).arg(QFileInfo(m_runConfig->dumperLib()).fileName());
+    m_startParams->remoteDumperLib = remoteDir().toUtf8() + '/'
+        + QFileInfo(m_runConfig->dumperLib()).fileName().toUtf8();
 
     connect(m_debuggerManager, SIGNAL(debuggingFinished()), this,
         SLOT(debuggingFinished()), Qt::QueuedConnection);
     connect(m_debuggerManager, SIGNAL(applicationOutputAvailable(QString, bool)),
-        this, SLOT(debuggerOutput(QString)), Qt::QueuedConnection);
+            this,
+#ifdef USE_GDBSERVER
+            SLOT(debuggerOutput(QString))
+#else
+            SLOT(handleRemoteOutput(QString))
+#endif
+            , Qt::QueuedConnection);
 }
 
 MaemoDebugRunControl::~MaemoDebugRunControl()
@@ -405,7 +422,6 @@ MaemoDebugRunControl::~MaemoDebugRunControl()
     disconnect(SIGNAL(addToOutputWindow(RunControl*,QString, bool)));
     disconnect(SIGNAL(addToOutputWindowInline(RunControl*,QString, bool)));
     stop();
-    debuggingFinished();
 }
 
 void MaemoDebugRunControl::startInternal()
@@ -421,12 +437,23 @@ QString MaemoDebugRunControl::remoteCall() const
         .arg(executableFilePathOnTarget()).arg(targetCmdLineSuffix());
 }
 
+void MaemoDebugRunControl::startExecution()
+{
+#ifdef USE_GDBSERVER
+    AbstractMaemoRunControl::startExecution();
+#else
+    startDebugging();
+#endif
+}
+
 void MaemoDebugRunControl::handleRemoteOutput(const QString &output)
 {
+#ifdef USE_GDBSERVER
     if (!m_debuggingStarted) {
         m_debuggingStarted = true;
         startDebugging();
     }
+#endif
     emit addToOutputWindowInline(this, output, false);
 }
 
@@ -448,7 +475,11 @@ bool MaemoDebugRunControl::isRunning() const
 
 void MaemoDebugRunControl::debuggingFinished()
 {
+#ifdef USE_GDBSERVER
     AbstractMaemoRunControl::stopRunning(true);
+#else
+    AbstractMaemoRunControl::handleRunThreadFinished();
+#endif
 }
 
 void MaemoDebugRunControl::debuggerOutput(const QString &output)
index 4fe9744..12177e2 100644 (file)
@@ -63,7 +63,7 @@ class AbstractMaemoRunControl : public ProjectExplorer::RunControl
     Q_OBJECT
 
 public:
-    explicit AbstractMaemoRunControl(ProjectExplorer::RunConfiguration *runConfig);
+    explicit AbstractMaemoRunControl(ProjectExplorer::RunConfiguration *runConfig, QString mode);
     virtual ~AbstractMaemoRunControl();
 
 protected:
@@ -74,7 +74,7 @@ protected:
     void startDeployment(bool forDebugging);
     void deploy();
     void stopRunning(bool forDebugging);
-    void startExecution();
+    virtual void startExecution();
     void handleError(const QString &errString);
     const QString executableOnHost() const;
     const QString executableFileName() const;
@@ -85,11 +85,13 @@ protected:
     QString packageFilePath() const;
     QString executableFilePathOnTarget() const;
 
+protected slots:
+    void handleRunThreadFinished();
+
 private slots:
     virtual void handleRemoteOutput(const QString &output)=0;
     void handleInitialCleanupFinished();
     void handleDeployThreadFinished();
-    void handleRunThreadFinished();
     void handleFileCopied();
 
 protected:
@@ -160,6 +162,7 @@ private slots:
 private:
     virtual void startInternal();
     virtual void stopInternal();
+    virtual void startExecution();
     virtual QString remoteCall() const;
 
     QString gdbServerPort() const;
index fdffb2e..e56ef65 100644 (file)
@@ -251,6 +251,7 @@ void MaemoSettingsWidget::configNameEditingFinished()
 
 void MaemoSettingsWidget::deviceTypeChanged()
 {
+    const QString name = currentConfig().name;
     const MaemoDeviceConfig::DeviceType devType =
         m_ui->deviceButton->isChecked()
             ? MaemoDeviceConfig::Physical
@@ -263,6 +264,7 @@ void MaemoSettingsWidget::deviceTypeChanged()
         m_lastConfigSim = currentConfig();
         currentConfig() = m_lastConfigHW;
     }
+    currentConfig().name = name;
     fillInValues();
 }
 
index 4b3ee3b..081f7eb 100644 (file)
@@ -102,8 +102,8 @@ MaemoSshRunner::MaemoSshRunner(const Core::SshServerInfo &server,
 bool MaemoSshRunner::runInternal()
 {
     createConnection();
-    connect(m_connection.data(), SIGNAL(remoteOutput(QByteArray)),
-            this, SLOT(handleRemoteOutput(QByteArray)));
+    connect(m_connection.data(), SIGNAL(remoteOutputAvailable()),
+            this, SLOT(handleRemoteOutput()));
     m_endMarkerCount = 0;
     m_promptEncountered = false;
     if (!m_connection->start())
@@ -115,9 +115,10 @@ bool MaemoSshRunner::runInternal()
     return !m_connection->hasError();
 }
 
-void MaemoSshRunner::handleRemoteOutput(const QByteArray &curOutput)
+void MaemoSshRunner::handleRemoteOutput()
 {
-    const QByteArray output = m_potentialEndMarkerPrefix + curOutput;
+    const QByteArray output
+        = m_potentialEndMarkerPrefix + m_connection->waitForRemoteOutput(0);
 
     // Wait for a prompt before sending the command.
     if (!m_promptEncountered) {
index a01e1bd..ee17d4b 100644 (file)
@@ -96,7 +96,7 @@ signals:
 
 private:
     virtual bool runInternal();
-    Q_SLOT void handleRemoteOutput(const QByteArray &output);
+    Q_SLOT void handleRemoteOutput();
 
     static const QByteArray EndMarker;
 
index fa2c313..bd88b65 100644 (file)
@@ -42,13 +42,15 @@ namespace {
     const char * const SIGNMODE_KEY("Qt4ProjectManager.S60CreatePackageStep.SignMode");
     const char * const CERTIFICATE_KEY("Qt4ProjectManager.S60CreatePackageStep.Certificate");
     const char * const KEYFILE_KEY("Qt4ProjectManager.S60CreatePackageStep.Keyfile");
+    const char * const SMART_INSTALLER_KEY("Qt4ProjectManager.S60CreatorPackageStep.SmartInstaller");
 }
 
 // #pragma mark -- S60SignBuildStep
 
 S60CreatePackageStep::S60CreatePackageStep(ProjectExplorer::BuildConfiguration *bc) :
     MakeStep(bc, QLatin1String(SIGN_BS_ID)),
-    m_signingMode(SignSelf)
+    m_signingMode(SignSelf),
+    m_createSmartInstaller(false)
 {
     ctor_package();
 }
@@ -57,14 +59,16 @@ S60CreatePackageStep::S60CreatePackageStep(ProjectExplorer::BuildConfiguration *
     MakeStep(bc, bs),
     m_signingMode(bs->m_signingMode),
     m_customSignaturePath(bs->m_customSignaturePath),
-    m_customKeyPath(bs->m_customKeyPath)
+    m_customKeyPath(bs->m_customKeyPath),
+    m_createSmartInstaller(bs->m_createSmartInstaller)
 {
     ctor_package();
 }
 
 S60CreatePackageStep::S60CreatePackageStep(ProjectExplorer::BuildConfiguration *bc, const QString &id) :
     MakeStep(bc, id),
-    m_signingMode(SignSelf)
+    m_signingMode(SignSelf),
+    m_createSmartInstaller(false)
 {
     ctor_package();
 }
@@ -84,6 +88,7 @@ QVariantMap S60CreatePackageStep::toMap() const
     map.insert(QLatin1String(SIGNMODE_KEY), (int)m_signingMode);
     map.insert(QLatin1String(CERTIFICATE_KEY), m_customSignaturePath);
     map.insert(QLatin1String(KEYFILE_KEY), m_customKeyPath);
+    map.insert(QLatin1String(SMART_INSTALLER_KEY), m_createSmartInstaller);
     return map;
 }
 
@@ -92,6 +97,7 @@ bool S60CreatePackageStep::fromMap(const QVariantMap &map)
     m_signingMode = (SigningMode)map.value(QLatin1String(SIGNMODE_KEY)).toInt();
     m_customSignaturePath = map.value(QLatin1String(CERTIFICATE_KEY)).toString();
     m_customKeyPath = map.value(QLatin1String(KEYFILE_KEY)).toString();
+    m_createSmartInstaller = map.value(QLatin1String(SMART_INSTALLER_KEY), false).toBool();
     return MakeStep::fromMap(map);
 }
 
@@ -103,7 +109,10 @@ bool S60CreatePackageStep::init()
     ProjectExplorer::Environment environment = bc->environment();
     setEnvironment(environment);
     QStringList args;
-    args << QLatin1String("sis");
+    if (m_createSmartInstaller)
+        args << QLatin1String("installer_sis");
+    else
+        args << QLatin1String("sis");
     if (signingMode() == SignCustom) {
         args << QLatin1String("QT_SIS_CERTIFICATE=") + QDir::toNativeSeparators(customSignaturePath())
              << QLatin1String("QT_SIS_KEY=") + QDir::toNativeSeparators(customKeyPath());
@@ -152,6 +161,17 @@ void S60CreatePackageStep::setCustomKeyPath(const QString &path)
     m_customKeyPath = path;
 }
 
+bool S60CreatePackageStep::createsSmartInstaller() const
+{
+    return m_createSmartInstaller;
+}
+
+void S60CreatePackageStep::setCreatesSmartInstaller(bool value)
+{
+    m_createSmartInstaller = value;
+    static_cast<Qt4BuildConfiguration *>(buildConfiguration())->emitS60CreatesSmartInstallerChanged();
+}
+
 // #pragma mark -- S60SignBuildStepFactory
 
 S60CreatePackageStepFactory::S60CreatePackageStepFactory(QObject *parent) :
@@ -241,6 +261,8 @@ S60CreatePackageStepConfigWidget::S60CreatePackageStepConfigWidget(S60CreatePack
             this, SLOT(updateFromUi()));
     connect(m_ui.keyFilePath, SIGNAL(changed(QString)),
             this, SLOT(updateFromUi()));
+    connect(m_ui.smartInstaller, SIGNAL(clicked()),
+            this, SLOT(updateFromUi()));
 }
 
 void S60CreatePackageStepConfigWidget::updateUi()
@@ -252,6 +274,7 @@ void S60CreatePackageStepConfigWidget::updateUi()
     m_ui.keyFilePath->setEnabled(!selfSigned);
     m_ui.signaturePath->setPath(m_signStep->customSignaturePath());
     m_ui.keyFilePath->setPath(m_signStep->customKeyPath());
+    m_ui.smartInstaller->setChecked(m_signStep->createsSmartInstaller());
     emit updateSummary();
 }
 
@@ -262,6 +285,7 @@ void S60CreatePackageStepConfigWidget::updateFromUi()
         : S60CreatePackageStep::SignCustom);
     m_signStep->setCustomSignaturePath(m_ui.signaturePath->path());
     m_signStep->setCustomKeyPath(m_ui.keyFilePath->path());
+    m_signStep->setCreatesSmartInstaller(m_ui.smartInstaller->isChecked());
     updateUi();
 }
 
@@ -275,6 +299,8 @@ QString S60CreatePackageStepConfigWidget::summaryText() const
                .arg(m_signStep->customSignaturePath())
                .arg(m_signStep->customKeyPath());
     }
+    if (m_signStep->createsSmartInstaller())
+        return tr("<b>Create SIS Package:</b> %1, using Smart Installer").arg(text);
     return tr("<b>Create SIS Package:</b> %1").arg(text);
 }
 
index 410dfb9..e1982b4 100644 (file)
@@ -83,6 +83,8 @@ public:
     void setCustomSignaturePath(const QString &path);
     QString customKeyPath() const;
     void setCustomKeyPath(const QString &path);
+    bool createsSmartInstaller() const;
+    void setCreatesSmartInstaller(bool value);
 
 protected:
     S60CreatePackageStep(ProjectExplorer::BuildConfiguration *bc, S60CreatePackageStep *bs);
@@ -95,6 +97,7 @@ private:
     SigningMode m_signingMode;
     QString m_customSignaturePath;
     QString m_customKeyPath;
+    bool m_createSmartInstaller;
 };
 
 class S60CreatePackageStepConfigWidget : public ProjectExplorer::BuildStepConfigWidget
index 4ae64d1..ac7badf 100644 (file)
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>517</width>
-    <height>95</height>
+    <height>108</height>
    </rect>
   </property>
   <property name="windowTitle">
     </layout>
    </item>
    <item>
+    <widget class="QCheckBox" name="smartInstaller">
+     <property name="text">
+      <string>Create Smart Installer package</string>
+     </property>
+    </widget>
+   </item>
+   <item>
     <spacer name="verticalSpacer">
      <property name="orientation">
       <enum>Qt::Vertical</enum>
    <class>Utils::PathChooser</class>
    <extends>QWidget</extends>
    <header location="global">utils/pathchooser.h</header>
+   <container>1</container>
+   <slots>
+    <signal>editingFinished()</signal>
+    <signal>browsingFinished()</signal>
+   </slots>
   </customwidget>
  </customwidgets>
  <resources/>
index c2b5b05..1e6a9ea 100644 (file)
@@ -40,6 +40,7 @@
 #include "symbiandevicemanager.h"
 #include "qt4buildconfiguration.h"
 #include "qt4projectmanagerconstants.h"
+#include "s60createpackagestep.h"
 
 #include <coreplugin/icore.h>
 #include <coreplugin/messagemanager.h>
@@ -109,6 +110,7 @@ QString pathToId(const QString &path)
 S60DeviceRunConfiguration::S60DeviceRunConfiguration(Target *parent, const QString &proFilePath) :
     RunConfiguration(parent,  QLatin1String(S60_DEVICE_RC_ID)),
     m_proFilePath(proFilePath),
+    m_activeBuildConfiguration(0),
 #ifdef Q_OS_WIN
     m_serialPortName(QLatin1String("COM5"))
 #else
@@ -121,6 +123,7 @@ S60DeviceRunConfiguration::S60DeviceRunConfiguration(Target *parent, const QStri
 S60DeviceRunConfiguration::S60DeviceRunConfiguration(Target *target, S60DeviceRunConfiguration *source) :
     RunConfiguration(target, source),
     m_proFilePath(source->m_proFilePath),
+    m_activeBuildConfiguration(0),
     m_serialPortName(source->m_serialPortName)
 {
     ctor();
@@ -135,6 +138,9 @@ void S60DeviceRunConfiguration::ctor()
 
     connect(qt4Target()->qt4Project(), SIGNAL(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode*)),
             this, SLOT(proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode*)));
+    connect(qt4Target(), SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)),
+            this, SLOT(updateActiveBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
+    updateActiveBuildConfiguration(qt4Target()->activeBuildConfiguration());
 }
 
 void S60DeviceRunConfiguration::proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode *pro)
@@ -143,6 +149,17 @@ void S60DeviceRunConfiguration::proFileUpdate(Qt4ProjectManager::Internal::Qt4Pr
         emit targetInformationChanged();
 }
 
+void S60DeviceRunConfiguration::updateActiveBuildConfiguration(ProjectExplorer::BuildConfiguration *buildConfiguration)
+{
+    if (m_activeBuildConfiguration)
+        disconnect(m_activeBuildConfiguration, SIGNAL(s60CreatesSmartInstallerChanged()),
+                   this, SIGNAL(targetInformationChanged()));
+    m_activeBuildConfiguration = buildConfiguration;
+    if (m_activeBuildConfiguration)
+        connect(m_activeBuildConfiguration, SIGNAL(s60CreatesSmartInstallerChanged()),
+                this, SIGNAL(targetInformationChanged()));
+}
+
 S60DeviceRunConfiguration::~S60DeviceRunConfiguration()
 {
 }
@@ -346,12 +363,27 @@ QString S60DeviceRunConfiguration::localExecutableFileName() const
     return QDir::toNativeSeparators(localExecutable);
 }
 
+bool S60DeviceRunConfiguration::runSmartInstaller() const
+{
+    BuildConfiguration *bc = target()->activeBuildConfiguration();
+    QTC_ASSERT(bc, return false);
+    QList<BuildStep *> steps = bc->steps(Build);
+    foreach (const BuildStep *step, steps) {
+        if (const S60CreatePackageStep *packageStep = qobject_cast<const S60CreatePackageStep *>(step)) {
+            return packageStep->createsSmartInstaller();
+        }
+    }
+    return false;
+}
+
 QString S60DeviceRunConfiguration::signedPackage() const
 {
     TargetInformation ti = qt4Target()->qt4Project()->rootProjectNode()->targetInformation(m_proFilePath);
     if (!ti.valid)
         return QString();
-    return ti.buildDir + QLatin1Char('/') + ti.target + QLatin1String(".sis");
+    return ti.buildDir + QLatin1Char('/') + ti.target
+            + (runSmartInstaller() ? QLatin1String("_installer") : QLatin1String(""))
+            + QLatin1String(".sis");
 }
 
 QStringList S60DeviceRunConfiguration::commandLineArguments() const
@@ -451,8 +483,8 @@ RunConfiguration *S60DeviceRunConfigurationFactory::clone(Target *parent, RunCon
 
 // ======== S60DeviceRunControlBase
 
-S60DeviceRunControlBase::S60DeviceRunControlBase(RunConfiguration *runConfiguration) :
-    RunControl(runConfiguration),
+S60DeviceRunControlBase::S60DeviceRunControlBase(RunConfiguration *runConfiguration, QString mode) :
+    RunControl(runConfiguration, mode),
     m_toolChain(ProjectExplorer::ToolChain::INVALID),
     m_releaseDeviceAfterLauncherFinish(false),
     m_handleDeviceRemoval(true),
@@ -812,8 +844,8 @@ bool S60DeviceRunControlBase::checkConfiguration(QString * /* errorMessage */,
 
 // =============== S60DeviceRunControl
 
-S60DeviceRunControl::S60DeviceRunControl(ProjectExplorer::RunConfiguration *runConfiguration) :
-    S60DeviceRunControlBase(runConfiguration)
+S60DeviceRunControl::S60DeviceRunControl(ProjectExplorer::RunConfiguration *runConfiguration, QString mode) :
+    S60DeviceRunControlBase(runConfiguration, mode)
 {
 }
 
@@ -849,8 +881,8 @@ void S60DeviceRunControl::printRunFailNotice(const QString &errorMessage) {
 
 // ======== S60DeviceDebugRunControl
 
-S60DeviceDebugRunControl::S60DeviceDebugRunControl(S60DeviceRunConfiguration *runConfiguration) :
-    S60DeviceRunControlBase(runConfiguration),
+S60DeviceDebugRunControl::S60DeviceDebugRunControl(S60DeviceRunConfiguration *runConfiguration, QString mode) :
+    S60DeviceRunControlBase(runConfiguration, mode),
     m_startParams(new Debugger::DebuggerStartParameters)
 {
     setReleaseDeviceAfterLauncherFinish(true); // Debugger controls device after install
index 3ff0bc1..f37e67e 100644 (file)
@@ -100,6 +100,7 @@ signals:
 
 private slots:
     void proFileUpdate(Qt4ProjectManager::Internal::Qt4ProFileNode *pro);
+    void updateActiveBuildConfiguration(ProjectExplorer::BuildConfiguration *buildConfiguration);
 
 protected:
     S60DeviceRunConfiguration(ProjectExplorer::Target *parent, S60DeviceRunConfiguration *source);
@@ -109,7 +110,10 @@ private:
     ProjectExplorer::ToolChain::ToolChainType toolChainType(ProjectExplorer::BuildConfiguration *configuration) const;
     void ctor();
 
+    bool runSmartInstaller() const;
+
     QString m_proFilePath;
+    ProjectExplorer::BuildConfiguration *m_activeBuildConfiguration;
     QString m_serialPortName;
     QStringList m_commandLineArguments;
 };
@@ -144,7 +148,7 @@ class S60DeviceRunControlBase : public ProjectExplorer::RunControl
 {
     Q_OBJECT
 public:
-    explicit S60DeviceRunControlBase(ProjectExplorer::RunConfiguration *runConfiguration);
+    explicit S60DeviceRunControlBase(ProjectExplorer::RunConfiguration *runConfiguration, QString mode);
     ~S60DeviceRunControlBase();
     virtual void start();
     virtual void stop();
@@ -206,7 +210,7 @@ class S60DeviceRunControl : public S60DeviceRunControlBase
 {
     Q_OBJECT
 public:
-    explicit S60DeviceRunControl(ProjectExplorer::RunConfiguration *runConfiguration);
+    explicit S60DeviceRunControl(ProjectExplorer::RunConfiguration *runConfiguration, QString mode);
 
 protected:
     virtual void initLauncher(const QString &executable, trk::Launcher *);
@@ -225,7 +229,7 @@ class S60DeviceDebugRunControl : public S60DeviceRunControlBase
     Q_DISABLE_COPY(S60DeviceDebugRunControl)
     Q_OBJECT
 public:
-    explicit S60DeviceDebugRunControl(S60DeviceRunConfiguration *runConfiguration);
+    explicit S60DeviceDebugRunControl(S60DeviceRunConfiguration *runConfiguration, QString mode);
     virtual ~S60DeviceDebugRunControl();
 
     virtual void stop();
index 3a6d849..9ae33ff 100644 (file)
@@ -293,8 +293,8 @@ QString S60EmulatorRunConfigurationFactory::displayNameForId(const QString &id)
 
 // ======== S60EmulatorRunControl
 
-S60EmulatorRunControl::S60EmulatorRunControl(S60EmulatorRunConfiguration *runConfiguration)
-    : RunControl(runConfiguration)
+S60EmulatorRunControl::S60EmulatorRunControl(S60EmulatorRunConfiguration *runConfiguration, QString mode)
+    : RunControl(runConfiguration, mode)
 {
     // stuff like the EPOCROOT and EPOCDEVICE env variable
     Environment env = Environment::systemEnvironment();
index 7fd1dda..917eac3 100644 (file)
@@ -129,7 +129,7 @@ class S60EmulatorRunControl : public ProjectExplorer::RunControl
 {
     Q_OBJECT
 public:
-    explicit S60EmulatorRunControl(S60EmulatorRunConfiguration *runConfiguration);
+    explicit S60EmulatorRunControl(S60EmulatorRunConfiguration *runConfiguration, QString mode);
     ~S60EmulatorRunControl() {}
     void start();
     void stop();
index 941bdbd..cdb4902 100644 (file)
@@ -80,7 +80,7 @@ public:
     ProjectExplorer::RunControl* create(ProjectExplorer::RunConfiguration *runConfiguration, const QString &mode) {
         RunConfiguration *rc = qobject_cast<RunConfiguration *>(runConfiguration);
         QTC_ASSERT(rc && mode == m_mode, return 0);
-        return new RunControl(rc);
+        return new RunControl(rc, mode);
     }
 
     QString displayName() const {
index c1e91a2..39bd078 100644 (file)
@@ -194,8 +194,12 @@ ProjectExplorer::Environment Qt4BuildConfiguration::baseEnvironment() const
 QString Qt4BuildConfiguration::buildDirectory() const
 {
     QString workingDirectory;
-    if (m_shadowBuild)
-        workingDirectory = m_buildDirectory;
+    if (m_shadowBuild) {
+        if (!m_buildDirectory.isEmpty())
+            workingDirectory = m_buildDirectory;
+        else
+            workingDirectory = qt4Target()->defaultBuildDirectory();
+    }
     if (workingDirectory.isEmpty())
         workingDirectory = target()->project()->projectDirectory();
     return workingDirectory;
@@ -233,6 +237,8 @@ bool Qt4BuildConfiguration::shadowBuild() const
 /// \note buildDirectory() is probably the function you want to call
 QString Qt4BuildConfiguration::shadowBuildDirectory() const
 {
+    if (m_buildDirectory.isEmpty())
+        return qt4Target()->defaultBuildDirectory();
     return m_buildDirectory;
 }
 
@@ -365,6 +371,12 @@ void Qt4BuildConfiguration::emitBuildDirectoryInitialized()
     emit buildDirectoryInitialized();
 }
 
+void Qt4BuildConfiguration::emitS60CreatesSmartInstallerChanged()
+{
+    emit s60CreatesSmartInstallerChanged();
+}
+
+
 void Qt4BuildConfiguration::getConfigCommandLineArguments(QStringList *addedUserConfigs, QStringList *removedUserConfigs) const
 {
     QtVersion::QmakeBuildConfigs defaultBuildConfiguration = qtVersion()->defaultBuildConfig();
index 9dfb6d9..eec8600 100644 (file)
@@ -83,6 +83,10 @@ public:
     // used by qmake step to notify that the build directory was initialized
     // not really nice
     void emitBuildDirectoryInitialized();
+    // used by S60CreatePackageStep to notify that the smart installer property changed
+    // not really nice
+    void emitS60CreatesSmartInstallerChanged();
+
     void getConfigCommandLineArguments(QStringList *addedUserConfigs, QStringList *removedUserConfigs) const;
 
     // Those functions are used in a few places.
@@ -112,6 +116,8 @@ signals:
     /// emitted for setQMakeBuildConfig, not emitted for qt version changes, even
     /// if those change the qmakebuildconfig
     void qmakeBuildConfigurationChanged();
+    /// emitted when smart installer property of S60 create package step changes
+    void s60CreatesSmartInstallerChanged();
 
     /// emitted if the build configuration changed in a way that
     /// should trigger a reevaluation of all .pro files
index a5b857c..9c798ef 100644 (file)
@@ -172,6 +172,13 @@ bool Qt4PriFile::save(const QString &fileName)
     return false;
 }
 
+void Qt4PriFile::rename(const QString &newName)
+{
+    // Can't happen
+    Q_ASSERT(false);
+    Q_UNUSED(newName);
+}
+
 QString Qt4PriFile::fileName() const
 {
     return m_priFile->path();
@@ -537,7 +544,7 @@ void Qt4PriFileNode::update(ProFile *includeFileExact, ProFileReader *readerExac
     contents.updateSubFolders(this, this);
 }
 
-QList<ProjectNode::ProjectAction> Qt4PriFileNode::supportedActions() const
+QList<ProjectNode::ProjectAction> Qt4PriFileNode::supportedActions(Node *node) const
 {
     QList<ProjectAction> actions;
 
@@ -558,6 +565,11 @@ QList<ProjectNode::ProjectAction> Qt4PriFileNode::supportedActions() const
     default:
         break;
     }
+
+    FileNode *fileNode = qobject_cast<FileNode *>(node);
+    if (fileNode && fileNode->fileType() != ProjectExplorer::ProjectFileType)
+        actions << Rename;
+
     return actions;
 }
 
@@ -614,9 +626,6 @@ bool Qt4PriFileNode::renameFile(const FileType fileType, const QString &filePath
     if (newFilePath.isEmpty())
         return false;
 
-    if (!QFile::rename(filePath, newFilePath))
-        return false;
-
     QStringList dummy;
     changeFiles(fileType, QStringList() << filePath, &dummy, RemoveFromProFile);
     if (!dummy.isEmpty())
@@ -1168,16 +1177,31 @@ void Qt4ProFileNode::applyEvaluate(bool parseResult, bool async)
             // newCumalativeIt and newExactIt are already incremented
 
         }
-        // If we found something to add do it
+        // If we found something to add, do it
         if (!nodeToAdd.isEmpty()) {
             ProFile *fileExact = includeFilesCumlative.value(nodeToAdd);
             ProFile *fileCumlative = includeFilesCumlative.value(nodeToAdd);
-            if (fileExact || fileCumlative) {
+
+            // Loop preventation, make sure that exact same node is not in our parent chain
+            bool loop = false;
+            ProjectExplorer::Node *n = this;
+            while ((n = n->parentFolderNode())) {
+                if (qobject_cast<Qt4PriFileNode *>(n) && n->path() == nodeToAdd) {
+                    loop = true;
+                    break;
+                }
+            }
+
+            if (loop) {
+                // Do nothing
+            } else if (fileExact || fileCumlative) {
                 Qt4PriFileNode *qt4PriFileNode = new Qt4PriFileNode(m_project, this, nodeToAdd);
+                qt4PriFileNode->setParentFolderNode(this); // Needed for loop detection
                 qt4PriFileNode->update(fileExact, m_readerExact, fileCumlative, m_readerCumulative);
                 toAdd << qt4PriFileNode;
             } else {
                 Qt4ProFileNode *qt4ProFileNode = new Qt4ProFileNode(m_project, nodeToAdd);
+                qt4ProFileNode->setParentFolderNode(this); // Needed for loop detection
                 if (async)
                     qt4ProFileNode->asyncUpdate();
                 else
index a9585d8..b35f687 100644 (file)
@@ -105,6 +105,7 @@ public:
     Qt4PriFile(Qt4PriFileNode *qt4PriFile);
     virtual bool save(const QString &fileName = QString());
     virtual QString fileName() const;
+    virtual void rename(const QString &newName);
 
     virtual QString defaultPath() const;
     virtual QString suggestedFileName() const;
@@ -133,7 +134,7 @@ public:
 
 
 // ProjectNode interface
-    QList<ProjectAction> supportedActions() const;
+    QList<ProjectAction> supportedActions(Node *node) const;
 
     bool hasBuildTargets() const { return false; }
 
index e72aca8..cf3f84d 100644 (file)
@@ -180,6 +180,13 @@ bool Qt4ProjectFile::save(const QString &)
     return false;
 }
 
+void Qt4ProjectFile::rename(const QString &newName)
+{
+    // Can't happen
+    Q_UNUSED(newName);
+    Q_ASSERT(false);
+}
+
 QString Qt4ProjectFile::fileName() const
 {
     return m_filePath;
index 84aad0e..d64e241 100644 (file)
@@ -88,6 +88,7 @@ public:
 
     bool save(const QString &fileName = QString());
     QString fileName() const;
+    virtual void rename(const QString &newName);
 
     QString defaultPath() const;
     QString suggestedFileName() const;
index d3342b3..443923c 100644 (file)
@@ -269,6 +269,21 @@ void Qt4Manager::runQMake(ProjectExplorer::Project *p, ProjectExplorer::Node *no
 
 void Qt4Manager::buildSubDirContextMenu()
 {
+    handleSubDirContexMenu(BUILD);
+}
+
+void Qt4Manager::cleanSubDirContextMenu()
+{
+    handleSubDirContexMenu(CLEAN);
+}
+
+void Qt4Manager::rebuildSubDirContextMenu()
+{
+    handleSubDirContexMenu(REBUILD);
+}
+
+void Qt4Manager::handleSubDirContexMenu(Qt4Manager::Action action)
+{
     Qt4Project *qt4pro = qobject_cast<Qt4Project *>(m_contextProject);
     QTC_ASSERT(qt4pro, return);
 
@@ -281,8 +296,16 @@ void Qt4Manager::buildSubDirContextMenu()
         if (Qt4ProFileNode *profile = qobject_cast<Qt4ProFileNode *>(m_contextNode))
             bc->setSubNodeBuild(profile);
 
-    if (projectExplorer()->saveModifiedFiles())
-        projectExplorer()->buildManager()->buildProject(bc);
+    if (projectExplorer()->saveModifiedFiles()) {
+        if (action == BUILD)
+            projectExplorer()->buildManager()->buildProject(bc);
+        else if (action == CLEAN)
+            projectExplorer()->buildManager()->cleanProject(bc);
+        else if (action == REBUILD) {
+            projectExplorer()->buildManager()->cleanProject(bc);
+            projectExplorer()->buildManager()->buildProject(bc);
+        }
+    }
 
     bc->setSubNodeBuild(0);
 }
index 2235a17..8223837 100644 (file)
@@ -90,10 +90,14 @@ public:
     // Return the id string of a file
     static QString fileTypeId(ProjectExplorer::FileType type);
 
+    enum Action { BUILD, REBUILD, CLEAN };
+
 public slots:
     void runQMake();
     void runQMakeContextMenu();
     void buildSubDirContextMenu();
+    void rebuildSubDirContextMenu();
+    void cleanSubDirContextMenu();
 
 private slots:
     void editorAboutToClose(Core::IEditor *editor);
@@ -102,6 +106,7 @@ private slots:
 
 private:
     QList<Qt4Project *> m_projects;
+    void handleSubDirContexMenu(Action action);
     void runQMake(ProjectExplorer::Project *p, ProjectExplorer::Node *node);
 
     Internal::Qt4ProjectManagerPlugin *m_plugin;
index 68d36c8..8633d8d 100644 (file)
@@ -58,6 +58,8 @@ const char * const ADDTOPROJECT        = "Qt4.AddToProject";
 const char * const RUNQMAKE            = "Qt4Builder.RunQMake";
 const char * const RUNQMAKECONTEXTMENU = "Qt4Builder.RunQMakeContextMenu";
 const char * const BUILDSUBDIR         = "Qt4Builder.BuildSubDir";
+const char * const REBUILDSUBDIR       = "Qt4Builder.RebuildSubDir";
+const char * const CLEANSUBDIR         = "Qt4Builder.CleanSubDir";
 
 //configurations
 const char * const CONFIG_DEBUG     = "debug";
index d6500ed..f79dec8 100644 (file)
@@ -185,7 +185,6 @@ bool Qt4ProjectManagerPlugin::initialize(const QStringList &arguments, QString *
     m_runQMakeActionContextMenu = new QAction(qmakeIcon, tr("Run qmake"), this);
     command = am->registerAction(m_runQMakeActionContextMenu, Constants::RUNQMAKECONTEXTMENU, context);
     command->setAttribute(Core::Command::CA_Hide);
-    command->setAttribute(Core::Command::CA_UpdateText);
     mproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
     msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
     connect(m_runQMakeActionContextMenu, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(runQMakeContextMenu()));
@@ -195,10 +194,25 @@ bool Qt4ProjectManagerPlugin::initialize(const QStringList &arguments, QString *
     m_buildSubProjectContextMenu = new QAction(buildIcon, tr("Build"), this);
     command = am->registerAction(m_buildSubProjectContextMenu, Constants::BUILDSUBDIR, context);
     command->setAttribute(Core::Command::CA_Hide);
-    command->setAttribute(Core::Command::CA_UpdateText);
     msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
     connect(m_buildSubProjectContextMenu, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(buildSubDirContextMenu()));
 
+    QIcon rebuildIcon(ProjectExplorer::Constants::ICON_REBUILD);
+    rebuildIcon.addFile(ProjectExplorer::Constants::ICON_REBUILD_SMALL);
+    m_rebuildSubProjectContextMenu = new QAction(rebuildIcon, tr("Rebuild"), this);
+    command = am->registerAction(m_rebuildSubProjectContextMenu, Constants::REBUILDSUBDIR, context);
+    command->setAttribute(Core::Command::CA_Hide);
+    msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
+    connect(m_rebuildSubProjectContextMenu, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(rebuildSubDirContextMenu()));
+
+    QIcon cleanIcon(ProjectExplorer::Constants::ICON_CLEAN);
+    cleanIcon.addFile(ProjectExplorer::Constants::ICON_CLEAN_SMALL);
+    m_cleanSubProjectContextMenu = new QAction(cleanIcon, tr("Clean"), this);
+    command = am->registerAction(m_cleanSubProjectContextMenu, Constants::CLEANSUBDIR, context);
+    command->setAttribute(Core::Command::CA_Hide);
+    msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
+    connect(m_cleanSubProjectContextMenu, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(cleanSubDirContextMenu()));
+
     connect(m_projectExplorer,
             SIGNAL(aboutToShowContextMenu(ProjectExplorer::Project*, ProjectExplorer::Node*)),
             this, SLOT(updateContextMenu(ProjectExplorer::Project*, ProjectExplorer::Node*)));
@@ -224,23 +238,27 @@ void Qt4ProjectManagerPlugin::updateContextMenu(Project *project,
     m_qt4ProjectManager->setContextNode(node);
     m_runQMakeActionContextMenu->setEnabled(false);
     m_buildSubProjectContextMenu->setEnabled(false);
+    m_rebuildSubProjectContextMenu->setEnabled(false);
+    m_cleanSubProjectContextMenu->setEnabled(false);
 
     Qt4ProFileNode *proFileNode = qobject_cast<Qt4ProFileNode *>(node);
     if (qobject_cast<Qt4Project *>(project) && proFileNode) {
         m_runQMakeActionContextMenu->setVisible(true);
         m_buildSubProjectContextMenu->setVisible(true);
-
-        const QString nativeBuildDir = QDir::toNativeSeparators(proFileNode->buildDir());
-        m_runQMakeActionContextMenu->setText(tr("Run qmake in %1").arg(nativeBuildDir));
-        m_buildSubProjectContextMenu->setText(tr("Build in %1").arg(nativeBuildDir));
+        m_rebuildSubProjectContextMenu->setVisible(true);
+        m_cleanSubProjectContextMenu->setVisible(true);
 
         if (!m_projectExplorer->buildManager()->isBuilding(project)) {
             m_runQMakeActionContextMenu->setEnabled(true);
             m_buildSubProjectContextMenu->setEnabled(true);
+            m_rebuildSubProjectContextMenu->setEnabled(true);
+            m_cleanSubProjectContextMenu->setEnabled(true);
         }
     } else {
         m_runQMakeActionContextMenu->setVisible(false);
         m_buildSubProjectContextMenu->setVisible(false);
+        m_rebuildSubProjectContextMenu->setVisible(false);
+        m_cleanSubProjectContextMenu->setVisible(false);
     }
 }
 
index 4c8853b..eec6477 100644 (file)
@@ -93,6 +93,8 @@ private:
     QAction *m_runQMakeAction;
     QAction *m_runQMakeActionContextMenu;
     QAction *m_buildSubProjectContextMenu;
+    QAction *m_rebuildSubProjectContextMenu;
+    QAction *m_cleanSubProjectContextMenu;
     GettingStartedWelcomePage *m_welcomePage;
 };
 
index 32697a7..00486fe 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="RegExp" version="1.3.84" compatVersion="1.3.84">
+<plugin name="RegExp" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -13,6 +13,6 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Regular Expression test widget.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="Core" version="1.3.84"/>
+        <dependency name="Core" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 68ad8d1..b0fe4bf 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="ResourceEditor" version="1.3.84" compatVersion="1.3.84">
+<plugin name="ResourceEditor" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,6 +14,6 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Editor for qrc files.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="Core" version="1.3.84"/>
+        <dependency name="Core" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 75f9fb2..5ac8bd9 100644 (file)
@@ -156,6 +156,12 @@ bool ResourceEditorFile::save(const QString &name /*= QString()*/)
     return true;
 }
 
+void ResourceEditorFile::rename(const QString &newName)
+{
+    m_parent->m_resourceEditor->setFileName(newName);
+    emit changed();
+}
+
 QString ResourceEditorW::id() const {
     return QLatin1String(ResourceEditor::Constants::RESOURCEEDITOR_ID);
 }
index bdcba53..79e11bd 100644 (file)
@@ -66,6 +66,7 @@ public:
     QString defaultPath() const;
     QString suggestedFileName() const;
     virtual QString mimeType() const;
+    virtual void rename(const QString &newName);
 
 private:
     const QString m_mimeType;
index b1f3bf5..cf910ce 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="Snippets" version="1.3.84" compatVersion="1.3.84">
+<plugin name="Snippets" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -13,8 +13,8 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Code snippet plugin.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="Core" version="1.3.84"/>
-        <dependency name="TextEditor" version="1.3.84"/>
-        <dependency name="ProjectExplorer" version="1.3.84"/>
+        <dependency name="Core" version="2.0.80"/>
+        <dependency name="TextEditor" version="2.0.80"/>
+        <dependency name="ProjectExplorer" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 574ff93..60025cd 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="Subversion" version="1.3.84" compatVersion="1.3.84">
+<plugin name="Subversion" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,9 +14,9 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Subversion integration.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="TextEditor" version="1.3.84"/>
-        <dependency name="ProjectExplorer" version="1.3.84"/>
-        <dependency name="Core" version="1.3.84"/>
-        <dependency name="VCSBase" version="1.3.84"/>
+        <dependency name="TextEditor" version="2.0.80"/>
+        <dependency name="ProjectExplorer" version="2.0.80"/>
+        <dependency name="Core" version="2.0.80"/>
+        <dependency name="VCSBase" version="2.0.80"/>
     </dependencyList>
 </plugin>
index c58159f..f25fc3a 100644 (file)
@@ -52,6 +52,7 @@ bool SubversionControl::supportsOperation(Operation operation) const
     switch (operation) {
     case AddOperation:
     case DeleteOperation:
+    case MoveOperation:
     case AnnotateOperation:
         break;
     case OpenOperation:
@@ -81,6 +82,13 @@ bool SubversionControl::vcsDelete(const QString &fileName)
     return m_plugin->vcsDelete(fi.absolutePath(), fi.fileName());
 }
 
+bool SubversionControl::vcsMove(const QString &from, const QString &to)
+{
+    const QFileInfo fromInfo(from);
+    const QFileInfo toInfo(to);
+    return m_plugin->vcsMove(fromInfo.absolutePath(), fromInfo.absoluteFilePath(), toInfo.absoluteFilePath());
+}
+
 bool SubversionControl::vcsCreateRepository(const QString &)
 {
     return false;
@@ -106,14 +114,9 @@ bool SubversionControl::vcsRemoveSnapshot(const QString &, const QString &)
     return false;
 }
 
-bool SubversionControl::managesDirectory(const QString &directory) const
-{
-    return m_plugin->managesDirectory(directory);
-}
-
-QString SubversionControl::findTopLevelForDirectory(const QString &directory) const
+bool SubversionControl::managesDirectory(const QString &directory, QString *topLevel) const
 {
-    return m_plugin->findTopLevelForDirectory(directory);
+    return m_plugin->managesDirectory(directory, topLevel);
 }
 
 bool SubversionControl::vcsAnnotate(const QString &file, int line)
index 132aca4..5610059 100644 (file)
@@ -45,13 +45,13 @@ public:
     explicit SubversionControl(SubversionPlugin *plugin);
     virtual QString displayName() const;
 
-    virtual bool managesDirectory(const QString &directory) const;
-    virtual QString findTopLevelForDirectory(const QString &directory) const;
+    virtual bool managesDirectory(const QString &directory, QString *topLevel = 0) const;
 
     virtual bool supportsOperation(Operation operation) const;
     virtual bool vcsOpen(const QString &fileName);
     virtual bool vcsAdd(const QString &fileName);
     virtual bool vcsDelete(const QString &filename);
+    virtual bool vcsMove(const QString &from, const QString &to);
     virtual bool vcsCreateRepository(const QString &directory);
 
     virtual QString vcsCreateSnapshot(const QString &topLevel);
index a29483b..ff299b1 100644 (file)
@@ -940,8 +940,9 @@ void SubversionPlugin::describe(const QString &source, const QString &changeNr)
     // To describe a complete change, find the top level and then do
     //svn diff -r 472958:472959 <top level>
     const QFileInfo fi(source);
-    const QString topLevel = findTopLevelForDirectory(fi.isDir() ? source : fi.absolutePath());
-    if (topLevel.isEmpty())
+    QString topLevel;
+    const bool manages = managesDirectory(fi.isDir() ? source : fi.absolutePath(), &topLevel);
+    if (!manages || topLevel.isEmpty())
         return;
     if (Subversion::Constants::debug)
         qDebug() << Q_FUNC_INFO << source << topLevel << changeNr;
@@ -1184,7 +1185,7 @@ bool SubversionPlugin::vcsAdd14(const QString &workingDir, const QString &rawFil
             if (!path.isEmpty())
                 path += slash;
             path += relativePath.at(p);
-            if (!managesDirectory(QDir(path))) {
+            if (!checkSVNSubDir(QDir(path))) {
                 QStringList addDirArgs;
                 addDirArgs << QLatin1String("add") << QLatin1String("--non-recursive") << QDir::toNativeSeparators(path);
                 const SubversionResponse addDirResponse = runSvn(workingDir, addDirArgs, m_settings.timeOutMS(), true);
@@ -1211,19 +1212,53 @@ bool SubversionPlugin::vcsDelete(const QString &workingDir, const QString &rawFi
     return !response.error;
 }
 
+bool SubversionPlugin::vcsMove(const QString &workingDir, const QString &from, const QString &to)
+{
+    QStringList args(QLatin1String("move"));
+    args << QDir::toNativeSeparators(from) << QDir::toNativeSeparators(to);
+    qDebug()<<args;
+    const SubversionResponse response = runSvn(workingDir, args, m_settings.timeOutMS(), true);
+    qDebug() << response.stdOut << "\n"<<response.stdErr;
+    return !response.error;
+}
+
 /* Subversion has ".svn" directory in each directory
  * it manages. The top level is the first directory
  * under the directory that does not have a  ".svn". */
-bool SubversionPlugin::managesDirectory(const QString &directory) const
+bool SubversionPlugin::managesDirectory(const QString &directory, QString *topLevel /* = 0 */) const
 {
     const QDir dir(directory);
-    const bool rc = dir.exists() && managesDirectory(dir);
-    if (Subversion::Constants::debug)
-        qDebug() << "SubversionPlugin::managesDirectory" << directory << rc;
-    return rc;
+    if (topLevel)
+        topLevel->clear();
+    bool manages = false;
+    do {
+        if (!dir.exists() || !checkSVNSubDir(dir))
+            break;
+        manages = true;
+        if (!topLevel)
+            break;
+        /* Recursing up, the top level is a child of the first directory that does
+         * not have a  ".svn" directory. The starting directory must be a managed
+         * one. Go up and try to find the first unmanaged parent dir. */
+        QDir lastDirectory = dir;
+        for (QDir parentDir = lastDirectory; parentDir.cdUp() ; lastDirectory = parentDir) {
+            if (!checkSVNSubDir(parentDir)) {
+                *topLevel = lastDirectory.absolutePath();
+                break;
+            }
+        }
+    } while (false);
+    if (Subversion::Constants::debug) {
+        QDebug nsp = qDebug().nospace();
+        nsp << "SubversionPlugin::managesDirectory" << directory << manages;
+        if (topLevel)
+            nsp << *topLevel;
+    }
+    return manages;
 }
 
-bool SubversionPlugin::managesDirectory(const QDir &directory) const
+// Check whether SVN management subdirs exist.
+bool SubversionPlugin::checkSVNSubDir(const QDir &directory) const
 {
     const int dirCount = m_svnDirectories.size();
     for (int i = 0; i < dirCount; i++) {
@@ -1234,30 +1269,6 @@ bool SubversionPlugin::managesDirectory(const QDir &directory) const
     return false;
 }
 
-QString SubversionPlugin::findTopLevelForDirectory(const QString &directory) const
-{
-    // Debug wrapper
-    const QString rc = findTopLevelForDirectoryI(directory);
-    if (Subversion::Constants::debug)
-        qDebug() << "SubversionPlugin::findTopLevelForDirectory" << directory << rc;
-    return rc;
-}
-
-QString SubversionPlugin::findTopLevelForDirectoryI(const QString &directory) const
-{
-    /* Recursing up, the top level is a child of the first directory that does
-     * not have a  ".svn" directory. The starting directory must be a managed
-     * one. Go up and try to find the first unmanaged parent dir. */
-    QDir lastDirectory = QDir(directory);
-    if (!lastDirectory.exists() || !managesDirectory(lastDirectory))
-        return QString();
-    for (QDir parentDir = lastDirectory; parentDir.cdUp() ; lastDirectory = parentDir) {
-        if (!managesDirectory(parentDir))
-            return lastDirectory.absolutePath();
-    }
-    return QString();
-}
-
 SubversionControl *SubversionPlugin::subVersionControl() const
 {
     return static_cast<SubversionControl *>(versionControl());
index 2562895..278cb2d 100644 (file)
@@ -94,8 +94,8 @@ public:
     bool vcsAdd14(const QString &workingDir, const QString &fileName);
     bool vcsAdd15(const QString &workingDir, const QString &fileName);
     bool vcsDelete(const QString &workingDir, const QString &fileName);
-    bool managesDirectory(const QString &directory) const;
-    QString findTopLevelForDirectory(const QString &directory) const;
+    bool vcsMove(const QString &workingDir, const QString &from, const QString &to);
+    bool managesDirectory(const QString &directory, QString *topLevel = 0) const;
 
     static SubversionPlugin *subversionPluginInstance();
 
@@ -144,8 +144,7 @@ private:
                  bool enableAnnotationContextMenu = false);
     void svnStatus(const QString &workingDir, const QStringList &relativePath = QStringList());
     void svnUpdate(const QString &workingDir, const QStringList &relativePaths = QStringList());
-    bool managesDirectory(const QDir &directory) const;
-    QString findTopLevelForDirectoryI(const QString &directory) const;
+    bool checkSVNSubDir(const QDir &directory) const;
     void startCommit(const QString &workingDir, const QStringList &files = QStringList());
     bool commit(const QString &messageFile, const QStringList &subVersionFileList);
     void cleanCommitMessageFile();
index 6afb71a..5086f05 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="TextEditor" version="1.3.84" compatVersion="1.3.84">
+<plugin name="TextEditor" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,8 +14,8 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Text editor framework and the implementation of the basic text editor.</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="Core" version="1.3.84"/>
-        <dependency name="Find" version="1.3.84"/>
-        <dependency name="Locator" version="1.3.84"/>
+        <dependency name="Core" version="2.0.80"/>
+        <dependency name="Find" version="2.0.80"/>
+        <dependency name="Locator" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 8035f02..25406e9 100644 (file)
@@ -205,6 +205,14 @@ bool BaseTextDocument::save(const QString &fileName)
     return true;
 }
 
+void BaseTextDocument::rename(const QString &newName)
+{
+    const QFileInfo fi(newName);
+    m_fileName = QDir::cleanPath(fi.absoluteFilePath());
+    emit titleChanged(fi.fileName());
+    emit changed();
+}
+
 bool BaseTextDocument::isReadOnly() const
 {
     if (m_isBinaryData || m_hasDecodingError)
index 2958fc3..07f32b7 100644 (file)
@@ -89,6 +89,7 @@ public:
     void reload(ReloadFlag flag, ChangeType type);
     virtual QString mimeType() const;
     void setMimeType(const QString &mt);
+    virtual void rename(const QString &newName);
 
     virtual QString defaultPath() const { return m_defaultPath; }
     virtual QString suggestedFileName() const { return m_suggestedFileName; }
index 3f4c3ad..648c0a6 100644 (file)
 
 using namespace TextEditor;
 
-bool Parenthesis::hasClosingCollapse(const Parentheses &parentheses)
-{
-    return closeCollapseAtPos(parentheses) >= 0;
-}
-
-int Parenthesis::closeCollapseAtPos(const Parentheses &parentheses)
-{
-    int depth = 0;
-    for (int i = 0; i < parentheses.size(); ++i) {
-        const Parenthesis &p = parentheses.at(i);
-        if (p.chr == QLatin1Char('{')
-            || p.chr == QLatin1Char('+')
-            || p.chr == QLatin1Char('[')) {
-            ++depth;
-        } else if (p.chr == QLatin1Char('}')
-            || p.chr == QLatin1Char('-')
-            || p.chr == QLatin1Char(']')) {
-            if (--depth < 0)
-                return p.pos;
-        }
-    }
-    return -1;
-}
-
-int Parenthesis::collapseAtPos(const Parentheses &parentheses, QChar *character)
-{
-    int result = -1;
-    QChar c;
-
-    int depth = 0;
-    for (int i = 0; i < parentheses.size(); ++i) {
-        const Parenthesis &p = parentheses.at(i);
-        if (p.chr == QLatin1Char('{')
-            || p.chr == QLatin1Char('+')
-            || p.chr == QLatin1Char('[')) {
-            if (depth == 0) {
-                result = p.pos;
-                c = p.chr;
-            }
-            ++depth;
-        } else if (p.chr == QLatin1Char('}')
-            || p.chr == QLatin1Char('-')
-            || p.chr == QLatin1Char(']')) {
-            if (--depth < 0)
-                depth = 0;
-            result = -1;
-        }
-    }
-    if (result >= 0 && character)
-        *character = c;
-    return result;
-}
-
-
 TextBlockUserData::~TextBlockUserData()
 {
     TextMarks marks = m_marks;
@@ -94,11 +40,6 @@ TextBlockUserData::~TextBlockUserData()
     }
 }
 
-int TextBlockUserData::collapseAtPos(QChar *character) const
-{
-    return Parenthesis::collapseAtPos(m_parentheses, character);
-}
-
 int TextBlockUserData::braceDepthDelta() const
 {
     int delta = 0;
@@ -112,96 +53,6 @@ int TextBlockUserData::braceDepthDelta() const
     return delta;
 }
 
-
-QTextBlock TextBlockUserData::testCollapse(const QTextBlock& block)
-{
-    QTextBlock info = block;
-    if (block.userData() && static_cast<TextBlockUserData*>(block.userData())->collapseMode() == CollapseAfter)
-        ;
-    else if (block.next().userData()
-             && static_cast<TextBlockUserData*>(block.next().userData())->collapseMode()
-             == TextBlockUserData::CollapseThis)
-        info = block.next();
-    else
-        return QTextBlock();
-    int pos = static_cast<TextBlockUserData*>(info.userData())->collapseAtPos();
-    if (pos < 0)
-        return QTextBlock();
-    QTextCursor cursor(info);
-    cursor.setPosition(cursor.position() + pos);
-    matchCursorForward(&cursor);
-    return cursor.block();
-}
-
-void TextBlockUserData::doCollapse(const QTextBlock& block, bool visible)
-{
-    QTextBlock info = block;
-    if (block.userData() && static_cast<TextBlockUserData*>(block.userData())->collapseMode() == CollapseAfter)
-        ;
-    else if (block.next().userData()
-             && static_cast<TextBlockUserData*>(block.next().userData())->collapseMode()
-             == TextBlockUserData::CollapseThis)
-        info = block.next();
-    else {
-        if (visible && !block.next().isVisible()) {
-            // no match, at least unfold!
-            QTextBlock b = block.next();
-            while (b.isValid() && !b.isVisible()) {
-                b.setVisible(true);
-                b.setLineCount(visible ? qMax(1, b.layout()->lineCount()) : 0);
-                b = b.next();
-            }
-        }
-        return;
-    }
-    int pos = static_cast<TextBlockUserData*>(info.userData())->collapseAtPos();
-    if (pos < 0)
-        return;
-    QTextCursor cursor(info);
-    cursor.setPosition(cursor.position() + pos);
-    if (matchCursorForward(&cursor) != Match) {
-        if (visible) {
-            // no match, at least unfold!
-            QTextBlock b = block.next();
-            while (b.isValid() && !b.isVisible()) {
-                b.setVisible(true);
-                b.setLineCount(visible ? qMax(1, b.layout()->lineCount()) : 0);
-                b = b.next();
-            }
-        }
-        return;
-    }
-
-    QTextBlock b = block.next();
-    while (b < cursor.block()) {
-        b.setVisible(visible);
-        b.setLineCount(visible ? qMax(1, b.layout()->lineCount()) : 0);
-        if (visible) {
-            TextBlockUserData *data = canCollapse(b);
-            if (data && data->collapsed()) {
-                QTextBlock end =  testCollapse(b);
-                if (data->collapseIncludesClosure())
-                    end = end.next();
-                if (end.isValid()) {
-                    b = end;
-                    continue;
-                }
-            }
-        }
-        b = b.next();
-    }
-
-    bool collapseIncludesClosure = hasClosingCollapseAtEnd(b);
-    if (collapseIncludesClosure) {
-        b.setVisible(visible);
-        b.setLineCount(visible ? qMax(1, b.layout()->lineCount()) : 0);
-    }
-    static_cast<TextBlockUserData*>(info.userData())->setCollapseIncludesClosure(collapseIncludesClosure);
-    static_cast<TextBlockUserData*>(info.userData())->setCollapsed(!block.next().isVisible());
-
-}
-
-
 TextBlockUserData::MatchType TextBlockUserData::checkOpenParenthesis(QTextCursor *cursor, QChar c)
 {
     QTextBlock block = cursor->block();
@@ -591,3 +442,74 @@ void BaseTextDocumentLayout::changeBraceDepth(QTextBlock &block, int delta)
     if (delta)
         setBraceDepth(block, braceDepth(block) + delta);
 }
+
+void BaseTextDocumentLayout::setFoldingIndent(const QTextBlock &block, int indent)
+{
+    if (indent == 0) {
+        if (TextBlockUserData *userData = testUserData(block))
+            userData->setFoldingIndent(0);
+    } else {
+        userData(block)->setFoldingIndent(qMax(0,indent));
+    }
+}
+
+int BaseTextDocumentLayout::foldingIndent(const QTextBlock &block)
+{
+    if (TextBlockUserData *userData = testUserData(block))
+        return userData->foldingIndent();
+    return 0;
+}
+
+void BaseTextDocumentLayout::changeFoldingIndent(QTextBlock &block, int delta)
+{
+    if (delta)
+        setFoldingIndent(block, foldingIndent(block) + delta);
+}
+
+bool BaseTextDocumentLayout::canFold(const QTextBlock &block)
+{
+    return (block.next().isValid() && foldingIndent(block.next()) > foldingIndent(block));
+}
+
+bool BaseTextDocumentLayout::isFolded(const QTextBlock &block)
+{
+    if (TextBlockUserData *userData = testUserData(block))
+        return userData->folded();
+    return false;
+}
+
+void BaseTextDocumentLayout::setFolded(const QTextBlock &block, bool folded)
+{
+    if (folded)
+        userData(block)->setFolded(true);
+    else {
+        if (TextBlockUserData *userData = testUserData(block))
+            return userData->setFolded(false);
+    }
+}
+
+void BaseTextDocumentLayout::doFoldOrUnfold(const QTextBlock& block, bool unfold)
+{
+    if (!canFold(block))
+        return;
+    QTextBlock b = block.next();
+
+    int indent = foldingIndent(block);
+    while (b.isValid() && foldingIndent(b) > indent && b.next().isValid()) {
+        b.setVisible(unfold);
+        b.setLineCount(unfold? qMax(1, b.layout()->lineCount()) : 0);
+        if (unfold) { // do not unfold folded sub-blocks
+            if (isFolded(b) && b.next().isValid()) {
+                int jndent = foldingIndent(b);
+                b = b.next();
+                while (b.isValid() && foldingIndent(b) > jndent)
+                    b = b.next();
+                continue;
+            }
+        }
+        b = b.next();
+    }
+    setFolded(block, !unfold);
+}
+
+
index c2ba64a..c76a628 100644 (file)
@@ -52,9 +52,6 @@ struct TEXTEDITOR_EXPORT Parenthesis
     Type type;
     QChar chr;
     int pos;
-    static int collapseAtPos(const Parentheses &parentheses, QChar *character = 0);
-    static int closeCollapseAtPos(const Parentheses &parentheses);
-    static bool hasClosingCollapse(const Parentheses &parentheses);
 };
 
 
@@ -62,15 +59,12 @@ class TEXTEDITOR_EXPORT TextBlockUserData : public QTextBlockUserData
 {
 public:
 
-    enum CollapseMode { NoCollapse , CollapseThis, CollapseAfter };
-    enum ClosingCollapseMode { NoClosingCollapse, ClosingCollapse, ClosingCollapseAtEnd };
-
     inline TextBlockUserData()
-        : m_collapseIncludesClosure(false),
-          m_collapseMode(NoCollapse),
-          m_closingCollapseMode(NoClosingCollapse),
-          m_collapsed(false),
-          m_ifdefedOut(false) {}
+        : m_folded(false),
+          m_ifdefedOut(false),
+          m_foldingIndent(0),
+          m_foldingStartIncluded(false),
+          m_foldingEndIncluded(false){}
     ~TextBlockUserData();
 
     inline TextMarks marks() const { return m_marks; }
@@ -80,21 +74,8 @@ public:
     inline void clearMarks() { m_marks.clear(); }
     inline void documentClosing() { Q_FOREACH(ITextMark *tm, m_marks) { tm->documentClosing(); } m_marks.clear();}
 
-    inline CollapseMode collapseMode() const { return (CollapseMode)m_collapseMode; }
-    inline void setCollapseMode(CollapseMode c) { m_collapseMode = c; }
-
-    inline void setClosingCollapseMode(ClosingCollapseMode c) { m_closingCollapseMode = c; }
-    inline ClosingCollapseMode closingCollapseMode() const { return (ClosingCollapseMode) m_closingCollapseMode; }
-
-    inline bool hasClosingCollapse() const { return closingCollapseMode() != NoClosingCollapse; }
-    inline bool hasClosingCollapseAtEnd() const { return closingCollapseMode() == ClosingCollapseAtEnd; }
-    inline bool hasClosingCollapseInside() const { return closingCollapseMode() == ClosingCollapse; }
-
-    inline void setCollapsed(bool b) { m_collapsed = b; }
-    inline bool collapsed() const { return m_collapsed; }
-
-    inline void setCollapseIncludesClosure(bool b) { m_collapseIncludesClosure = b; }
-    inline bool collapseIncludesClosure() const { return m_collapseIncludesClosure; }
+    inline void setFolded(bool b) { m_folded = b; }
+    inline bool folded() const { return m_folded; }
 
     inline void setParentheses(const Parentheses &parentheses) { m_parentheses = parentheses; }
     inline void clearParentheses() { m_parentheses.clear(); }
@@ -106,49 +87,6 @@ public:
     inline bool clearIfdefedOut() { bool result = m_ifdefedOut; m_ifdefedOut = false; return result;}
     inline bool ifdefedOut() const { return m_ifdefedOut; }
 
-    inline static TextBlockUserData *canCollapse(const QTextBlock &block) {
-        TextBlockUserData *data = static_cast<TextBlockUserData*>(block.userData());
-        if (!data || data->collapseMode() != CollapseAfter) {
-            data = static_cast<TextBlockUserData*>(block.next().userData());
-            if (!data || data->collapseMode() != TextBlockUserData::CollapseThis)
-                data = 0;
-        }
-        if (data && data->m_ifdefedOut)
-            data = 0;
-        return data;
-    }
-
-    inline static bool hasCollapseAfter(const QTextBlock & block)
-    {
-        if (!block.isValid()) {
-            return false;
-        } else if (block.next().isValid()) {
-            TextBlockUserData *data = static_cast<TextBlockUserData*>(block.next().userData());
-            if (data && data->collapseMode() == TextBlockUserData::CollapseThis &&  !data->m_ifdefedOut)
-                return true;
-        }
-        return false;
-    }
-
-    inline static bool hasClosingCollapse(const QTextBlock &block) {
-        TextBlockUserData *data = static_cast<TextBlockUserData*>(block.userData());
-        return (data && data->hasClosingCollapse());
-    }
-
-    inline static bool hasClosingCollapseAtEnd(const QTextBlock &block) {
-        TextBlockUserData *data = static_cast<TextBlockUserData*>(block.userData());
-        return (data && data->hasClosingCollapseAtEnd());
-    }
-
-    inline static bool hasClosingCollapseInside(const QTextBlock &block) {
-        TextBlockUserData *data = static_cast<TextBlockUserData*>(block.userData());
-        return (data && data->hasClosingCollapseInside());
-    }
-
-    static QTextBlock testCollapse(const QTextBlock& block);
-    static void doCollapse(const QTextBlock& block, bool visible);
-
-    int collapseAtPos(QChar *character = 0) const;
 
     enum MatchType { NoMatch, Match, Mismatch  };
     static MatchType checkOpenParenthesis(QTextCursor *cursor, QChar c);
@@ -161,14 +99,21 @@ public:
     static bool findPreviousBlockOpenParenthesis(QTextCursor *cursor, bool checkStartPosition = false);
     static bool findNextBlockClosingParenthesis(QTextCursor *cursor);
 
+    int foldingIndent() const { return m_foldingIndent; }
+    void setFoldingIndent(int indent) { m_foldingIndent = indent; }
+    void setFoldingStartIncluded(bool included) { m_foldingStartIncluded = included; }
+    bool foldingStartIncluded() const { return m_foldingStartIncluded; }
+    void setFoldingEndIncluded(bool included) { m_foldingEndIncluded = included; }
+    bool foldingEndIncluded() const { return m_foldingEndIncluded; }
+
 
 private:
     TextMarks m_marks;
-    uint m_collapseIncludesClosure : 1;
-    uint m_collapseMode : 4;
-    uint m_closingCollapseMode : 4;
-    uint m_collapsed : 1;
+    uint m_folded : 1;
     uint m_ifdefedOut : 1;
+    uint m_foldingIndent : 16;
+    uint m_foldingStartIncluded : 1;
+    uint m_foldingEndIncluded : 1;
     Parentheses m_parentheses;
 };
 
@@ -192,6 +137,13 @@ public:
     static int braceDepth(const QTextBlock &block);
     static void setBraceDepth(QTextBlock &block, int depth);
     static void changeBraceDepth(QTextBlock &block, int delta);
+    static void setFoldingIndent(const QTextBlock &block, int indent);
+    static int foldingIndent(const QTextBlock &block);
+    static void changeFoldingIndent(QTextBlock &block, int delta);
+    static bool canFold(const QTextBlock &block);
+    static void doFoldOrUnfold(const QTextBlock& block, bool unfold);
+    static bool isFolded(const QTextBlock &block);
+    static void setFolded(const QTextBlock &block, bool folded);
 
     static TextBlockUserData *testUserData(const QTextBlock &block) {
         return static_cast<TextBlockUserData*>(block.userData());
index fca4b85..178e857 100644 (file)
@@ -202,11 +202,10 @@ BaseTextEditor::BaseTextEditor(QWidget *parent)
     viewport()->setMouseTracking(true);
     d->extraAreaSelectionAnchorBlockNumber
         = d->extraAreaToggleMarkBlockNumber
-        = d->extraAreaHighlightCollapseBlockNumber
-        = d->extraAreaHighlightCollapseColumn
+        = d->extraAreaHighlightFoldedBlockNumber
         = -1;
 
-    d->visibleCollapsedBlockNumber = d->suggestedVisibleCollapsedBlockNumber = -1;
+    d->visibleFoldedBlockNumber = d->suggestedVisibleFoldedBlockNumber = -1;
 
     connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(slotUpdateExtraAreaWidth()));
     connect(this, SIGNAL(modificationChanged(bool)), this, SLOT(slotModificationChanged(bool)));
@@ -280,7 +279,7 @@ void BaseTextEditor::print(QPrinter *printer)
     delete dlg;
 }
 
-static int collapseBoxWidth(const QFontMetrics &fm)
+static int foldBoxWidth(const QFontMetrics &fm)
 {
     const int lineSpacing = fm.lineSpacing();
     return lineSpacing + lineSpacing%2 + 1;
@@ -585,7 +584,7 @@ bool BaseTextEditor::open(const QString &fileName)
 /*
   Collapses the first comment in a file, if there is only whitespace above
   */
-void BaseTextEditorPrivate::collapseLicenseHeader()
+void BaseTextEditorPrivate::foldLicenseHeader()
 {
     QTextDocument *doc = q->document();
     BaseTextDocumentLayout *documentLayout = qobject_cast<BaseTextDocumentLayout*>(doc->documentLayout());
@@ -593,19 +592,16 @@ void BaseTextEditorPrivate::collapseLicenseHeader()
     QTextBlock block = doc->firstBlock();
     const TabSettings &ts = m_document->tabSettings();
     while (block.isValid() && block.isVisible()) {
-        TextBlockUserData *data = TextBlockUserData::canCollapse(block);
-        if (data && block.next().isVisible()) {
-            QChar character;
-            static_cast<TextBlockUserData*>(data)->collapseAtPos(&character);
-            if (character != QLatin1Char('+'))
-                break; // not a comment
-            TextBlockUserData::doCollapse(block, false);
-            moveCursorVisible();
-            documentLayout->requestUpdate();
-            documentLayout->emitDocumentSizeChanged();
-            break;
-        }
         QString text = block.text();
+        if (BaseTextDocumentLayout::canFold(block) && block.next().isVisible()) {
+            if (text.trimmed().startsWith(QLatin1String("/*"))) {
+                BaseTextDocumentLayout::doFoldOrUnfold(block, false);
+                moveCursorVisible();
+                documentLayout->requestUpdate();
+                documentLayout->emitDocumentSizeChanged();
+                break;
+            }
+        }
         if (ts.firstNonSpace(text) < text.size())
             break;
         block = block.next();
@@ -963,6 +959,29 @@ void BaseTextEditor::joinLines()
     setTextCursor(cursor);
 }
 
+void BaseTextEditor::insertLineAbove()
+{
+    QTextCursor cursor = textCursor();
+    cursor.beginEditBlock();
+    cursor.movePosition(QTextCursor::PreviousBlock, QTextCursor::MoveAnchor);
+    cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::MoveAnchor);
+    cursor.insertBlock();
+    indent(document(), cursor, QChar::Null);
+    cursor.endEditBlock();
+    setTextCursor(cursor);
+}
+
+void BaseTextEditor::insertLineBelow()
+{
+    QTextCursor cursor = textCursor();
+    cursor.beginEditBlock();
+    cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::MoveAnchor);
+    cursor.insertBlock();
+    indent(document(), cursor, QChar::Null);
+    cursor.endEditBlock();
+    setTextCursor(cursor);
+}
+
 void BaseTextEditor::moveLineUp()
 {
     moveLineUpDown(true);
@@ -978,7 +997,7 @@ void BaseTextEditor::moveLineUpDown(bool up)
     QTextCursor cursor = textCursor();
     QTextCursor move = cursor;
 
-    move.setVisualNavigation(false); // this opens collapsed items instead of destroying them
+    move.setVisualNavigation(false); // this opens folded items instead of destroying them
 
     if (d->m_moveLineUndoHack)
         move.joinPreviousEditBlock();
@@ -1045,7 +1064,7 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e)
     QToolTip::hideText();
 
     d->m_moveLineUndoHack = false;
-    d->clearVisibleCollapsedBlock();
+    d->clearVisibleFoldedBlock();
 
     QKeyEvent *original_e = e;
     d->m_lastEventWasBlockSelectionEvent = false;
@@ -1606,19 +1625,16 @@ QByteArray BaseTextEditor::saveState() const
     stream << column;
 
     // store code folding state
-    QList<int> collapsedBlocks;
+    QList<int> foldedBlocks;
     QTextBlock block = document()->firstBlock();
     while (block.isValid()) {
-        if (block.userData() && static_cast<TextBlockUserData*>(block.userData())->collapsed()) {
+        if (block.userData() && static_cast<TextBlockUserData*>(block.userData())->folded()) {
             int number = block.blockNumber();
-            if (static_cast<TextBlockUserData*>(block.userData())->collapseMode()
-                == TextBlockUserData::CollapseThis)
-                number--;
-            collapsedBlocks += number;
+            foldedBlocks += number;
         }
         block = block.next();
     }
-    stream << collapsedBlocks;
+    stream << foldedBlocks;
 
     return state;
 }
@@ -1627,7 +1643,7 @@ bool BaseTextEditor::restoreState(const QByteArray &state)
 {
     if (state.isEmpty()) {
         if (d->m_displaySettings.m_autoFoldFirstComment)
-            d->collapseLicenseHeader();
+            d->foldLicenseHeader();
         return false;
     }
     int version;
@@ -1649,11 +1665,11 @@ bool BaseTextEditor::restoreState(const QByteArray &state)
         foreach(int blockNumber, collapsedBlocks) {
             QTextBlock block = doc->findBlockByNumber(qMax(0, blockNumber));
             if (block.isValid())
-                TextBlockUserData::doCollapse(block, false);
+                BaseTextDocumentLayout::doFoldOrUnfold(block, false);
         }
     } else {
         if (d->m_displaySettings.m_autoFoldFirstComment)
-            d->collapseLicenseHeader();
+            d->foldLicenseHeader();
     }
 
     d->m_lastCursorChangeWasInteresting = false; // avoid adding last position to history
@@ -1827,7 +1843,7 @@ BaseTextEditorPrivate::BaseTextEditorPrivate()
     m_parenthesesMatchingEnabled(false),
     m_autoParenthesesEnabled(true),
     m_extraArea(0),
-    m_mouseOnCollapsedMarker(false),
+    m_mouseOnFoldedMarker(false),
     m_marksVisible(false),
     m_codeFoldingVisible(false),
     m_codeFoldingSupported(false),
@@ -1976,29 +1992,26 @@ void BaseTextEditor::resizeEvent(QResizeEvent *e)
                            QRect(cr.left(), cr.top(), extraAreaWidth(), cr.height())));
 }
 
-QRect BaseTextEditor::collapseBox()
+QRect BaseTextEditor::foldBox()
 {
-    if (d->m_highlightBlocksInfo.isEmpty() || d->extraAreaHighlightCollapseBlockNumber < 0)
+    if (d->m_highlightBlocksInfo.isEmpty() || d->extraAreaHighlightFoldedBlockNumber < 0)
         return QRect();
 
     QTextBlock begin = document()->findBlockByNumber(d->m_highlightBlocksInfo.open.last());
 
-    if (TextBlockUserData::hasCollapseAfter(begin.previous()))
-        begin = begin.previous();
-
     QTextBlock end = document()->findBlockByNumber(d->m_highlightBlocksInfo.close.first());
     if (!begin.isValid() || !end.isValid())
         return QRect();
     QRectF br = blockBoundingGeometry(begin).translated(contentOffset());
     QRectF er = blockBoundingGeometry(end).translated(contentOffset());
 
-    return QRect(d->m_extraArea->width() - collapseBoxWidth(fontMetrics()),
+    return QRect(d->m_extraArea->width() - foldBoxWidth(fontMetrics()),
                  int(br.top()),
-                 collapseBoxWidth(fontMetrics()),
+                 foldBoxWidth(fontMetrics()),
                  er.bottom() - br.top());
 }
 
-QTextBlock BaseTextEditor::collapsedBlockAt(const QPoint &pos, QRect *box) const
+QTextBlock BaseTextEditor::foldedBlockAt(const QPoint &pos, QRect *box) const
 {
     QPointF offset(contentOffset());
     QTextBlock block = firstVisibleBlock();
@@ -2331,14 +2344,6 @@ void BaseTextEditor::paintEvent(QPaintEvent *e)
                 for (int i = 0; i <= depth; ++i) {
                     int vi = i > 0 ? d->m_highlightBlocksInfo.visualIndent.at(i-1) : 0;
                     painter.fillRect(rr.adjusted(vi, 0, -8*i, 0), calcBlendColor(baseColor, i, count));
-                    if (d->m_highlightCurrentLine && blockFP == textCursorBlock) {
-                        QRectF rrr = blockFP.layout()->lineForTextPosition(textCursor().positionInBlock()).rect();
-                        rrr.moveTop(rrr.top() + rr.top());
-                        rrr.setLeft(rr.left());
-                        rrr.setRight(rr.right());
-                        painter.fillRect(rrr.adjusted(vi, 0, -8*i, 0),
-                                         calcBlendColor(d->m_currentLineFormat.background().color(), i, count));
-                    }
                 }
 
             }
@@ -2510,26 +2515,10 @@ void BaseTextEditor::paintEvent(QPaintEvent *e)
                 rr.moveTop(rr.top() + r.top());
                 rr.setLeft(0);
                 rr.setRight(viewportRect.width() - offset.x());
-                if (lineX > 0) {
-                    if (lineX < rr.right()) {
-                        QRectF rrr = rr;
-                        rrr.setLeft(lineX);
-                        painter.fillRect(rrr,
-                                         blendColors(
-                                                 d->m_currentLineFormat.background().color(),
-                                                 d->m_ifdefedOutFormat.background().color(),
-                                                 50)
-                                         );
-                        const QColor col = (palette().base().color().value() > 128) ? Qt::black : Qt::white;
-                        const QPen pen = painter.pen();
-                        painter.setPen(blendColors(d->m_currentLineFormat.background().color(), col, 32));
-                        painter.drawLine(QPointF(lineX, rr.top()), QPointF(lineX, rr.bottom()));
-                        painter.setPen(pen);
-                    }
-                    rr.setRight(qMin(lineX, rr.right()));
-                }
-                if (d->m_highlightBlocksInfo.isEmpty() || BaseTextDocumentLayout::ifdefedOut(block))
-                    painter.fillRect(rr, d->m_currentLineFormat.background());
+                QColor color = d->m_currentLineFormat.background().color();
+                // set alpha, otherwise we cannot see block highlighting and find scope underneath
+                color.setAlpha(128);
+                painter.fillRect(rr, color);
             }
 
             bool drawCursor = ((editable || true) // we want the cursor in read-only mode
@@ -2598,7 +2587,7 @@ void BaseTextEditor::paintEvent(QPaintEvent *e)
         block = block.next();
 
         if (!block.isVisible()) {
-            if (block.blockNumber() == d->visibleCollapsedBlockNumber) {
+            if (block.blockNumber() == d->visibleFoldedBlockNumber) {
                 visibleCollapsedBlock = block;
                 visibleCollapsedBlockOffset = offset + QPointF(0,1);
             }
@@ -2702,34 +2691,29 @@ void BaseTextEditor::paintEvent(QPaintEvent *e)
 
                 QString replacement = QLatin1String("...");
 
-                QTextBlock info = block;
-                if (block.userData()
-                    && static_cast<TextBlockUserData*>(block.userData())->collapseMode() == TextBlockUserData::CollapseAfter)
-                    ;
-                else if (block.next().userData()
-                         && static_cast<TextBlockUserData*>(block.next().userData())->collapseMode()
-                         == TextBlockUserData::CollapseThis) {
-                    replacement.prepend(nextBlock.text().trimmed().left(1));
-                    info = nextBlock;
+                if (TextBlockUserData *nextBlockUserData = BaseTextDocumentLayout::testUserData(nextBlock)) {
+                    if (nextBlockUserData->foldingStartIncluded())
+                        replacement.prepend(nextBlock.text().trimmed().left(1));
                 }
 
-
                 block = nextVisibleBlock.previous();
                 if (!block.isValid())
                     block = doc->lastBlock();
 
-                if (info.userData()
-                    && static_cast<TextBlockUserData*>(info.userData())->collapseIncludesClosure()) {
-                    QString right = block.text().trimmed();
-                    if (right.endsWith(QLatin1Char(';'))) {
-                        right.chop(1);
-                        right = right.trimmed();
-                        replacement.append(right.right(right.endsWith(QLatin1Char('/')) ? 2 : 1));
-                        replacement.append(QLatin1Char(';'));
-                    } else {
-                        replacement.append(right.right(right.endsWith(QLatin1Char('/')) ? 2 : 1));
+                if (TextBlockUserData *blockUserData = BaseTextDocumentLayout::testUserData(block)) {
+                    if (blockUserData->foldingEndIncluded()) {
+                        QString right = block.text().trimmed();
+                        if (right.endsWith(QLatin1Char(';'))) {
+                            right.chop(1);
+                            right = right.trimmed();
+                            replacement.append(right.right(right.endsWith(QLatin1Char('/')) ? 2 : 1));
+                            replacement.append(QLatin1Char(';'));
+                        } else {
+                            replacement.append(right.right(right.endsWith(QLatin1Char('/')) ? 2 : 1));
+                        }
                     }
                 }
+
                 if (selectThis)
                     painter.setPen(palette().highlightedText().color());
                 painter.drawText(collapseRect, Qt::AlignCenter, replacement);
@@ -2865,7 +2849,7 @@ int BaseTextEditor::extraAreaWidth(int *markWidthPtr) const
     space += 4;
 
     if (d->m_codeFoldingVisible)
-        space += collapseBoxWidth(fm);
+        space += foldBoxWidth(fm);
     return space;
 }
 
@@ -2925,7 +2909,7 @@ void BaseTextEditor::extraAreaPaintEvent(QPaintEvent *e)
     if (d->m_marksVisible)
         markWidth += fm.lineSpacing();
 
-    const int collapseColumnWidth = d->m_codeFoldingVisible ? collapseBoxWidth(fm): 0;
+    const int collapseColumnWidth = d->m_codeFoldingVisible ? foldBoxWidth(fm): 0;
     const int extraAreaWidth = d->m_extraArea->width() - collapseColumnWidth;
 
     painter.fillRect(e->rect(), pal.color(QPalette::Base));
@@ -2997,50 +2981,35 @@ void BaseTextEditor::extraAreaPaintEvent(QPaintEvent *e)
 
             if (d->m_codeFoldingVisible) {
 
-                bool collapseThis = false;
-                bool collapseAfter = false;
-                bool hasClosingCollapse = false;
-
-                if (TextBlockUserData *userData = static_cast<TextBlockUserData*>(block.userData())) {
-                    if (!userData->ifdefedOut()) {
-                        collapseAfter = (userData->collapseMode() == TextBlockUserData::CollapseAfter);
-                        collapseThis = (userData->collapseMode() == TextBlockUserData::CollapseThis);
-                        hasClosingCollapse = userData->hasClosingCollapse() && (previousBraceDepth > 0);
-                    }
-                }
-
-                int extraAreaHighlightCollapseBlockNumber = -1;
-                int extraAreaHighlightCollapseEndBlockNumber = -1;
+                int extraAreaHighlightFoldBlockNumber = -1;
+                int extraAreaHighlightFoldEndBlockNumber = -1;
                 bool endIsVisible = false;
                 if (!d->m_highlightBlocksInfo.isEmpty()) {
-                    extraAreaHighlightCollapseBlockNumber =  d->m_highlightBlocksInfo.open.last();
-                    extraAreaHighlightCollapseEndBlockNumber =  d->m_highlightBlocksInfo.close.first();
-                    endIsVisible = doc->findBlockByNumber(extraAreaHighlightCollapseEndBlockNumber).isVisible();
-
-                    QTextBlock before = doc->findBlockByNumber(extraAreaHighlightCollapseBlockNumber-1);
-                    if (TextBlockUserData::hasCollapseAfter(before)) {
-                        extraAreaHighlightCollapseBlockNumber--;
-                    }
+                    extraAreaHighlightFoldBlockNumber =  d->m_highlightBlocksInfo.open.last();
+                    extraAreaHighlightFoldEndBlockNumber =  d->m_highlightBlocksInfo.close.first();
+                    endIsVisible = doc->findBlockByNumber(extraAreaHighlightFoldEndBlockNumber).isVisible();
+
+//                    QTextBlock before = doc->findBlockByNumber(extraAreaHighlightCollapseBlockNumber-1);
+//                    if (TextBlockUserData::hasCollapseAfter(before)) {
+//                        extraAreaHighlightCollapseBlockNumber--;
+//                    }
                 }
 
                 TextBlockUserData *nextBlockUserData = BaseTextDocumentLayout::testUserData(nextBlock);
 
-                bool collapseNext = nextBlockUserData
-                                    && nextBlockUserData->collapseMode() == TextBlockUserData::CollapseThis
-                                    && !nextBlockUserData->ifdefedOut();
+                bool drawBox = nextBlockUserData
+                               && BaseTextDocumentLayout::foldingIndent(block) < nextBlockUserData->foldingIndent();
+
 
-                bool nextHasClosingCollapse = nextBlockUserData
-                                              && nextBlockUserData->hasClosingCollapseInside()
-                                              && nextBlockUserData->ifdefedOut();
 
-                bool drawBox = ((collapseAfter || collapseNext) && !nextHasClosingCollapse);
-                bool active = blockNumber == extraAreaHighlightCollapseBlockNumber;
-                bool drawStart = drawBox && active;
-                bool drawEnd = blockNumber == extraAreaHighlightCollapseEndBlockNumber || (drawStart && !endIsVisible);
-                bool hovered = blockNumber >= extraAreaHighlightCollapseBlockNumber
-                               && blockNumber <= extraAreaHighlightCollapseEndBlockNumber;
+                bool active = blockNumber == extraAreaHighlightFoldBlockNumber;
 
-                int boxWidth = collapseBoxWidth(fm);
+                bool drawStart = active;
+                bool drawEnd = blockNumber == extraAreaHighlightFoldEndBlockNumber || (drawStart && !endIsVisible);
+                bool hovered = blockNumber >= extraAreaHighlightFoldBlockNumber
+                               && blockNumber <= extraAreaHighlightFoldEndBlockNumber;
+
+                int boxWidth = foldBoxWidth(fm);
                 if (hovered) {
                     int itop = qRound(top);
                     int ibottom = qRound(bottom);
@@ -3241,8 +3210,8 @@ void BaseTextEditor::slotCursorPositionChanged()
 {
 #if 0
     qDebug() << "block" << textCursor().blockNumber()+1
-            << "depth:" << BaseTextDocumentLayout::braceDepth(textCursor().block())
-            << '/' << BaseTextDocumentLayout::braceDepth(document()->lastBlock());
+            << "brace depth:" << BaseTextDocumentLayout::braceDepth(textCursor().block())
+            << "indent:" << BaseTextDocumentLayout::userData(textCursor().block())->foldingIndent();
 #endif
     if (!d->m_contentsChanged && d->m_lastCursorChangeWasInteresting) {
         Core::EditorManager::instance()->addCurrentPositionToNavigationHistory(editableInterface(), d->m_tempNavigationState);
@@ -3271,8 +3240,7 @@ void BaseTextEditor::updateHighlights()
 
     if (d->m_displaySettings.m_highlightBlocks) {
         QTextCursor cursor = textCursor();
-        d->extraAreaHighlightCollapseBlockNumber = cursor.blockNumber();
-        d->extraAreaHighlightCollapseColumn = cursor.position() - cursor.block().position();
+        d->extraAreaHighlightFoldedBlockNumber = cursor.blockNumber();
         d->m_highlightBlocksTimer->start(100);
     }
 }
@@ -3292,7 +3260,7 @@ void BaseTextEditor::slotUpdateBlockNotify(const QTextBlock &block)
         /* The syntax highlighting state changes. This opens up for
            the possibility that the paragraph has braces that support
            code folding. In this case, do the save thing and also
-           update the previous block, which might contain a collapse
+           update the previous block, which might contain a fold
            box which now is invalid.*/
             emit requestBlockUpdate(block.previous());
         }
@@ -3327,24 +3295,24 @@ void BaseTextEditor::timerEvent(QTimerEvent *e)
         int timeout = 4900 / (delta * delta);
         d->autoScrollTimer.start(timeout, this);
 
-    } else if (e->timerId() == d->collapsedBlockTimer.timerId()) {
-        d->visibleCollapsedBlockNumber = d->suggestedVisibleCollapsedBlockNumber;
-        d->suggestedVisibleCollapsedBlockNumber = -1;
-        d->collapsedBlockTimer.stop();
+    } else if (e->timerId() == d->foldedBlockTimer.timerId()) {
+        d->visibleFoldedBlockNumber = d->suggestedVisibleFoldedBlockNumber;
+        d->suggestedVisibleFoldedBlockNumber = -1;
+        d->foldedBlockTimer.stop();
         viewport()->update();
     }
     QPlainTextEdit::timerEvent(e);
 }
 
 
-void BaseTextEditorPrivate::clearVisibleCollapsedBlock()
+void BaseTextEditorPrivate::clearVisibleFoldedBlock()
 {
-    if (suggestedVisibleCollapsedBlockNumber) {
-        suggestedVisibleCollapsedBlockNumber = -1;
-        collapsedBlockTimer.stop();
+    if (suggestedVisibleFoldedBlockNumber) {
+        suggestedVisibleFoldedBlockNumber = -1;
+        foldedBlockTimer.stop();
     }
-    if (visibleCollapsedBlockNumber >= 0) {
-        visibleCollapsedBlockNumber = -1;
+    if (visibleFoldedBlockNumber >= 0) {
+        visibleFoldedBlockNumber = -1;
         q->viewport()->update();
     }
 }
@@ -3356,21 +3324,21 @@ void BaseTextEditor::mouseMoveEvent(QMouseEvent *e)
     updateLink(e);
 
     if (e->buttons() == Qt::NoButton) {
-        const QTextBlock collapsedBlock = collapsedBlockAt(e->pos());
+        const QTextBlock collapsedBlock = foldedBlockAt(e->pos());
         const int blockNumber = collapsedBlock.next().blockNumber();
         if (blockNumber < 0) {
-            d->clearVisibleCollapsedBlock();
-        } else if (blockNumber != d->visibleCollapsedBlockNumber) {
-            d->suggestedVisibleCollapsedBlockNumber = blockNumber;
-            d->collapsedBlockTimer.start(40, this);
+            d->clearVisibleFoldedBlock();
+        } else if (blockNumber != d->visibleFoldedBlockNumber) {
+            d->suggestedVisibleFoldedBlockNumber = blockNumber;
+            d->foldedBlockTimer.start(40, this);
         }
 
         // Update the mouse cursor
-        if (collapsedBlock.isValid() && !d->m_mouseOnCollapsedMarker) {
-            d->m_mouseOnCollapsedMarker = true;
+        if (collapsedBlock.isValid() && !d->m_mouseOnFoldedMarker) {
+            d->m_mouseOnFoldedMarker = true;
             viewport()->setCursor(Qt::PointingHandCursor);
-        } else if (!collapsedBlock.isValid() && d->m_mouseOnCollapsedMarker) {
-            d->m_mouseOnCollapsedMarker = false;
+        } else if (!collapsedBlock.isValid() && d->m_mouseOnFoldedMarker) {
+            d->m_mouseOnFoldedMarker = false;
             viewport()->setCursor(Qt::IBeamCursor);
         }
     } else {
@@ -3406,9 +3374,9 @@ void BaseTextEditor::mousePressEvent(QMouseEvent *e)
     if (e->button() == Qt::LeftButton) {
         d->clearBlockSelection(); // just in case, otherwise we might get strange drag and drop
 
-        QTextBlock collapsedBlock = collapsedBlockAt(e->pos());
-        if (collapsedBlock.isValid()) {
-            toggleBlockVisible(collapsedBlock);
+        QTextBlock foldedBlock = foldedBlockAt(e->pos());
+        if (foldedBlock.isValid()) {
+            toggleBlockVisible(foldedBlock);
             viewport()->setCursor(Qt::IBeamCursor);
         }
 
@@ -3486,7 +3454,6 @@ void BaseTextEditor::extraAreaLeaveEvent(QEvent *)
 void BaseTextEditor::extraAreaMouseEvent(QMouseEvent *e)
 {
     QTextCursor cursor = cursorForPosition(QPoint(0, e->pos().y()));
-    cursor.setPosition(cursor.block().position());
 
     int markWidth;
     extraAreaWidth(&markWidth);
@@ -3494,34 +3461,19 @@ void BaseTextEditor::extraAreaMouseEvent(QMouseEvent *e)
     if (d->m_codeFoldingVisible
         && e->type() == QEvent::MouseMove && e->buttons() == 0) { // mouse tracking
         // Update which folder marker is highlighted
-        const int highlightBlockNumber = d->extraAreaHighlightCollapseBlockNumber;
-        const int highlightColumn = d->extraAreaHighlightCollapseColumn;
-        d->extraAreaHighlightCollapseBlockNumber = -1;
-        d->extraAreaHighlightCollapseColumn = -1;
-
-        if (e->pos().x() > extraArea()->width() - collapseBoxWidth(fontMetrics())) {
-            d->extraAreaHighlightCollapseBlockNumber = cursor.blockNumber();
-            if (TextBlockUserData::canCollapse(cursor.block())
-                || !TextBlockUserData::hasClosingCollapse(cursor.block()))
-                d->extraAreaHighlightCollapseColumn = cursor.block().length()-1;
-            if (TextBlockUserData::hasCollapseAfter(cursor.block())) {
-                d->extraAreaHighlightCollapseBlockNumber++;
-                d->extraAreaHighlightCollapseColumn = -1;
-                if (TextBlockUserData::canCollapse(cursor.block().next())
-                    || !TextBlockUserData::hasClosingCollapse(cursor.block().next()))
-                    d->extraAreaHighlightCollapseColumn = cursor.block().next().length()-1;
-            }
+        const int highlightBlockNumber = d->extraAreaHighlightFoldedBlockNumber;
+        d->extraAreaHighlightFoldedBlockNumber = -1;
+
+        if (e->pos().x() > extraArea()->width() - foldBoxWidth(fontMetrics())) {
+            d->extraAreaHighlightFoldedBlockNumber = cursor.blockNumber();
         } else if (d->m_displaySettings.m_highlightBlocks) {
             QTextCursor cursor = textCursor();
-            d->extraAreaHighlightCollapseBlockNumber = cursor.blockNumber();
-            d->extraAreaHighlightCollapseColumn = cursor.position() - cursor.block().position();
+            d->extraAreaHighlightFoldedBlockNumber = cursor.blockNumber();
         }
 
-        if (highlightBlockNumber != d->extraAreaHighlightCollapseBlockNumber
-            || highlightColumn != d->extraAreaHighlightCollapseColumn) {
+        if (highlightBlockNumber != d->extraAreaHighlightFoldedBlockNumber)
             d->m_highlightBlocksTimer->start(d->m_highlightBlocksInfo.isEmpty() ? 120 : 0);
         }
-    }
 
     // Set whether the mouse cursor is a hand or normal arrow
     if (e->type() == QEvent::MouseMove) {
@@ -3532,18 +3484,16 @@ void BaseTextEditor::extraAreaMouseEvent(QMouseEvent *e)
 
     if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonDblClick) {
         if (e->button() == Qt::LeftButton) {
-            int boxWidth = collapseBoxWidth(fontMetrics());
+            int boxWidth = foldBoxWidth(fontMetrics());
             if (d->m_codeFoldingVisible && e->pos().x() > extraArea()->width() - boxWidth) {
                 if (!cursor.block().next().isVisible()) {
                     toggleBlockVisible(cursor.block());
                     d->moveCursorVisible(false);
-                } else if (collapseBox().contains(e->pos())) {
+                } else if (foldBox().contains(e->pos())) {
                     cursor.setPosition(
                             document()->findBlockByNumber(d->m_highlightBlocksInfo.open.last()).position()
                             );
                     QTextBlock c = cursor.block();
-                    if (TextBlockUserData::hasCollapseAfter(c.previous()))
-                        c = c.previous();
                     toggleBlockVisible(c);
                     d->moveCursorVisible(false);
                 }
@@ -3620,7 +3570,7 @@ void BaseTextEditor::toggleBlockVisible(const QTextBlock &block)
     QTC_ASSERT(documentLayout, return);
 
     bool visible = block.next().isVisible();
-    TextBlockUserData::doCollapse(block, !visible);
+    BaseTextDocumentLayout::doFoldOrUnfold(block, !visible);
     documentLayout->requestUpdate();
     documentLayout->emitDocumentSizeChanged();
 }
@@ -3767,7 +3717,7 @@ void BaseTextEditor::handleBackspaceKey()
 
 void BaseTextEditor::wheelEvent(QWheelEvent *e)
 {
-    d->clearVisibleCollapsedBlock();
+    d->clearVisibleFoldedBlock();
     if (scrollWheelZoomingEnabled() && e->modifiers() & Qt::ControlModifier) {
         const int delta = e->delta();
         if (delta < 0)
@@ -3781,7 +3731,7 @@ void BaseTextEditor::wheelEvent(QWheelEvent *e)
 
 void BaseTextEditor::zoomIn(int range)
 {
-    d->clearVisibleCollapsedBlock();
+    d->clearVisibleFoldedBlock();
     emit requestFontZoom(range*10);
 }
 
@@ -4434,30 +4384,56 @@ void BaseTextEditor::_q_highlightBlocks()
 {
     BaseTextEditorPrivateHighlightBlocks highlightBlocksInfo;
 
-    if (d->extraAreaHighlightCollapseBlockNumber >= 0) {
-        QTextBlock block = document()->findBlockByNumber(d->extraAreaHighlightCollapseBlockNumber);
-        if (block.isValid()) {
-            QTextCursor cursor(block);
-            if (d->extraAreaHighlightCollapseColumn >= 0)
-                cursor.setPosition(cursor.position() + qMin(d->extraAreaHighlightCollapseColumn,
-                                                            block.length()-1));
-            QTextCursor closeCursor;
-            bool firstRun = true;
-            while (TextBlockUserData::findPreviousBlockOpenParenthesis(&cursor, firstRun)) {
-                firstRun = false;
-                highlightBlocksInfo.open.prepend(cursor.blockNumber());
-                int visualIndent = d->visualIndent(cursor.block());
-                if (closeCursor.isNull())
-                    closeCursor = cursor;
-                if (TextBlockUserData::findNextBlockClosingParenthesis(&closeCursor)) {
-                    highlightBlocksInfo.close.append(closeCursor.blockNumber());
-                    visualIndent = qMin(visualIndent, d->visualIndent(closeCursor.block()));
-                }
-                highlightBlocksInfo.visualIndent.prepend(visualIndent);
+    QTextBlock block;
+    if (d->extraAreaHighlightFoldedBlockNumber >= 0) {
+        block = document()->findBlockByNumber(d->extraAreaHighlightFoldedBlockNumber);
+        if (block.isValid()
+            && block.next().isValid()
+            && BaseTextDocumentLayout::foldingIndent(block.next())
+            > BaseTextDocumentLayout::foldingIndent(block))
+            block = block.next();
+    }
+
+    QTextBlock closeBlock = block;
+    while (block.isValid()) {
+        int foldingIndent = BaseTextDocumentLayout::foldingIndent(block);
+
+        while (block.previous().isValid() && BaseTextDocumentLayout::foldingIndent(block) >= foldingIndent)
+            block = block.previous();
+        int nextIndent = BaseTextDocumentLayout::foldingIndent(block);
+        if (nextIndent == foldingIndent)
+            break;
+        highlightBlocksInfo.open.prepend(block.blockNumber());
+        while (closeBlock.next().isValid()
+            && BaseTextDocumentLayout::foldingIndent(closeBlock.next()) >= foldingIndent )
+            closeBlock = closeBlock.next();
+        highlightBlocksInfo.close.append(closeBlock.blockNumber());
+        int visualIndent = qMin(d->visualIndent(block), d->visualIndent(closeBlock));
+        highlightBlocksInfo.visualIndent.prepend(visualIndent);
+    }
+
+#if 0
+    if (block.isValid()) {
+        QTextCursor cursor(block);
+        if (d->extraAreaHighlightCollapseColumn >= 0)
+            cursor.setPosition(cursor.position() + qMin(d->extraAreaHighlightCollapseColumn,
+                                                        block.length()-1));
+        QTextCursor closeCursor;
+        bool firstRun = true;
+        while (TextBlockUserData::findPreviousBlockOpenParenthesis(&cursor, firstRun)) {
+            firstRun = false;
+            highlightBlocksInfo.open.prepend(cursor.blockNumber());
+            int visualIndent = d->visualIndent(cursor.block());
+            if (closeCursor.isNull())
+                closeCursor = cursor;
+            if (TextBlockUserData::findNextBlockClosingParenthesis(&closeCursor)) {
+                highlightBlocksInfo.close.append(closeCursor.blockNumber());
+                visualIndent = qMin(visualIndent, d->visualIndent(closeCursor.block()));
             }
+            highlightBlocksInfo.visualIndent.prepend(visualIndent);
         }
     }
-
+#endif
     if (d->m_highlightBlocksInfo != highlightBlocksInfo) {
         d->m_highlightBlocksInfo = highlightBlocksInfo;
         viewport()->update();
@@ -4628,8 +4604,10 @@ void BaseTextEditor::setIfdefedOutBlocks(const QList<BaseTextEditor::BlockRange>
                 braceDepthDelta -= delta;
         }
 
-        if (braceDepthDelta)
+        if (braceDepthDelta) {
             BaseTextDocumentLayout::changeBraceDepth(block,braceDepthDelta);
+            BaseTextDocumentLayout::changeFoldingIndent(block, braceDepthDelta); // ### C++ only, refactor!
+        }
 
         block = block.next();
     }
@@ -4880,7 +4858,7 @@ void BaseTextEditor::setDisplaySettings(const DisplaySettings &ds)
 
     d->m_displaySettings = ds;
     if (!ds.m_highlightBlocks) {
-        d->extraAreaHighlightCollapseBlockNumber = d->extraAreaHighlightCollapseColumn = -1;
+        d->extraAreaHighlightFoldedBlockNumber = -1;
         d->m_highlightBlocksInfo = BaseTextEditorPrivateHighlightBlocks();
     }
 
@@ -4905,31 +4883,27 @@ void BaseTextEditor::setCompletionSettings(const TextEditor::CompletionSettings
     setAutoParenthesesEnabled(completionSettings.m_autoInsertBrackets);
 }
 
-void BaseTextEditor::collapse()
+void BaseTextEditor::fold()
 {
     QTextDocument *doc = document();
     BaseTextDocumentLayout *documentLayout = qobject_cast<BaseTextDocumentLayout*>(doc->documentLayout());
     QTC_ASSERT(documentLayout, return);
     QTextBlock block = textCursor().block();
-    QTextBlock curBlock = block;
-    while (block.isValid()) {
-        if (TextBlockUserData::canCollapse(block) && block.next().isVisible()) {
-            if (block == curBlock || block.next() == curBlock)
-                break;
-            if ((block.next().userState()) >> 8 <= (curBlock.previous().userState() >> 8))
-                break;
-        }
-        block = block.previous();
+    if (!(BaseTextDocumentLayout::canFold(block) && block.next().isVisible())) {
+        // find the closest previous block which can fold
+        int indent = BaseTextDocumentLayout::foldingIndent(block);
+        while (block.isValid() && (BaseTextDocumentLayout::foldingIndent(block) >= indent || !block.isVisible()))
+            block = block.previous();
     }
     if (block.isValid()) {
-        TextBlockUserData::doCollapse(block, false);
+        BaseTextDocumentLayout::doFoldOrUnfold(block, false);
         d->moveCursorVisible();
         documentLayout->requestUpdate();
         documentLayout->emitDocumentSizeChanged();
     }
 }
 
-void BaseTextEditor::expand()
+void BaseTextEditor::unfold()
 {
     QTextDocument *doc = document();
     BaseTextDocumentLayout *documentLayout = qobject_cast<BaseTextDocumentLayout*>(doc->documentLayout());
@@ -4937,13 +4911,13 @@ void BaseTextEditor::expand()
     QTextBlock block = textCursor().block();
     while (block.isValid() && !block.isVisible())
         block = block.previous();
-    TextBlockUserData::doCollapse(block, true);
+    BaseTextDocumentLayout::doFoldOrUnfold(block, true);
     d->moveCursorVisible();
     documentLayout->requestUpdate();
     documentLayout->emitDocumentSizeChanged();
 }
 
-void BaseTextEditor::unCollapseAll()
+void BaseTextEditor::unfoldAll()
 {
     QTextDocument *doc = document();
     BaseTextDocumentLayout *documentLayout = qobject_cast<BaseTextDocumentLayout*>(doc->documentLayout());
@@ -4952,7 +4926,7 @@ void BaseTextEditor::unCollapseAll()
     QTextBlock block = doc->firstBlock();
     bool makeVisible = true;
     while (block.isValid()) {
-        if (block.isVisible() && TextBlockUserData::canCollapse(block) && block.next().isVisible()) {
+        if (block.isVisible() && BaseTextDocumentLayout::canFold(block) && block.next().isVisible()) {
             makeVisible = false;
             break;
         }
@@ -4962,8 +4936,8 @@ void BaseTextEditor::unCollapseAll()
     block = doc->firstBlock();
 
     while (block.isValid()) {
-        if (TextBlockUserData::canCollapse(block))
-            TextBlockUserData::doCollapse(block, makeVisible);
+        if (BaseTextDocumentLayout::canFold(block))
+            BaseTextDocumentLayout::doFoldOrUnfold(block, makeVisible);
         block = block.next();
     }
 
index ddca759..d13a7ae 100644 (file)
@@ -224,9 +224,9 @@ public slots:
 
     void cutLine();
     void deleteLine();
-    void unCollapseAll();
-    void collapse();
-    void expand();
+    void unfoldAll();
+    void fold();
+    void unfold();
     void selectEncoding();
 
     void gotoBlockStart();
@@ -262,6 +262,9 @@ public slots:
 
     void joinLines();
 
+    void insertLineAbove();
+    void insertLineBelow();
+
     void cleanWhitespace();
 
 signals:
@@ -488,9 +491,9 @@ private:
                            bool hovered) const;
 
     void toggleBlockVisible(const QTextBlock &block);
-    QRect collapseBox();
+    QRect foldBox();
 
-    QTextBlock collapsedBlockAt(const QPoint &pos, QRect *box = 0) const;
+    QTextBlock foldedBlockAt(const QPoint &pos, QRect *box = 0) const;
 
     void updateLink(QMouseEvent *e);
     void showLink(const Link &);
index 784d95f..9cb7788 100644 (file)
@@ -189,8 +189,7 @@ public:
 
     int extraAreaSelectionAnchorBlockNumber;
     int extraAreaToggleMarkBlockNumber;
-    int extraAreaHighlightCollapseBlockNumber;
-    int extraAreaHighlightCollapseColumn;
+    int extraAreaHighlightFoldedBlockNumber;
 
     TextEditorOverlay *m_overlay;
     TextEditorOverlay *m_snippetOverlay;
@@ -200,12 +199,12 @@ public:
     QTextCharFormat m_occurrencesFormat;
     QTextCharFormat m_occurrenceRenameFormat;
 
-    QBasicTimer collapsedBlockTimer;
-    int visibleCollapsedBlockNumber;
-    int suggestedVisibleCollapsedBlockNumber;
-    void clearVisibleCollapsedBlock();
-    bool m_mouseOnCollapsedMarker;
-    void collapseLicenseHeader();
+    QBasicTimer foldedBlockTimer;
+    int visibleFoldedBlockNumber;
+    int suggestedVisibleFoldedBlockNumber;
+    void clearVisibleFoldedBlock();
+    bool m_mouseOnFoldedMarker;
+    void foldLicenseHeader();
 
     QBasicTimer autoScrollTimer;
     void updateMarksLineNumber();
index e30c00f..6d84bdb 100644 (file)
@@ -277,8 +277,8 @@ QColor FormatDescription::background() const
         qreal smallRatio;
         qreal largeRatio;
         if (m_id == QLatin1String(Constants::C_CURRENT_LINE)) {
-            smallRatio = .15;
-            largeRatio = .3;
+            smallRatio = .3;
+            largeRatio = .6;
         } else {
             smallRatio = .05;
             largeRatio = .4;
diff --git a/src/plugins/texteditor/generichighlighter/context.cpp b/src/plugins/texteditor/generichighlighter/context.cpp
new file mode 100644 (file)
index 0000000..d9fea72
--- /dev/null
@@ -0,0 +1,156 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "context.h"
+#include "rule.h"
+#include "reuse.h"
+#include "dynamicrule.h"
+#include "highlightdefinition.h"
+
+using namespace TextEditor;
+using namespace Internal;
+
+Context::Context() : m_fallthrough(false), m_dynamic(false)
+{}
+
+Context::Context(const Context &context) :
+    m_id(context.m_id), m_name(context.m_name), m_lineBeginContext(context.m_lineBeginContext),
+    m_lineEndContext(context.m_lineEndContext), m_fallthroughContext(context.m_fallthroughContext),
+    m_itemData(context.m_itemData), m_fallthrough(context.m_fallthrough),
+    m_dynamic(context.m_dynamic), m_instructions(context.m_instructions),
+    m_definition(context.m_definition)
+{
+    // Rules need to be deeply copied because of dynamic contexts.
+    foreach (const QSharedPointer<Rule> &rule, context.m_rules)
+        m_rules.append(QSharedPointer<Rule>(rule->clone()));
+}
+
+const Context &Context::operator=(Context copy)
+{
+    swap(copy);
+    return *this;
+}
+
+Context::~Context()
+{}
+
+void Context::swap(Context &context)
+{
+    qSwap(m_id, context.m_id);
+    qSwap(m_name, context.m_name);
+    qSwap(m_lineBeginContext, context.m_lineBeginContext);
+    qSwap(m_lineEndContext, context.m_lineEndContext);
+    qSwap(m_fallthroughContext, context.m_fallthroughContext);
+    qSwap(m_itemData, context.m_itemData);
+    qSwap(m_fallthrough, context.m_fallthrough);
+    qSwap(m_dynamic, context.m_dynamic);
+    qSwap(m_rules, context.m_rules);
+    qSwap(m_instructions, context.m_instructions);
+    qSwap(m_definition, context.m_definition);
+}
+
+void Context::configureId(const int unique)
+{ m_id.append(QString::number(unique)); }
+
+const QString &Context::id() const
+{ return m_id; }
+
+void Context::setName(const QString &name)
+{
+    m_name = name;
+    m_id = name;
+}
+
+const QString &Context::name() const
+{ return m_name; }
+
+void Context::setLineBeginContext(const QString &context)
+{ m_lineBeginContext = context; }
+
+const QString &Context::lineBeginContext() const
+{ return m_lineBeginContext; }
+
+void Context::setLineEndContext(const QString &context)
+{ m_lineEndContext = context; }
+
+const QString &Context::lineEndContext() const
+{ return m_lineEndContext; }
+
+void Context::setFallthroughContext(const QString &context)
+{ m_fallthroughContext = context; }
+
+const QString &Context::fallthroughContext() const
+{ return m_fallthroughContext; }
+
+void Context::setItemData(const QString &itemData)
+{ m_itemData = itemData; }
+
+const QString &Context::itemData() const
+{ return m_itemData; }
+
+void Context::setFallthrough(const QString &fallthrough)
+{ m_fallthrough = toBool(fallthrough); }
+
+bool Context::isFallthrough() const
+{ return m_fallthrough; }
+
+void Context::setDynamic(const QString &dynamic)
+{ m_dynamic = toBool(dynamic); }
+
+bool Context::isDynamic() const
+{ return m_dynamic; }
+
+void Context::updateDynamicRules(const QStringList &captures) const
+{
+    TextEditor::Internal::updateDynamicRules(m_rules, captures);
+}
+
+void Context::addRule(const QSharedPointer<Rule> &rule)
+{ m_rules.append(rule); }
+
+void Context::addRule(const QSharedPointer<Rule> &rule, int index)
+{ m_rules.insert(index, rule); }
+
+const QList<QSharedPointer<Rule> > & Context::rules() const
+{ return m_rules; }
+
+void Context::addIncludeRulesInstruction(const IncludeRulesInstruction &instruction)
+{ m_instructions.append(instruction); }
+
+const QList<IncludeRulesInstruction> &Context::includeRulesInstructions() const
+{ return m_instructions; }
+
+void Context::clearIncludeRulesInstructions()
+{ m_instructions.clear(); }
+
+void Context::setDefinition(const QSharedPointer<HighlightDefinition> &definition)
+{ m_definition = definition; }
+
+const QSharedPointer<HighlightDefinition> &Context::definition() const
+{ return m_definition; }
diff --git a/src/plugins/texteditor/generichighlighter/context.h b/src/plugins/texteditor/generichighlighter/context.h
new file mode 100644 (file)
index 0000000..1d800ca
--- /dev/null
@@ -0,0 +1,110 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef CONTEXT_H
+#define CONTEXT_H
+
+#include "includerulesinstruction.h"
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QSharedPointer>
+
+namespace TextEditor {
+namespace Internal {
+
+class Rule;
+class HighlightDefinition;
+
+class Context
+{
+public:
+    Context();
+    Context(const Context &context);
+    const Context &operator=(Context copy);
+    ~Context();
+
+    void configureId(const int unique);
+    const QString &id() const;
+
+    void setName(const QString &name);
+    const QString &name() const;
+
+    void setLineBeginContext(const QString &context);
+    const QString &lineBeginContext() const;
+
+    void setLineEndContext(const QString &context);
+    const QString &lineEndContext() const;
+
+    void setFallthroughContext(const QString &context);
+    const QString &fallthroughContext() const;
+
+    void setItemData(const QString &itemData);
+    const QString &itemData() const;
+
+    void setFallthrough(const QString &fallthrough);
+    bool isFallthrough() const;
+
+    void setDynamic(const QString &dynamic);
+    bool isDynamic() const;
+    void updateDynamicRules(const QStringList &captures) const;
+
+    void addRule(const QSharedPointer<Rule> &rule);
+    void addRule(const QSharedPointer<Rule> &rule, int index);
+    const QList<QSharedPointer<Rule> > &rules() const;
+
+    void addIncludeRulesInstruction(const IncludeRulesInstruction &instruction);
+    const QList<IncludeRulesInstruction> &includeRulesInstructions() const;
+    void clearIncludeRulesInstructions();
+
+    void setDefinition(const QSharedPointer<HighlightDefinition> &definition);
+    const QSharedPointer<HighlightDefinition> &definition() const;
+
+    void swap(Context &context);
+
+private:
+    QString m_id;
+    QString m_name;
+    QString m_lineBeginContext;
+    QString m_lineEndContext;
+    QString m_fallthroughContext;
+    QString m_itemData;
+    bool m_fallthrough;
+    bool m_dynamic;
+
+    QList<QSharedPointer<Rule> > m_rules;
+    QList<IncludeRulesInstruction> m_instructions;
+
+    QSharedPointer<HighlightDefinition> m_definition;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // CONTEXT_H
diff --git a/src/plugins/texteditor/generichighlighter/dynamicrule.cpp b/src/plugins/texteditor/generichighlighter/dynamicrule.cpp
new file mode 100644 (file)
index 0000000..24d7414
--- /dev/null
@@ -0,0 +1,67 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "dynamicrule.h"
+#include "reuse.h"
+
+using namespace TextEditor;
+using namespace Internal;
+
+DynamicRule::DynamicRule() : m_active(false)
+{}
+
+DynamicRule::~DynamicRule()
+{}
+
+void DynamicRule::setActive(const QString &active)
+{ m_active = toBool(active); }
+
+bool DynamicRule::isActive() const
+{ return m_active; }
+
+void DynamicRule::replaceExpressions(const QStringList &captures)
+{
+    doReplaceExpressions(captures);
+    updateDynamicRules(childs(), captures);
+}
+
+namespace TextEditor {
+namespace Internal {
+
+void updateDynamicRules(const QList<QSharedPointer<Rule> > &rules, const QStringList &captures)
+{
+    foreach (QSharedPointer<Rule> rule, rules) {
+        DynamicRule *dynamicRule = dynamic_cast<DynamicRule *>(rule.data());
+        if (dynamicRule && dynamicRule->isActive())
+            dynamicRule->replaceExpressions(captures);
+    }
+}
+
+} // namespace Internal
+} // namespace TextEditor
diff --git a/src/plugins/texteditor/generichighlighter/dynamicrule.h b/src/plugins/texteditor/generichighlighter/dynamicrule.h
new file mode 100644 (file)
index 0000000..1e116d3
--- /dev/null
@@ -0,0 +1,64 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DYNAMICRULE_H
+#define DYNAMICRULE_H
+
+#include "rule.h"
+
+QT_BEGIN_NAMESPACE
+class QStringList;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+namespace Internal {
+
+class DynamicRule : public Rule
+{
+public:
+    DynamicRule();
+    virtual ~DynamicRule();
+
+    void setActive(const QString &active);
+    bool isActive() const;
+
+    virtual void replaceExpressions(const QStringList &captures);
+
+private:
+    virtual void doReplaceExpressions(const QStringList &captures) = 0;
+
+    bool m_active;    
+};
+
+void updateDynamicRules(const QList<QSharedPointer<Rule> > &rules, const QStringList &captures);
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // DYNAMICRULE_H
diff --git a/src/plugins/texteditor/generichighlighter/highlightdefinition.cpp b/src/plugins/texteditor/generichighlighter/highlightdefinition.cpp
new file mode 100644 (file)
index 0000000..7c72322
--- /dev/null
@@ -0,0 +1,167 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "highlightdefinition.h"
+#include "highlighterexception.h"
+#include "context.h"
+#include "keywordlist.h"
+#include "itemdata.h"
+#include "reuse.h"
+
+#include <QLatin1String>
+
+using namespace TextEditor;
+using namespace Internal;
+
+HighlightDefinition::HighlightDefinition() :
+    m_delimiters(QLatin1String(".():!+,-<=>%&/;?[]^{|}~\\*, \t")),
+    m_singleLineCommentAfterWhiteSpaces(false),
+    m_keywordCaseSensitivity(Qt::CaseSensitive)
+{}
+
+HighlightDefinition::~HighlightDefinition()
+{}
+
+template <class Element, class Container>
+const QSharedPointer<Element> &HighlightDefinition::
+GenericHelper::create(const QString &name, Container &container)
+{
+    if (name.isEmpty())
+        throw HighlighterException();
+
+    if (container.contains(name))
+        throw HighlighterException();
+
+    container.insert(name, QSharedPointer<Element>(new Element));
+    return *container.constFind(name);
+}
+
+template <class Element, class Container>
+const QSharedPointer<Element> &HighlightDefinition::
+GenericHelper::find(const QString &name, const Container &container) const
+{
+    typename Container::const_iterator it = container.find(name);
+    if (it == container.end())
+        throw HighlighterException();
+
+    return it.value();
+}
+
+const QSharedPointer<KeywordList> &HighlightDefinition::createKeywordList(const QString &list)
+{ return m_helper.create<KeywordList>(list, m_lists); }
+
+const QSharedPointer<KeywordList> &HighlightDefinition::keywordList(const QString &list)
+{ return m_helper.find<KeywordList>(list, m_lists); }
+
+const QSharedPointer<Context> &HighlightDefinition::createContext(const QString &context,
+                                                                  bool initial)
+{
+    if (initial)
+        m_initialContext = context;
+
+    return m_helper.create<Context>(context, m_contexts);
+}
+
+const QSharedPointer<Context> &HighlightDefinition::initialContext() const
+{ return m_helper.find<Context>(m_initialContext, m_contexts); }
+
+const QSharedPointer<Context> &HighlightDefinition::context(const QString &context) const
+{ return m_helper.find<Context>(context, m_contexts); }
+
+const QHash<QString, QSharedPointer<Context> > &HighlightDefinition::contexts() const
+{ return m_contexts; }
+
+const QSharedPointer<ItemData> &HighlightDefinition::createItemData(const QString &itemData)
+{ return m_helper.create<ItemData>(itemData, m_itemsData); }
+
+const QSharedPointer<ItemData> &HighlightDefinition::itemData(const QString &itemData) const
+{ return m_helper.find<ItemData>(itemData, m_itemsData); }
+
+void HighlightDefinition::setSingleLineComment(const QString &start)
+{ m_singleLineComment = start; }
+
+const QString &HighlightDefinition::singleLineComment() const
+{ return m_singleLineComment; }
+
+void HighlightDefinition::setCommentAfterWhitespaces(const QString &after)
+{
+    if (after == QLatin1String("afterwhitespace"))
+        m_singleLineCommentAfterWhiteSpaces = true;
+}
+
+bool HighlightDefinition::isCommentAfterWhiteSpaces() const
+{ return m_singleLineCommentAfterWhiteSpaces; }
+
+void HighlightDefinition::setMultiLineCommentStart(const QString &start)
+{ m_multiLineCommentStart = start; }
+
+const QString &HighlightDefinition::multiLineCommentStart() const
+{ return m_multiLineCommentStart; }
+
+void HighlightDefinition::setMultiLineCommentEnd(const QString &end)
+{ m_multiLineCommentEnd = end; }
+
+const QString &HighlightDefinition::multiLineCommentEnd() const
+{ return m_multiLineCommentEnd; }
+
+void HighlightDefinition::setMultiLineCommentRegion(const QString &region)
+{ m_multiLineCommentRegion = region; }
+
+const QString &HighlightDefinition::multiLineCommentRegion() const
+{ return m_multiLineCommentRegion; }
+
+void HighlightDefinition::removeDelimiters(const QString &characters)
+{
+    for (int i = 0; i < characters.length(); ++i)
+        m_delimiters.remove(characters.at(i));
+}
+
+void HighlightDefinition::addDelimiters(const QString &characters)
+{
+    for (int i = 0; i < characters.length(); ++i) {
+        if (!m_delimiters.contains(characters.at(i)))
+            m_delimiters.append(characters.at(i));
+    }
+}
+
+bool HighlightDefinition::isDelimiter(const QChar &character) const
+{
+    if (m_delimiters.contains(character))
+        return true;
+    return false;
+}
+
+void HighlightDefinition::setKeywordsSensitive(const QString &sensitivity)
+{
+    if (!sensitivity.isEmpty())
+        m_keywordCaseSensitivity = toCaseSensitivity(toBool(sensitivity));
+}
+
+Qt::CaseSensitivity HighlightDefinition::keywordsSensitive() const
+{ return m_keywordCaseSensitivity; }
diff --git a/src/plugins/texteditor/generichighlighter/highlightdefinition.h b/src/plugins/texteditor/generichighlighter/highlightdefinition.h
new file mode 100644 (file)
index 0000000..2f48bc2
--- /dev/null
@@ -0,0 +1,117 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef HIGHLIGHTDEFINITION_H
+#define HIGHLIGHTDEFINITION_H
+
+#include <QtCore/QString>
+#include <QtCore/QHash>
+#include <QtCore/QSharedPointer>
+
+namespace TextEditor {
+namespace Internal {
+
+class KeywordList;
+class Context;
+class ItemData;
+
+class HighlightDefinition
+{
+public:
+    HighlightDefinition();
+    ~HighlightDefinition();
+
+    const QSharedPointer<KeywordList> &createKeywordList(const QString &list);
+    const QSharedPointer<KeywordList> &keywordList(const QString &list);
+
+    const QSharedPointer<Context> &createContext(const QString &context, bool initial);
+    const QSharedPointer<Context> &initialContext() const;
+    const QSharedPointer<Context> &context(const QString &context) const;
+    const QHash<QString, QSharedPointer<Context> > &contexts() const;
+
+    const QSharedPointer<ItemData> &createItemData(const QString &itemData);
+    const QSharedPointer<ItemData> &itemData(const QString &itemData) const;
+
+    void setKeywordsSensitive(const QString &sensitivity);
+    Qt::CaseSensitivity keywordsSensitive() const;
+
+    void addDelimiters(const QString &characters);
+    void removeDelimiters(const QString &characters);
+    bool isDelimiter(const QChar &character) const;
+
+    void setSingleLineComment(const QString &start);
+    const QString &singleLineComment() const;
+
+    void setCommentAfterWhitespaces(const QString &after);
+    bool isCommentAfterWhiteSpaces() const;
+
+    void setMultiLineCommentStart(const QString &start);
+    const QString &multiLineCommentStart() const;
+
+    void setMultiLineCommentEnd(const QString &end);
+    const QString &multiLineCommentEnd() const;
+
+    void setMultiLineCommentRegion(const QString &region);
+    const QString &multiLineCommentRegion() const;
+
+private:
+    Q_DISABLE_COPY(HighlightDefinition)
+
+    struct GenericHelper
+    {
+        template <class Element, class Container>
+        const QSharedPointer<Element> &create(const QString &name, Container &container);
+
+        template <class Element, class Container>
+        const QSharedPointer<Element> &find(const QString &name, const Container &container) const;
+    };
+    GenericHelper m_helper;
+
+    QHash<QString, QSharedPointer<KeywordList> > m_lists;
+    QHash<QString, QSharedPointer<Context> > m_contexts;
+    QHash<QString, QSharedPointer<ItemData> > m_itemsData;
+
+    QString m_initialContext;
+
+    QString m_delimiters;
+
+    QString m_singleLineComment;
+    bool m_singleLineCommentAfterWhiteSpaces;
+
+    QString m_multiLineCommentStart;
+    QString m_multiLineCommentEnd;
+    QString m_multiLineCommentRegion;
+
+    Qt::CaseSensitivity m_keywordCaseSensitivity;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // HIGHLIGHTDEFINITION_H
diff --git a/src/plugins/texteditor/generichighlighter/highlightdefinitionhandler.cpp b/src/plugins/texteditor/generichighlighter/highlightdefinitionhandler.cpp
new file mode 100644 (file)
index 0000000..f18d3de
--- /dev/null
@@ -0,0 +1,461 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "highlightdefinitionhandler.h"
+#include "highlightdefinition.h"
+#include "specificrules.h"
+#include "itemdata.h"
+#include "keywordlist.h"
+#include "context.h"
+#include "reuse.h"
+#include "manager.h"
+#include "highlighterexception.h"
+
+#include <QLatin1String>
+
+using namespace TextEditor;
+using namespace Internal;
+
+namespace {
+    static const QLatin1String kName("name");
+    static const QLatin1String kList("list");
+    static const QLatin1String kItem("item");
+    static const QLatin1String kContext("context");
+    static const QLatin1String kAttribute("attribute");
+    static const QLatin1String kDynamic("dynamic");
+    static const QLatin1String kFallthrough("fallthrough");
+    static const QLatin1String kLineEndContext("lineEndContext");
+    static const QLatin1String kLineBeginContext("lineBeginContext");
+    static const QLatin1String kFallthroughContext("fallthroughContext");
+    static const QLatin1String kBeginRegion("beginRegion");
+    static const QLatin1String kEndRegion("endRegion");
+    static const QLatin1String kLookAhead("lookAhead");
+    static const QLatin1String kFirstNonSpace("firstNonSpace");
+    static const QLatin1String kColumn("column");
+    static const QLatin1String kItemData("itemData");
+    static const QLatin1String kDefStyleNum("defStyleNum");
+    static const QLatin1String kColor("color");
+    static const QLatin1String kSelColor("selColor");
+    static const QLatin1String kItalic("italic");
+    static const QLatin1String kBold("bold");
+    static const QLatin1String kUnderline("underline");
+    static const QLatin1String kStrikeout("strikeout");
+    static const QLatin1String kChar("char");
+    static const QLatin1String kChar1("char1");
+    static const QLatin1String kString("String");
+    static const QLatin1String kInsensitive("insensitive");
+    static const QLatin1String kMinimal("minimal");
+    static const QLatin1String kKeywords("keywords");
+    static const QLatin1String kCaseSensitive("casesensitive");
+    static const QLatin1String kWeakDeliminator("weakDeliminator");
+    static const QLatin1String kAdditionalDeliminator("additionalDeliminator");
+    static const QLatin1String kWordWrapDeliminator("wordWrapDeliminator");
+    static const QLatin1String kComment("comment");
+    static const QLatin1String kPosition("position");
+    static const QLatin1String kSingleLine("singleline");
+    static const QLatin1String kMultiLine("multiline");
+    static const QLatin1String kStart("start");
+    static const QLatin1String kEnd("end");
+    static const QLatin1String kRegion("region");
+    static const QLatin1String kDetectChar("DetectChar");
+    static const QLatin1String kDetect2Chars("Detect2Chars");
+    static const QLatin1String kAnyChar("AnyChar");
+    static const QLatin1String kStringDetect("StringDetect");
+    static const QLatin1String kRegExpr("RegExpr");
+    static const QLatin1String kKeyword("keyword");
+    static const QLatin1String kInt("Int");
+    static const QLatin1String kFloat("Float");
+    static const QLatin1String kHlCOct("HlCOct");
+    static const QLatin1String kHlCHex("HlCHex");
+    static const QLatin1String kHlCStringChar("HlCStringChar");
+    static const QLatin1String kHlCChar("HlCChar");
+    static const QLatin1String kRangeDetect("RangeDetect");
+    static const QLatin1String kLineContinue("LineContinue");
+    static const QLatin1String kIncludeRules("IncludeRules");
+    static const QLatin1String kDetectSpaces("DetectSpaces");
+    static const QLatin1String kDetectIdentifier("DetectIdentifier");
+    static const QLatin1String kLanguage("language");
+    static const QLatin1String kExtensions("extensions");
+    static const QLatin1String kIncludeAttrib("includeAttrib");
+    static const QLatin1String kHash("#");
+    static const QLatin1String kDoubleHash("##");
+}
+
+HighlightDefinitionHandler::
+HighlightDefinitionHandler(const QSharedPointer<HighlightDefinition> &definition) :
+    m_definition(definition),
+    m_processingKeyword(false),
+    m_initialContext(true)
+{}
+
+HighlightDefinitionHandler::~HighlightDefinitionHandler()
+{}
+
+bool HighlightDefinitionHandler::startDocument()
+{
+    return true;
+}
+
+bool HighlightDefinitionHandler::endDocument()
+{
+    processIncludeRules();
+    return true;
+}
+
+bool HighlightDefinitionHandler::startElement(const QString &,
+                                              const QString &,
+                                              const QString &qName,
+                                              const QXmlAttributes &atts)
+{
+    if (qName == kList) {
+        listElementStarted(atts);
+    } else if (qName == kItem) {
+        itemElementStarted();
+    } else if (qName == kContext) {
+        contextElementStarted(atts);
+    } else if (qName == kItemData) {
+        itemDataElementStarted(atts);
+    } else if (qName == kComment) {
+        commentElementStarted(atts);
+    } else if (qName == kKeywords) {
+        keywordsElementStarted(atts);
+    } else if (qName == kDetectChar) {
+        detectCharStarted(atts);
+    } else if (qName == kDetect2Chars) {
+        detect2CharsStarted(atts);
+    } else if (qName == kAnyChar) {
+        anyCharStarted(atts);
+    } else if (qName == kStringDetect) {
+        stringDetectedStarted(atts);
+    } else if (qName == kRegExpr) {
+        regExprStarted(atts);
+    } else if (qName == kKeyword) {
+        keywordStarted(atts);
+    } else if (qName == kInt) {
+        intStarted(atts);
+    } else if (qName == kFloat) {
+        floatStarted(atts);
+    } else if (qName == kHlCOct) {
+        hlCOctStarted(atts);
+    } else if (qName == kHlCHex) {
+        hlCHexStarted(atts);
+    } else if (qName == kHlCStringChar) {
+        hlCStringCharStarted(atts);
+    } else if (qName == kHlCChar) {
+        hlCCharStarted(atts);
+    } else if (qName == kRangeDetect) {
+        rangeDetectStarted(atts);
+    } else if (qName == kLineContinue) {
+        lineContinue(atts);
+    } else if (qName == kIncludeRules) {
+        includeRulesStarted(atts);
+    } else if (qName == kDetectSpaces) {
+        detectSpacesStarted(atts);
+    } else if (qName == kDetectIdentifier) {
+        detectIdentifier(atts);
+    }
+
+    return true;
+}
+
+bool HighlightDefinitionHandler::endElement(const QString &, const QString &, const QString &qName)
+{
+    if (qName == kItem) {
+        m_currentList->addKeyword(m_currentKeyword.trimmed());
+        m_processingKeyword = false;
+    } else if (qName == kDetectChar || qName == kDetect2Chars || qName == kAnyChar ||
+               qName == kStringDetect || qName == kRegExpr || qName == kKeyword || qName == kInt ||
+               qName == kFloat || qName == kHlCOct || qName == kHlCHex || qName == kHlCStringChar ||
+               qName == kHlCChar || qName == kRangeDetect || qName == kLineContinue ||
+               qName == kDetectSpaces || qName == kDetectIdentifier) {
+        m_currentRule.pop();
+    }
+
+    return true;
+}
+
+bool HighlightDefinitionHandler::characters(const QString& ch)
+{
+    // Character data of an element may be reported in more than one chunk.
+    if (m_processingKeyword)
+        m_currentKeyword.append(ch);
+
+    return true;
+}
+
+void HighlightDefinitionHandler::listElementStarted(const QXmlAttributes &atts)
+{
+    m_currentList = m_definition->createKeywordList(atts.value(kName));
+}
+
+void HighlightDefinitionHandler::itemElementStarted()
+{
+    m_currentKeyword.clear();
+    m_processingKeyword = true;
+}
+
+void HighlightDefinitionHandler::contextElementStarted(const QXmlAttributes &atts)
+{
+    m_currentContext = m_definition->createContext(atts.value(kName), m_initialContext);
+    m_currentContext->setDefinition(m_definition);
+    m_currentContext->setName(atts.value(kName));
+    m_currentContext->setItemData(atts.value(kAttribute));
+    m_currentContext->setDynamic(atts.value(kDynamic));
+    m_currentContext->setFallthrough(atts.value(kFallthrough));
+    m_currentContext->setFallthroughContext(atts.value(kFallthroughContext));
+    m_currentContext->setLineBeginContext(atts.value(kLineBeginContext));
+    m_currentContext->setLineEndContext(atts.value(kLineEndContext));
+
+    m_initialContext = false;
+}
+
+void HighlightDefinitionHandler::ruleElementStarted(const QXmlAttributes &atts,
+                                                    const QSharedPointer<Rule> &rule)
+{
+    // The definition of a rule is not necessarily the same of its enclosing context because of
+    // externally included rules.
+    rule->setDefinition(m_definition);
+    rule->setItemData(atts.value(kAttribute));
+    rule->setContext(atts.value(kContext));
+    rule->setBeginRegion(atts.value(kBeginRegion));
+    rule->setEndRegion(atts.value(kEndRegion));
+    rule->setLookAhead(atts.value(kLookAhead));
+    rule->setFirstNonSpace(atts.value(kFirstNonSpace));
+    rule->setColumn(atts.value(kColumn));
+
+    if (m_currentRule.isEmpty())
+        m_currentContext->addRule(rule);
+    else
+        m_currentRule.top()->addChild(rule);
+
+    m_currentRule.push(rule);
+}
+
+void HighlightDefinitionHandler::itemDataElementStarted(const QXmlAttributes &atts) const
+{
+    QSharedPointer<ItemData> itemData = m_definition->createItemData(atts.value(kName));
+    itemData->setStyle(atts.value(kDefStyleNum));
+    itemData->setColor(atts.value(kColor));
+    itemData->setSelectionColor(atts.value(kSelColor));
+    itemData->setItalic(atts.value(kItalic));
+    itemData->setBold(atts.value(kBold));
+    itemData->setUnderlined(atts.value(kUnderline));
+    itemData->setStrikedOut(atts.value(kStrikeout));
+}
+
+void HighlightDefinitionHandler::commentElementStarted(const QXmlAttributes &atts) const
+{
+    const QString &commentType = atts.value(kName);
+    if (commentType.compare(kSingleLine, Qt::CaseInsensitive) == 0) {
+        m_definition->setSingleLineComment(atts.value(kStart));
+        m_definition->setCommentAfterWhitespaces(atts.value(kPosition));
+    } else if (commentType.compare(kMultiLine, Qt::CaseInsensitive) == 0) {
+        m_definition->setMultiLineCommentStart(atts.value(kStart));
+        m_definition->setMultiLineCommentEnd(atts.value(kEnd));
+        m_definition->setMultiLineCommentRegion(atts.value(kRegion));
+    }
+}
+
+void HighlightDefinitionHandler::keywordsElementStarted(const QXmlAttributes &atts) const
+{
+    // Global case sensitivity appears last in the document (required by dtd) and is set here.
+    m_definition->setKeywordsSensitive(atts.value(kCaseSensitive));
+    m_definition->removeDelimiters(atts.value(kWeakDeliminator));
+    m_definition->addDelimiters(atts.value(kAdditionalDeliminator));
+    //@todo: wordWrapDelimiters?
+}
+
+void HighlightDefinitionHandler::detectCharStarted(const QXmlAttributes &atts)
+{
+    DetectCharRule *rule = new DetectCharRule;
+    rule->setChar(atts.value(kChar));
+    rule->setActive(atts.value(kDynamic));
+    ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::detect2CharsStarted(const QXmlAttributes &atts)
+{
+    Detect2CharsRule *rule = new Detect2CharsRule;
+    rule->setChar(atts.value(kChar));
+    rule->setChar1(atts.value(kChar1));
+    rule->setActive(atts.value(kDynamic));
+    ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::anyCharStarted(const QXmlAttributes &atts)
+{
+    AnyCharRule *rule = new AnyCharRule;
+    rule->setCharacterSet(atts.value(kString));
+    ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::stringDetectedStarted(const QXmlAttributes &atts)
+{
+    StringDetectRule *rule = new StringDetectRule;
+    rule->setString(atts.value(kString));
+    rule->setInsensitive(atts.value(kInsensitive));
+    rule->setActive(atts.value(kDynamic));
+    ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::regExprStarted(const QXmlAttributes &atts)
+{
+    RegExprRule *rule = new RegExprRule;
+    rule->setPattern(atts.value(kString));
+    rule->setMinimal(atts.value(kMinimal));
+    rule->setInsensitive(atts.value(kInsensitive));
+    rule->setActive(atts.value(kDynamic));
+    ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::keywordStarted(const QXmlAttributes &atts)
+{
+    KeywordRule *rule = new KeywordRule(m_definition);
+    rule->setList(atts.value(kString));
+    rule->setInsensitive(atts.value(kInsensitive));
+    ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::intStarted(const QXmlAttributes &atts)
+{    
+    ruleElementStarted(atts, QSharedPointer<Rule>(new IntRule));
+}
+
+void HighlightDefinitionHandler::floatStarted(const QXmlAttributes &atts)
+{
+    ruleElementStarted(atts, QSharedPointer<Rule>(new FloatRule));
+}
+
+void HighlightDefinitionHandler::hlCOctStarted(const QXmlAttributes &atts)
+{    
+    ruleElementStarted(atts, QSharedPointer<Rule>(new HlCOctRule));
+}
+
+void HighlightDefinitionHandler::hlCHexStarted(const QXmlAttributes &atts)
+{    
+    ruleElementStarted(atts, QSharedPointer<Rule>(new HlCHexRule));
+}
+
+void HighlightDefinitionHandler::hlCStringCharStarted(const QXmlAttributes &atts)
+{    
+    ruleElementStarted(atts, QSharedPointer<Rule>(new HlCStringCharRule));
+}
+
+void HighlightDefinitionHandler::hlCCharStarted(const QXmlAttributes &atts)
+{
+    ruleElementStarted(atts, QSharedPointer<Rule>(new HlCCharRule));
+}
+
+void HighlightDefinitionHandler::rangeDetectStarted(const QXmlAttributes &atts)
+{
+    RangeDetectRule *rule = new RangeDetectRule;
+    rule->setChar(atts.value(kChar));
+    rule->setChar1(atts.value(kChar1));
+    ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::lineContinue(const QXmlAttributes &atts)
+{    
+    ruleElementStarted(atts, QSharedPointer<Rule>(new LineContinueRule));
+}
+
+void HighlightDefinitionHandler::includeRulesStarted(const QXmlAttributes &atts)
+{
+    // Include rules are treated as instructions for latter processing.
+    IncludeRulesInstruction instruction(atts.value(kContext), m_currentContext->rules().size(),
+                                        atts.value(kIncludeAttrib));
+
+    // Include rules (as many others) are not allowed as a child.
+    m_currentContext->addIncludeRulesInstruction(instruction);
+}
+
+void HighlightDefinitionHandler::detectSpacesStarted(const QXmlAttributes &atts)
+{
+    ruleElementStarted(atts, QSharedPointer<Rule>(new DetectSpacesRule));
+}
+
+void HighlightDefinitionHandler::detectIdentifier(const QXmlAttributes &atts)
+{
+    ruleElementStarted(atts, QSharedPointer<Rule>(new DetectIdentifierRule));
+}
+
+void HighlightDefinitionHandler::processIncludeRules() const
+{
+    const QHash<QString, QSharedPointer<Context> > &allContexts = m_definition->contexts();
+    foreach (const QSharedPointer<Context> &context, allContexts)
+        processIncludeRules(context);
+}
+
+void HighlightDefinitionHandler::processIncludeRules(const QSharedPointer<Context> &context) const
+{
+    if (context->includeRulesInstructions().isEmpty())
+        return;
+
+    int rulesIncluded = 0;
+    const QList<IncludeRulesInstruction> &instructions = context->includeRulesInstructions();
+    foreach (const IncludeRulesInstruction &instruction, instructions) {
+
+        QSharedPointer<Context> sourceContext;
+        const QString &sourceName = instruction.sourceContext();
+        if (sourceName.startsWith(kDoubleHash)) {
+            // This refers to an external definition. The rules included are the ones from its
+            // initial context. Others contexts and rules from the external definition will work
+            // transparently to the highlighter. This is because contexts and rules know the
+            // definition they are from.
+            QString externalName = QString::fromRawData(sourceName.unicode() + 2,
+                                                        sourceName.length() - 2);
+            const QString &id = Manager::instance()->definitionIdByName(externalName);
+
+            // If there is an incorrect circular dependency among definitions this is skipped.
+            if (Manager::instance()->isBuildingDefinition(id))
+                continue;
+
+            const QSharedPointer<HighlightDefinition> &externalDefinition =
+                Manager::instance()->definition(id);
+            sourceContext = externalDefinition->initialContext();
+        } else if (!sourceName.startsWith(kHash)) {
+            sourceContext = m_definition->context(sourceName);
+
+            // Recursion is done only for context direct rules. Child rules are not processed
+            // because they cannot be include rules.
+            processIncludeRules(sourceContext);
+        }
+
+        if (instruction.replaceItemData()) {
+            context->setItemData(sourceContext->itemData());
+            context->setDefinition(sourceContext->definition());
+        }
+
+        foreach (QSharedPointer<Rule> rule, sourceContext->rules()) {
+            context->addRule(rule, instruction.indexHint() + rulesIncluded);
+            ++rulesIncluded;
+        }
+    }
+    context->clearIncludeRulesInstructions();
+}
diff --git a/src/plugins/texteditor/generichighlighter/highlightdefinitionhandler.h b/src/plugins/texteditor/generichighlighter/highlightdefinitionhandler.h
new file mode 100644 (file)
index 0000000..e08be97
--- /dev/null
@@ -0,0 +1,106 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef HIGHLIGHTDEFINITIONHANDLER_H
+#define HIGHLIGHTDEFINITIONHANDLER_H
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QStack>
+
+#include <QtXml/QXmlDefaultHandler>
+
+namespace TextEditor {
+namespace Internal {
+
+class KeywordList;
+class Context;
+class Rule;
+class HighlightDefinition;
+
+class HighlightDefinitionHandler : public QXmlDefaultHandler
+{
+public:
+    HighlightDefinitionHandler(const QSharedPointer<HighlightDefinition> &definition);
+    ~HighlightDefinitionHandler();
+
+    bool startDocument();
+    bool endDocument();
+    bool startElement(const QString &namespaceURI, const QString &localName,
+                      const QString &qName, const QXmlAttributes &atts);
+    bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName);
+    bool characters(const QString &ch);
+
+private:
+    void listElementStarted(const QXmlAttributes &atts);
+    void itemElementStarted();
+    void contextElementStarted(const QXmlAttributes &atts);
+    void itemDataElementStarted(const QXmlAttributes &atts) const;
+    void commentElementStarted(const QXmlAttributes &atts) const;
+    void keywordsElementStarted(const QXmlAttributes &atts) const;
+    void ruleElementStarted(const QXmlAttributes &atts, const QSharedPointer<Rule> &rule);
+
+    // Specific rules.
+    void detectCharStarted(const QXmlAttributes &atts);
+    void detect2CharsStarted(const QXmlAttributes &atts);
+    void anyCharStarted(const QXmlAttributes &atts);
+    void stringDetectedStarted(const QXmlAttributes &atts);
+    void regExprStarted(const QXmlAttributes &atts);
+    void keywordStarted(const QXmlAttributes &atts);
+    void intStarted(const QXmlAttributes &atts);
+    void floatStarted(const QXmlAttributes &atts);
+    void hlCOctStarted(const QXmlAttributes &atts);
+    void hlCHexStarted(const QXmlAttributes &atts);
+    void hlCStringCharStarted(const QXmlAttributes &atts);
+    void hlCCharStarted(const QXmlAttributes &atts);
+    void rangeDetectStarted(const QXmlAttributes &atts);
+    void lineContinue(const QXmlAttributes &atts);
+    void includeRulesStarted(const QXmlAttributes &atts);
+    void detectSpacesStarted(const QXmlAttributes &atts);
+    void detectIdentifier(const QXmlAttributes &atts);
+
+    void processIncludeRules() const;
+    void processIncludeRules(const QSharedPointer<Context> &context) const;
+
+    QSharedPointer<HighlightDefinition> m_definition;
+
+    bool m_processingKeyword;
+    QString m_currentKeyword;
+    QSharedPointer<KeywordList> m_currentList;
+    QSharedPointer<Context> m_currentContext;
+    QStack<QSharedPointer<Rule> > m_currentRule;
+
+    bool m_initialContext;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // HIGHLIGHTDEFINITIONHANDLER_H
diff --git a/src/plugins/texteditor/generichighlighter/highlighter.cpp b/src/plugins/texteditor/generichighlighter/highlighter.cpp
new file mode 100644 (file)
index 0000000..27b0309
--- /dev/null
@@ -0,0 +1,478 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "highlighter.h"
+#include "highlightdefinition.h"
+#include "context.h"
+#include "rule.h"
+#include "itemdata.h"
+#include "highlighterexception.h"
+#include "progressdata.h"
+#include "reuse.h"
+#include "texteditorconstants.h"
+#include "fontsettings.h"
+
+#include <QtCore/QLatin1String>
+#include <QtCore/QLatin1Char>
+
+using namespace TextEditor;
+using namespace Internal;
+
+namespace {
+    static const QLatin1String kStay("#stay");
+    static const QLatin1String kPop("#pop");
+    static const QLatin1Char kBackSlash('\\');
+    static const QLatin1Char kHash('#');
+}
+
+Highlighter::Highlighter(const QSharedPointer<Context> &defaultContext,QTextDocument *parent) :
+    QSyntaxHighlighter(parent),
+    m_persistentStatesCounter(PersistentsStart),
+    m_dynamicContextsCounter(0),
+    m_isBroken(false),
+    m_defaultContext(defaultContext)
+{
+    m_persistentStates.insert(m_defaultContext->name(), Default);
+}
+
+Highlighter::~Highlighter()
+{}
+
+Highlighter::BlockData::BlockData()
+{}
+
+Highlighter::BlockData::~BlockData()
+{}
+
+void Highlighter::highlightBlock(const QString &text)
+{
+    if (m_isBroken)
+        return;
+
+    try {
+        setupDataForBlock(text);
+
+        handleContextChange(m_currentContext->lineBeginContext(), m_currentContext->definition());
+
+        ProgressData progress;
+        const int length = text.length();
+        while (progress.offset() < length) {
+
+            if (progress.offset() > 0 &&
+                progress.onlySpacesSoFar() &&
+                !text.at(progress.offset()).isSpace()) {
+                progress.setOnlySpacesSoFar(false);
+            }
+
+            iterateThroughRules(text, length, &progress, false, m_currentContext->rules());
+        }
+
+        handleContextChange(m_currentContext->lineEndContext(), m_currentContext->definition(),
+                            false);
+    } catch (const HighlighterException &) {
+        m_isBroken = true;
+        return;
+    }
+
+    m_contexts.clear();
+    applyVisualWhitespaceFormat(text);
+}
+
+void Highlighter::setupDataForBlock(const QString &text)
+{
+    if (currentBlockState() == WillContinue)
+        analyseConsistencyOfWillContinueBlock(text);
+
+    if (previousBlockState() == Default || previousBlockState() == -1)
+        setupDefault();
+    else if (previousBlockState() == WillContinue)
+        setupFromWillContinue();
+    else if (previousBlockState() == Continued)
+        setupFromContinued();
+    else
+        setupFromPersistent();
+
+    setCurrentContext();
+}
+
+void Highlighter::setupDefault()
+{
+    m_contexts.push_back(m_defaultContext);
+
+    setCurrentBlockState(Default);
+}
+
+void Highlighter::setupFromWillContinue()
+{
+    BlockData *previousData = static_cast<BlockData *>(currentBlock().previous().userData());
+    m_contexts.push_back(previousData->m_contextToContinue);
+
+    if (!currentBlockUserData()) {
+        BlockData *data = initializeBlockData();
+        data->m_originalState = previousData->m_originalState;
+    }
+
+    if (currentBlockState() == Default || currentBlockState() == -1)
+        setCurrentBlockState(Continued);
+}
+
+void Highlighter::setupFromContinued()
+{
+    BlockData *previousData = static_cast<BlockData *>(currentBlock().previous().userData());
+
+    Q_ASSERT(previousData->m_originalState != WillContinue &&
+             previousData->m_originalState != Continued);
+
+    if (previousData->m_originalState == Default || previousData->m_originalState == -1)
+        m_contexts.push_back(m_defaultContext);
+    else
+        pushContextSequence(previousData->m_originalState);
+
+    setCurrentBlockState(previousData->m_originalState);
+}
+
+void Highlighter::setupFromPersistent()
+{
+    pushContextSequence(previousBlockState());
+
+    setCurrentBlockState(previousBlockState());
+}
+
+void Highlighter::iterateThroughRules(const QString &text,
+                                      const int length,
+                                      ProgressData *progress,
+                                      const bool childRule,
+                                      const QList<QSharedPointer<Rule> > &rules)
+{
+    typedef QList<QSharedPointer<Rule> >::const_iterator RuleIterator;
+
+    bool contextChanged = false;
+    bool atLeastOneMatch = false;
+
+    RuleIterator it = rules.begin();
+    RuleIterator endIt = rules.end();
+    while (it != endIt && progress->offset() < length) {
+        int startOffset = progress->offset();
+
+        const QSharedPointer<Rule> &rule = *it;
+        if (rule->matchSucceed(text, length, progress)) {
+            atLeastOneMatch = true;
+
+            if (progress->willContinueLine()) {
+                createWillContinueBlock();
+                progress->setWillContinueLine(false);
+                progress->setOffset(length);
+            } else {
+                if (rule->hasChild())
+                    iterateThroughRules(text, length, progress, true, rule->childs());
+
+                if (!rule->context().isEmpty() && contextChangeRequired(rule->context())) {
+                    m_currentCaptures = progress->captures();
+                    changeContext(rule->context(), rule->definition());
+                    contextChanged = true;
+                }
+            }
+
+            // Format is not applied to child rules directly (but relative to the offset of their
+            // parent) nor to look ahead rules.
+            if (!childRule && !rule->isLookAhead()) {
+                if (rule->itemData().isEmpty())
+                    applyFormat(startOffset, progress->offset() - startOffset,
+                                m_currentContext->itemData(), m_currentContext->definition());
+                else
+                    applyFormat(startOffset, progress->offset() - startOffset, rule->itemData(),
+                                rule->definition());
+            }
+
+            // When there is a match of one child rule the others should be skipped. Otherwise
+            // the highlighting would be incorret in a case like 9ULLLULLLUULLULLUL, for example.
+            if (contextChanged || childRule) {
+                break;
+            } else {
+                it = rules.begin();
+                continue;
+            }
+        }
+        ++it;
+    }
+
+    if (!childRule && !atLeastOneMatch) {
+        if (m_currentContext->isFallthrough()) {
+            handleContextChange(m_currentContext->fallthroughContext(),
+                                m_currentContext->definition());
+            iterateThroughRules(text, length, progress, false, m_currentContext->rules());
+        } else {
+            applyFormat(progress->offset(), 1, m_currentContext->itemData(),
+                        m_currentContext->definition());
+            progress->incrementOffset();
+        }
+    }
+}
+
+bool Highlighter::contextChangeRequired(const QString &contextName) const
+{
+    if (contextName == kStay)
+        return false;
+    return true;
+}
+
+void Highlighter::changeContext(const QString &contextName,
+                                const QSharedPointer<HighlightDefinition> &definition,
+                                const bool setCurrent)
+{
+    if (contextName.startsWith(kPop)) {
+        QStringList list = contextName.split(kHash, QString::SkipEmptyParts);
+        for (int i = 0; i < list.size(); ++i)
+            m_contexts.pop_back();
+
+        if (currentBlockState() >= PersistentsStart) {
+            // One or more persistent contexts were popped.
+            const QString &currentSequence = currentContextSequence();
+            if (m_persistentStates.contains(currentSequence))
+                setCurrentBlockState(m_persistentStates.value(currentContextSequence()));
+            else
+                setCurrentBlockState(m_leadingStates.value(currentContextSequence()));
+        }
+    } else {
+        const QSharedPointer<Context> &context = definition->context(contextName);
+
+        if (context->isDynamic())
+            pushDynamicContext(context);
+        else
+            m_contexts.push_back(context);
+
+        if (m_contexts.back()->lineEndContext() == kStay) {
+            // A persistent context was pushed.
+            const QString &currentSequence = currentContextSequence();
+            mapContextSequence(currentSequence);
+            setCurrentBlockState(m_persistentStates.value(currentSequence));
+        }
+    }
+
+    if (setCurrent)
+        setCurrentContext();
+}
+
+void Highlighter::handleContextChange(const QString &contextName,
+                                      const QSharedPointer<HighlightDefinition> &definition,
+                                      const bool setCurrent)
+{
+    if (!contextName.isEmpty() && contextChangeRequired(contextName))
+        changeContext(contextName, definition, setCurrent);
+}
+
+void Highlighter::applyFormat(int offset,
+                              int count,
+                              const QString &itemDataName,
+                              const QSharedPointer<HighlightDefinition> &definition)
+{
+    if (count == 0)
+        return;
+
+    QSharedPointer<ItemData> itemData;
+    try {
+        itemData = definition->itemData(itemDataName);
+    } catch (const HighlighterException &) {
+        // There are some broken files. For instance, the Printf context in java.xml points to an
+        // inexistent Printf item data. These cases are considered to have normal text style.
+        return;
+    }
+
+    if (itemData->style() != ItemData::kDsNormal) {
+        QTextCharFormat format = m_genericFormats.value(itemData->style());
+
+        if (itemData->isCustomized()) {
+            // Please notice that the following are applied every time for item datas which have
+            // customizations. The configureFormats method could be used to provide a "one time"
+            // configuration, but it would probably require to traverse all item datas from all
+            // definitions available/loaded (either to set the values or for some "notifying"
+            // strategy). This is because the highlighter does not really know on which
+            // definition(s) it is working. Since not many item datas specify customizations I
+            // think this approach would fit better. If there are other ideas...
+            if (itemData->color().isValid())
+                format.setForeground(itemData->color());
+            if (itemData->isItalicSpecified())
+                format.setFontItalic(itemData->isItalic());
+            if (itemData->isBoldSpecified())
+                format.setFontWeight(toFontWeight(itemData->isBold()));
+            if (itemData->isUnderlinedSpecified())
+                format.setFontUnderline(itemData->isUnderlined());
+            if (itemData->isStrikedOutSpecified())
+                format.setFontStrikeOut(itemData->isStrikedOut());
+        }
+
+        setFormat(offset, count, format);
+    }
+}
+
+void Highlighter::applyVisualWhitespaceFormat(const QString &text)
+{
+    int offset = 0;
+    const int length = text.length();
+    while (offset < length) {
+        if (text.at(offset).isSpace()) {
+            int start = offset++;
+            while (offset < length && text.at(offset).isSpace())
+                ++offset;
+            setFormat(start, offset - start, m_visualWhitespaceFormat);
+        } else {
+            ++offset;
+        }
+    }
+}
+
+void Highlighter::createWillContinueBlock()
+{
+    if (!currentBlockUserData())
+        initializeBlockData();
+
+    BlockData *data = static_cast<BlockData *>(currentBlockUserData());
+    if (currentBlockState() == Continued) {
+        BlockData *previousData = static_cast<BlockData *>(currentBlock().previous().userData());
+        data->m_originalState = previousData->m_originalState;
+    } else if (currentBlockState() != WillContinue) {
+        data->m_originalState = currentBlockState();
+    }
+    data->m_contextToContinue = m_currentContext;
+
+    setCurrentBlockState(WillContinue);
+}
+
+void Highlighter::analyseConsistencyOfWillContinueBlock(const QString &text)
+{
+    if (currentBlock().next().isValid() && (
+        text.length() == 0 || text.at(text.length() - 1) != kBackSlash) &&
+        currentBlock().next().userState() != Continued) {
+        currentBlock().next().setUserState(Continued);
+    }
+
+    if (text.length() == 0 || text.at(text.length() - 1) != kBackSlash) {
+        BlockData *data = static_cast<BlockData *>(currentBlockUserData());
+        data->m_contextToContinue.clear();
+        setCurrentBlockState(data->m_originalState);
+    }
+}
+
+void Highlighter::mapContextSequence(const QString &contextSequence)
+{
+    if (currentBlockState() < PersistentsStart && !m_leadingStates.contains(contextSequence))
+        m_leadingStates.insert(contextSequence, currentBlockState());
+
+    if (!m_persistentStates.contains(contextSequence)) {
+        int newState = m_persistentStatesCounter;
+        m_persistentStates.insert(contextSequence, newState);
+        m_persistentContexts.insert(newState, m_contexts);
+        ++m_persistentStatesCounter;
+    }
+}
+
+void Highlighter::pushContextSequence(int state)
+{
+    const QVector<QSharedPointer<Context> > &contexts = m_persistentContexts.value(state);
+    for (int i = 0; i < contexts.size(); ++i)
+        m_contexts.push_back(contexts.at(i));
+}
+
+QString Highlighter::currentContextSequence() const
+{
+    QString sequence;
+    for (int i = 0; i < m_contexts.size(); ++i)
+        sequence.append(m_contexts.at(i)->id());
+
+    return sequence;
+}
+
+Highlighter::BlockData *Highlighter::initializeBlockData()
+{
+    BlockData *data = new BlockData;
+    setCurrentBlockUserData(data);
+    return data;
+}
+
+void Highlighter::pushDynamicContext(const QSharedPointer<Context> &baseContext)
+{
+    // A dynamic context is created from another context which serves as its basis. Then,
+    // its rules are updated according to the captures from the calling regular expression which
+    // triggered the push of the dynamic context.
+    QSharedPointer<Context> context(new Context(*baseContext));
+    context->configureId(m_dynamicContextsCounter);
+    context->updateDynamicRules(m_currentCaptures);
+    m_contexts.push_back(context);
+    ++m_dynamicContextsCounter;
+}
+
+void Highlighter::setCurrentContext()
+{
+    if (m_contexts.isEmpty()) {
+        // This is not supposed to happen. However, there are broken files (for example, php.xml)
+        // which will cause this behaviour. In such cases pushing the default context is enough to
+        // keep highlighter working.
+        m_contexts.push_back(m_defaultContext);
+    }
+    m_currentContext = m_contexts.back();
+}
+
+void Highlighter::configureFormats(const FontSettings & fs)
+{
+    m_visualWhitespaceFormat = fs.toTextCharFormat(
+            QLatin1String(TextEditor::Constants::C_VISUAL_WHITESPACE));
+
+    m_genericFormats[ItemData::kDsKeyword] = fs.toTextCharFormat(
+            QLatin1String(TextEditor::Constants::C_KEYWORD));
+    m_genericFormats[ItemData::kDsDataType] = fs.toTextCharFormat(
+            QLatin1String(TextEditor::Constants::C_TYPE));
+    // Currenlty using C_NUMBER for all kinds of numbers.
+    m_genericFormats[ItemData::kDsDecVal] = fs.toTextCharFormat(
+            QLatin1String(TextEditor::Constants::C_NUMBER));
+    m_genericFormats[ItemData::kDsBaseN] = fs.toTextCharFormat(
+            QLatin1String(TextEditor::Constants::C_NUMBER));
+    m_genericFormats[ItemData::kDsFloat] = fs.toTextCharFormat(
+            QLatin1String(TextEditor::Constants::C_NUMBER));
+    // Currently using C_STRING for strings and chars.
+    m_genericFormats[ItemData::kDsChar] = fs.toTextCharFormat(
+            QLatin1String(TextEditor::Constants::C_STRING));
+    m_genericFormats[ItemData::kDsString] = fs.toTextCharFormat(
+            QLatin1String(TextEditor::Constants::C_STRING));
+    m_genericFormats[ItemData::kDsComment] = fs.toTextCharFormat(
+            QLatin1String(TextEditor::Constants::C_COMMENT));
+
+    // Currently Creator does not have corresponding formats for the following items. We can
+    // implement them... Just for now I will leave hardcoded colors.
+    QTextCharFormat format;
+    format.setForeground(Qt::blue);
+    m_genericFormats[ItemData::kDsOthers] = format;
+    format.setForeground(Qt::red);
+    m_genericFormats[ItemData::kDsAlert] = format;
+    format.setForeground(Qt::darkBlue);
+    m_genericFormats[ItemData::kDsFunction] = format;
+    format.setForeground(Qt::darkGray);
+    m_genericFormats[ItemData::kDsRegionMarker] = format;
+    format.setForeground(Qt::darkRed);
+    m_genericFormats[ItemData::kDsError] = format;
+}
diff --git a/src/plugins/texteditor/generichighlighter/highlighter.h b/src/plugins/texteditor/generichighlighter/highlighter.h
new file mode 100644 (file)
index 0000000..bbf7e76
--- /dev/null
@@ -0,0 +1,154 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef HIGHLIGHTER_H
+#define HIGHLIGHTER_H
+
+#include "basetextdocumentlayout.h"
+
+#include <QtCore/QString>
+#include <QtCore/QVector>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QStringList>
+
+#include <QtGui/QSyntaxHighlighter>
+
+namespace TextEditor {
+class FontSettings;
+}
+
+namespace TextEditor {
+namespace Internal {
+
+class Rule;
+class Context;
+class HighlightDefinition;
+class ProgressData;
+
+class Highlighter : public QSyntaxHighlighter
+{
+public:
+    Highlighter(const QSharedPointer<Context> &defaultContext, QTextDocument *parent = 0);
+    virtual ~Highlighter();
+
+    void configureFormats(const FontSettings & fs);
+
+protected:
+    virtual void highlightBlock(const QString &text);
+
+private:
+
+    void setupDataForBlock(const QString &text);
+    void setupDefault();
+    void setupFromWillContinue();
+    void setupFromContinued();
+    void setupFromPersistent();
+
+    void iterateThroughRules(const QString &text,
+                             const int length,
+                             ProgressData *progress,
+                             const bool childRule,
+                             const QList<QSharedPointer<Rule> > &rules);
+
+    bool contextChangeRequired(const QString &contextName) const;
+    void handleContextChange(const QString &contextName,
+                             const QSharedPointer<HighlightDefinition> &definition,
+                             const bool setCurrent = true);
+    void changeContext(const QString &contextName,
+                       const QSharedPointer<HighlightDefinition> &definition,
+                       const bool setCurrent = true);
+
+    void applyFormat(int offset,
+                     int count,
+                     const QString &itemDataName,
+                     const QSharedPointer<HighlightDefinition> &definition);
+    void applyVisualWhitespaceFormat(const QString &text);
+
+    QString currentContextSequence() const;
+    void mapContextSequence(const QString &contextSequence);
+    void pushContextSequence(int state);
+    void pushDynamicContext(const QSharedPointer<Context> &baseContext);
+
+    void setCurrentContext();
+
+    void createWillContinueBlock();
+    void analyseConsistencyOfWillContinueBlock(const QString &text);
+
+    struct BlockData : TextBlockUserData
+    {
+        BlockData();
+        virtual ~BlockData();
+
+        int m_originalState;
+        QSharedPointer<Context> m_contextToContinue;
+    };
+    BlockData *initializeBlockData();
+
+    // Block states
+    // - Default [0]: Nothing special.
+    // - WillContinue [1]: When there is match of the LineContinue rule (backslash as the last
+    //   character).
+    // - Continued [2]: Blocks that happen after a WillContinue block and continued from their
+    //   context until the next line end.
+    // - Persistent(s) [Anything >= 3]: Correspond to persistent contexts which last until a pop
+    //   occurs due to a matching rule. Every sequence of persistent contexts seen so far is
+    //   associated with a number (incremented by a unit each time).
+    enum BlockState {
+        Default = 0,
+        WillContinue,
+        Continued,
+        PersistentsStart
+    };
+    int m_persistentStatesCounter;
+    int m_dynamicContextsCounter;
+
+    bool m_isBroken;
+
+    QSharedPointer<Context> m_defaultContext;
+    QSharedPointer<Context> m_currentContext;
+    QVector<QSharedPointer<Context> > m_contexts;
+
+    // Mapping from context sequences to the persistent state they represent.
+    QHash<QString, int> m_persistentStates;
+    // Mapping from context sequences to the non-persistent state that led to them.
+    QHash<QString, int> m_leadingStates;
+    // Mapping from persistent states to context sequences (the actual "stack").
+    QHash<int, QVector<QSharedPointer<Context> > > m_persistentContexts;
+
+    // Captures used in dynamic rules.
+    QStringList m_currentCaptures;
+
+    QTextCharFormat m_visualWhitespaceFormat;
+    QHash<QString, QTextCharFormat> m_genericFormats;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // HIGHLIGHTER_H
diff --git a/src/plugins/texteditor/generichighlighter/highlighterexception.h b/src/plugins/texteditor/generichighlighter/highlighterexception.h
new file mode 100644 (file)
index 0000000..1331040
--- /dev/null
@@ -0,0 +1,41 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef HIGHLIGHTEREXCEPTION_H
+#define HIGHLIGHTEREXCEPTION_H
+
+namespace TextEditor {
+namespace Internal {
+
+class HighlighterException {};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // HIGHLIGHTEREXCEPTION_H
diff --git a/src/plugins/texteditor/generichighlighter/includerulesinstruction.cpp b/src/plugins/texteditor/generichighlighter/includerulesinstruction.cpp
new file mode 100644 (file)
index 0000000..8b04826
--- /dev/null
@@ -0,0 +1,50 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "includerulesinstruction.h"
+#include "reuse.h"
+
+using namespace TextEditor;
+using namespace Internal;
+
+IncludeRulesInstruction::IncludeRulesInstruction(const QString &context,
+                                                 int hint,
+                                                 const QString &replaceItemData) :
+    m_sourceContext(context), m_indexHint(hint), m_replaceItemData(toBool(replaceItemData))
+{
+}
+
+const QString &IncludeRulesInstruction::sourceContext() const
+{ return m_sourceContext; }
+
+int IncludeRulesInstruction::indexHint() const
+{ return m_indexHint; }
+
+bool IncludeRulesInstruction::replaceItemData() const
+{ return m_replaceItemData; }
diff --git a/src/plugins/texteditor/generichighlighter/includerulesinstruction.h b/src/plugins/texteditor/generichighlighter/includerulesinstruction.h
new file mode 100644 (file)
index 0000000..c0f5d6e
--- /dev/null
@@ -0,0 +1,56 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef INCLUDERULESINSTRUCTION_H
+#define INCLUDERULESINSTRUCTION_H
+
+#include <QtCore/QString>
+
+namespace TextEditor {
+namespace Internal {
+
+class IncludeRulesInstruction
+{
+public:
+    IncludeRulesInstruction(const QString &context, int hint, const QString &replaceItemData);
+
+    const QString &sourceContext() const;
+    int indexHint() const;
+    bool replaceItemData() const;
+
+private:
+    QString m_sourceContext;
+    int m_indexHint;
+    bool m_replaceItemData;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // INCLUDERULESINSTRUCTION_H
diff --git a/src/plugins/texteditor/generichighlighter/itemdata.cpp b/src/plugins/texteditor/generichighlighter/itemdata.cpp
new file mode 100644 (file)
index 0000000..498d968
--- /dev/null
@@ -0,0 +1,148 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "itemdata.h"
+#include "reuse.h"
+
+using namespace TextEditor;
+using namespace Internal;
+
+const QLatin1String ItemData::kDsNormal("dsNormal");
+const QLatin1String ItemData::kDsKeyword("dsKeyword");
+const QLatin1String ItemData::kDsDataType("dsDataType");
+const QLatin1String ItemData::kDsDecVal("dsDecVal");
+const QLatin1String ItemData::kDsBaseN("dsBaseN");
+const QLatin1String ItemData::kDsFloat("dsFloat");
+const QLatin1String ItemData::kDsChar("dsChar");
+const QLatin1String ItemData::kDsString("dsString");
+const QLatin1String ItemData::kDsComment("dsComment");
+const QLatin1String ItemData::kDsOthers("dsOthers");
+const QLatin1String ItemData::kDsAlert("dsAlert");
+const QLatin1String ItemData::kDsFunction("dsFunction");
+const QLatin1String ItemData::kDsRegionMarker("dsRegionMarker");
+const QLatin1String ItemData::kDsError("dsError");
+
+ItemData::ItemData() :
+    m_italicSpecified(false),
+    m_boldSpecified(false),
+    m_underlinedSpecified(false),
+    m_strikedOutSpecified(false),
+    m_isCustomized(false)
+{}
+
+void ItemData::setStyle(const QString &style)
+{ m_style = style; }
+
+const QString &ItemData::style() const
+{ return m_style; }
+
+void ItemData::setColor(const QString &color)
+{
+    if (!color.isEmpty()) {
+        m_color.setNamedColor(color);
+        m_isCustomized = true;
+    }
+}
+
+const QColor &ItemData::color() const
+{ return m_color; }
+
+void ItemData::setSelectionColor(const QString &color)
+{
+    if (!color.isEmpty()) {
+        m_selectionColor.setNamedColor(color);
+        m_isCustomized = true;
+    }
+}
+
+const QColor &ItemData::selectionColor() const
+{ return m_selectionColor; }
+
+void ItemData::setItalic(const QString &italic)
+{
+    if (!italic.isEmpty()) {
+        m_italic = toBool(italic);
+        m_italicSpecified = true;
+        m_isCustomized = true;
+    }
+}
+
+bool ItemData::isItalic() const
+{ return m_italic; }
+
+bool ItemData::isItalicSpecified() const
+{ return m_italicSpecified; }
+
+void ItemData::setBold(const QString &bold)
+{
+    if (!bold.isEmpty()) {
+        m_bold = toBool(bold);
+        m_boldSpecified = true;
+        m_isCustomized = true;
+    }
+}
+
+bool ItemData::isBold() const
+{ return m_bold; }
+
+bool ItemData::isBoldSpecified() const
+{ return m_boldSpecified; }
+
+void ItemData::setUnderlined(const QString &underlined)
+{
+    if (!underlined.isEmpty()) {
+        m_underlined = toBool(underlined);
+        m_underlinedSpecified = true;
+        m_isCustomized = true;
+    }
+}
+
+bool ItemData::isUnderlined() const
+{ return m_underlined; }
+
+bool ItemData::isUnderlinedSpecified() const
+{ return m_underlinedSpecified; }
+
+void ItemData::setStrikedOut(const QString &striked)
+{
+    if (!striked.isEmpty()) {
+        m_strikedOut = toBool(striked);
+        m_strikedOutSpecified = true;
+        m_isCustomized = true;
+    }
+}
+
+bool ItemData::isStrikedOut() const
+{ return m_strikedOut; }
+
+bool ItemData::isStrikedOutSpecified() const
+{ return m_strikedOutSpecified; }
+
+bool ItemData::isCustomized() const
+{ return m_isCustomized; }
diff --git a/src/plugins/texteditor/generichighlighter/itemdata.h b/src/plugins/texteditor/generichighlighter/itemdata.h
new file mode 100644 (file)
index 0000000..c130239
--- /dev/null
@@ -0,0 +1,104 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef ITEMDATA_H
+#define ITEMDATA_H
+
+#include <QtCore/QString>
+#include <QtGui/QColor>
+
+namespace TextEditor {
+namespace Internal {
+
+class ItemData
+{
+public:
+    ItemData();
+
+    void setStyle(const QString &style);
+    const QString &style() const;
+
+    void setColor(const QString &color);
+    const QColor &color() const;
+
+    void setSelectionColor(const QString &color);
+    const QColor &selectionColor() const;
+
+    void setItalic(const QString &italic);
+    bool isItalic() const;
+    bool isItalicSpecified() const;
+
+    void setBold(const QString &bold);
+    bool isBold() const;
+    bool isBoldSpecified() const;
+
+    void setUnderlined(const QString &underlined);
+    bool isUnderlined() const;
+    bool isUnderlinedSpecified() const;
+
+    void setStrikedOut(const QString &striked);
+    bool isStrikedOut() const;
+    bool isStrikedOutSpecified() const;
+
+    bool isCustomized() const;
+
+    static const QLatin1String kDsNormal;
+    static const QLatin1String kDsKeyword;
+    static const QLatin1String kDsDataType;
+    static const QLatin1String kDsDecVal;
+    static const QLatin1String kDsBaseN;
+    static const QLatin1String kDsFloat;
+    static const QLatin1String kDsChar;
+    static const QLatin1String kDsString;
+    static const QLatin1String kDsComment;
+    static const QLatin1String kDsOthers;
+    static const QLatin1String kDsAlert;
+    static const QLatin1String kDsFunction;
+    static const QLatin1String kDsRegionMarker;
+    static const QLatin1String kDsError;
+
+private:
+    QString m_style;
+    QColor m_color;
+    QColor m_selectionColor;
+    bool m_italic;
+    bool m_italicSpecified;
+    bool m_bold;
+    bool m_boldSpecified;
+    bool m_underlined;
+    bool m_underlinedSpecified;
+    bool m_strikedOut;
+    bool m_strikedOutSpecified;
+    bool m_isCustomized;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // ITEMDATA_H
diff --git a/src/plugins/texteditor/generichighlighter/keywordlist.cpp b/src/plugins/texteditor/generichighlighter/keywordlist.cpp
new file mode 100644 (file)
index 0000000..48c9672
--- /dev/null
@@ -0,0 +1,61 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "keywordlist.h"
+
+using namespace TextEditor;
+using namespace Internal;
+
+void KeywordList::addKeyword(const QString &keyword)
+{
+    if (keyword.isEmpty())
+        return; 
+
+    m_keywords.insert(keyword);
+}
+
+bool KeywordList::isKeyword(const QString &keyword, Qt::CaseSensitivity sensitivity) const
+{
+    if (keyword.isEmpty())
+        return false;
+
+    // Case sensitivity could be implemented, for example, by converting all keywords to lower
+    // if the global sensitivity attribute is insensitive, then always checking for containment
+    // (with a conversion to lower in the necessary cases). But the code below is one alternative
+    // to support the existence of local sensitivity attributes (which override the global one -
+    // currently not documented).
+    if (sensitivity == Qt::CaseSensitive) {
+        return m_keywords.contains(keyword);
+    } else {
+        foreach (const QString &s, m_keywords)
+            if (keyword.compare(s, Qt::CaseInsensitive) == 0)
+                return true;
+        return false;
+    }
+}
diff --git a/src/plugins/texteditor/generichighlighter/keywordlist.h b/src/plugins/texteditor/generichighlighter/keywordlist.h
new file mode 100644 (file)
index 0000000..82495ca
--- /dev/null
@@ -0,0 +1,53 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef KEYWORDLIST_H
+#define KEYWORDLIST_H
+
+#include <QtCore/QString>
+#include <QtCore/QSet>
+
+namespace TextEditor {
+namespace Internal {
+
+class KeywordList
+{
+public:
+
+    void addKeyword(const QString &keyword);
+    bool isKeyword(const QString &keyword, Qt::CaseSensitivity sensitivity) const;
+
+private:
+    QSet<QString> m_keywords;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // KEYWORDLIST_H
diff --git a/src/plugins/texteditor/generichighlighter/manager.cpp b/src/plugins/texteditor/generichighlighter/manager.cpp
new file mode 100644 (file)
index 0000000..1c41983
--- /dev/null
@@ -0,0 +1,240 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "manager.h"
+#include "highlightdefinition.h"
+#include "highlightdefinitionhandler.h"
+#include "highlighterexception.h"
+#include "texteditorplugin.h"
+#include "texteditorsettings.h"
+#include "plaintexteditorfactory.h"
+
+#include <coreplugin/icore.h>
+#include <utils/qtcassert.h>
+#include <qtconcurrent/QtConcurrentTools>
+
+#include <QtCore/QtAlgorithms>
+#include <QtCore/QtPlugin>
+#include <QtCore/QString>
+#include <QtCore/QLatin1Char>
+#include <QtCore/QLatin1String>
+#include <QtCore/QStringList>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+#include <QtCore/QList>
+#include <QtCore/QRegExp>
+#include <QtCore/QFuture>
+#include <QtCore/QtConcurrentRun>
+#include <QtXml/QXmlSimpleReader>
+#include <QtXml/QXmlInputSource>
+#include <QtXml/QXmlStreamReader>
+#include <QtXml/QXmlStreamAttributes>
+
+using namespace TextEditor;
+using namespace Internal;
+
+Manager::Manager()
+{}
+
+Manager::~Manager()
+{
+}
+
+Manager *Manager::instance()
+{
+    static Manager manager;
+    return &manager;
+}
+
+QString Manager::definitionIdByName(const QString &name) const
+{ return m_idByName.value(name); }
+
+QString Manager::definitionIdByMimeType(const QString &mimeType) const
+{
+    Q_ASSERT(!mimeType.isEmpty());
+
+    if (m_idByMimeType.count(mimeType) <= 1) {
+        return m_idByMimeType.value(mimeType);
+    } else {
+        QStringList candidateIds;
+        QMultiHash<QString, QString>::const_iterator it = m_idByMimeType.find(mimeType);
+        QMultiHash<QString, QString>::const_iterator endIt = m_idByMimeType.end();
+        for (; it != endIt && it.key() == mimeType; ++it)
+            candidateIds.append(it.value());
+
+        qSort(candidateIds.begin(), candidateIds.end(), m_priorityComp);
+        return candidateIds.last();
+    }
+}
+
+const QSharedPointer<HighlightDefinition> &Manager::definition(const QString &id)
+{
+    if (!m_definitions.contains(id)) {
+        m_isBuilding.insert(id);
+
+        QFile definitionFile(id);
+        if (!definitionFile.open(QIODevice::ReadOnly | QIODevice::Text))
+            throw HighlighterException();
+        QXmlInputSource source(&definitionFile);
+
+        QSharedPointer<HighlightDefinition> definition(new HighlightDefinition);
+        HighlightDefinitionHandler handler(definition);
+
+        QXmlSimpleReader reader;
+        reader.setContentHandler(&handler);
+        reader.parse(source);
+
+        m_definitions.insert(id, definition);
+        definitionFile.close();
+        m_isBuilding.remove(id);
+    }
+
+    return *m_definitions.constFind(id);
+}
+
+bool Manager::isBuildingDefinition(const QString &id) const
+{ return m_isBuilding.contains(id); }
+
+void Manager::registerMimeTypes()
+{
+    QFuture<Core::MimeType> future =
+            QtConcurrent::run(&Manager::gatherDefinitionsMimeTypes, this);
+    m_watcher.setFuture(future);
+
+    connect(&m_watcher, SIGNAL(resultReadyAt(int)), this, SLOT(registerMimeType(int)));
+}
+
+void Manager::gatherDefinitionsMimeTypes(QFutureInterface<Core::MimeType> &future)
+{
+    QDir definitionsDir(Core::ICore::instance()->resourcePath() +
+                        QLatin1String("/generic-highlighter"));
+
+    QStringList filter(QLatin1String("*.xml"));
+    definitionsDir.setNameFilters(filter);
+
+    const QFileInfoList &filesInfo = definitionsDir.entryInfoList();
+    foreach (const QFileInfo &fileInfo, filesInfo) {
+        QString comment;
+        QStringList mimeTypes;
+        QStringList patterns;
+        parseDefinitionMetadata(fileInfo, &comment, &mimeTypes, &patterns);
+
+        // A definition can specify multiple MIME types and file extensions/patterns. However, each
+        // thing is done with a single string. Then, there is no direct way to tell which patterns
+        // belong to which MIME types nor whether a MIME type is just an alias for the other.
+        // Currently, I associate all expressions/patterns with all MIME types from a definition.
+
+        static const QStringList textPlain(QLatin1String("text/plain"));
+
+        QList<QRegExp> expressions;
+        foreach (const QString &type, mimeTypes) {
+            Core::MimeType mimeType = Core::ICore::instance()->mimeDatabase()->findByType(type);
+            if (mimeType.isNull()) {
+                if (expressions.isEmpty()) {
+                    foreach (const QString &pattern, patterns)
+                        expressions.append(QRegExp(pattern, Qt::CaseSensitive, QRegExp::Wildcard));
+                }
+
+                mimeType.setType(type);
+                mimeType.setSubClassesOf(textPlain);
+                mimeType.setComment(comment);
+                mimeType.setGlobPatterns(expressions);
+
+                future.reportResult(mimeType);
+            }
+        }
+    }
+}
+
+void Manager::registerMimeType(int index) const
+{
+    const Core::MimeType &mimeType = m_watcher.resultAt(index);
+    Core::ICore::instance()->mimeDatabase()->addMimeType(mimeType);
+    TextEditorPlugin::instance()->editorFactory()->addMimeType(mimeType.type());
+}
+
+void Manager::parseDefinitionMetadata(const QFileInfo &fileInfo,
+                                                  QString *comment,
+                                                  QStringList *mimeTypes,
+                                                  QStringList *patterns)
+{
+    static const QLatin1Char kSemiColon(';');
+    static const QLatin1Char kSlash('/');
+    static const QLatin1String kLanguage("language");
+    static const QLatin1String kName("name");
+    static const QLatin1String kExtensions("extensions");
+    static const QLatin1String kMimeType("mimetype");
+    static const QLatin1String kPriority("priority");
+    static const QLatin1String kArtificial("artificial");
+
+    const QString &id = fileInfo.absoluteFilePath();
+
+    QFile definitionFile(id);
+    if (!definitionFile.open(QIODevice::ReadOnly | QIODevice::Text))
+        return;
+
+    QXmlStreamReader reader(&definitionFile);
+    while (!reader.atEnd() && !reader.hasError()) {
+        if (reader.readNext() == QXmlStreamReader::StartElement &&
+            reader.name() == kLanguage) {
+            const QXmlStreamAttributes &attr = reader.attributes();
+
+            *comment = attr.value(kName).toString();
+            m_idByName.insert(*comment, id);
+
+            *patterns = attr.value(kExtensions).toString().split(kSemiColon,
+                                                                 QString::SkipEmptyParts);
+
+            *mimeTypes = attr.value(kMimeType).toString().split(kSemiColon,
+                                                                QString::SkipEmptyParts);
+            if (mimeTypes->isEmpty()) {
+                // There are definitions which do not specify a MIME type, but specify file
+                // patterns. Creating an artificial MIME type is a workaround.
+                QString artificialType(kArtificial);
+                artificialType.append(kSlash).append(*comment);
+                m_idByMimeType.insert(artificialType, id);
+                mimeTypes->append(artificialType);
+            } else {
+                foreach (const QString &type, *mimeTypes)
+                    m_idByMimeType.insert(type, id);
+            }
+
+            // The priority below should not be confused with the priority used when matching files
+            // to MIME types. Kate uses this when there are definitions which share equal
+            // extensions/patterns. Here it is for choosing a highlight definition if there are
+            // multiple ones associated with the same MIME type (should not happen in general).
+            m_priorityComp.m_priorityById.insert(id, attr.value(kPriority).toString().toInt());
+
+            break;
+        }
+    }
+    reader.clear();
+    definitionFile.close();
+}
diff --git a/src/plugins/texteditor/generichighlighter/manager.h b/src/plugins/texteditor/generichighlighter/manager.h
new file mode 100644 (file)
index 0000000..2c0073e
--- /dev/null
@@ -0,0 +1,99 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef MANAGER_H
+#define MANAGER_H
+
+#include <coreplugin/mimedatabase.h>
+
+#include <QtCore/QString>
+#include <QtCore/QHash>
+#include <QtCore/QMultiHash>
+#include <QtCore/QSet>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QFutureWatcher>
+
+QT_BEGIN_NAMESPACE
+class QFileInfo;
+class QStringList;
+template <class> class QFutureInterface;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+namespace Internal {
+
+class HighlightDefinition;
+
+class Manager : public QObject
+{
+    Q_OBJECT
+public:
+    virtual ~Manager();
+    static Manager *instance();
+
+    QString definitionIdByName(const QString &name) const;
+    QString definitionIdByMimeType(const QString &mimeType) const;
+    bool isBuildingDefinition(const QString &id) const;
+    const QSharedPointer<HighlightDefinition> &definition(const QString &id);
+
+private slots:
+    void registerMimeTypes();
+    void registerMimeType(int index) const;
+
+private:
+    Manager();
+    Q_DISABLE_COPY(Manager)
+
+    void gatherDefinitionsMimeTypes(QFutureInterface<Core::MimeType> &future);
+    void parseDefinitionMetadata(const QFileInfo &fileInfo,
+                                 QString *comment,
+                                 QStringList *mimeTypes,
+                                 QStringList *patterns);
+
+    struct PriorityCompare
+    {
+        bool operator()(const QString &a, const QString &b) const
+        { return m_priorityById.value(a) < m_priorityById.value(b); }
+
+        QHash<QString, int> m_priorityById;
+    };
+    PriorityCompare m_priorityComp;
+
+    QFutureWatcher<Core::MimeType> m_watcher;
+
+    QHash<QString, QString> m_idByName;
+    QMultiHash<QString, QString> m_idByMimeType;
+    QHash<QString, QSharedPointer<HighlightDefinition> > m_definitions;
+    QSet<QString> m_isBuilding;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // MANAGER_H
diff --git a/src/plugins/texteditor/generichighlighter/progressdata.cpp b/src/plugins/texteditor/generichighlighter/progressdata.cpp
new file mode 100644 (file)
index 0000000..12c7607
--- /dev/null
@@ -0,0 +1,82 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "progressdata.h"
+
+#include <QtCore/QtGlobal>
+
+using namespace TextEditor;
+using namespace Internal;
+
+ProgressData::ProgressData() :
+    m_offset(0),
+    m_savedOffset(-1),
+    m_onlySpacesSoFar(true),
+    m_willContinueLine(false)
+{}
+
+void ProgressData::setOffset(const int offset)
+{ m_offset = offset; }
+
+int ProgressData::offset() const
+{ return m_offset; }
+
+void ProgressData::incrementOffset()
+{ ++m_offset; }
+
+void ProgressData::incrementOffset(const int increment)
+{ m_offset += increment; }
+
+void ProgressData::saveOffset()
+{ m_savedOffset = m_offset; }
+
+void ProgressData::restoreOffset()
+{
+    Q_ASSERT(m_savedOffset != -1);
+    m_offset = m_savedOffset;
+    m_savedOffset = -1;
+}
+
+void ProgressData::setOnlySpacesSoFar(const bool onlySpaces)
+{ m_onlySpacesSoFar = onlySpaces; }
+
+bool ProgressData::onlySpacesSoFar() const
+{ return m_onlySpacesSoFar; }
+
+void ProgressData::setWillContinueLine(const bool willContinue)
+{ m_willContinueLine = willContinue; }
+
+bool ProgressData::willContinueLine() const
+{ return m_willContinueLine; }
+
+void ProgressData::setCaptures(const QStringList &captures)
+{ m_captures = captures; }
+
+const QStringList &ProgressData::captures() const
+{ return m_captures; }
diff --git a/src/plugins/texteditor/generichighlighter/progressdata.h b/src/plugins/texteditor/generichighlighter/progressdata.h
new file mode 100644 (file)
index 0000000..a621c15
--- /dev/null
@@ -0,0 +1,72 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef PROGRESSDATA_H
+#define PROGRESSDATA_H
+
+#include <QtCore/QStringList>
+
+namespace TextEditor {
+namespace Internal {
+
+class ProgressData
+{
+public:
+    ProgressData();
+
+    void setOffset(const int offset);
+    int offset() const;
+
+    void incrementOffset();
+    void incrementOffset(const int increment);
+
+    void saveOffset();
+    void restoreOffset();
+
+    void setOnlySpacesSoFar(const bool onlySpaces);
+    bool onlySpacesSoFar() const;
+
+    void setWillContinueLine(const bool willContinue);
+    bool willContinueLine() const;
+
+    void setCaptures(const QStringList &captures);
+    const QStringList &captures() const;
+
+private:
+    int m_offset;
+    int m_savedOffset;
+    bool m_onlySpacesSoFar;
+    bool m_willContinueLine;
+    QStringList m_captures;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // PROGRESSDATA_H
diff --git a/src/plugins/texteditor/generichighlighter/reuse.h b/src/plugins/texteditor/generichighlighter/reuse.h
new file mode 100644 (file)
index 0000000..197e304
--- /dev/null
@@ -0,0 +1,100 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef REUSE_H
+#define REUSE_H
+
+#include <Qt>
+#include <QtCore/QString>
+#include <QtCore/QLatin1String>
+#include <QtCore/QChar>
+#include <QtGui/QFont>
+
+namespace TextEditor {
+namespace Internal {
+
+inline bool toBool(const QString &s)
+{
+    static const QLatin1String kTrue("true");
+    static const QLatin1String k1("1");
+
+    if (s.toLower() == kTrue || s == k1)
+        return true;
+    return false;
+}
+
+
+inline Qt::CaseSensitivity toCaseSensitivity(const bool sensitive)
+{
+    if (sensitive)
+        return Qt::CaseSensitive;
+    return Qt::CaseInsensitive;
+}
+
+inline QFont::Weight toFontWeight(const bool bold)
+{
+    if (bold)
+        return QFont::Bold;
+    else
+        return QFont::Normal;
+}
+
+inline bool isOctalDigit(const QChar &c)
+{
+    static const QLatin1Char k0('0');
+    static const QLatin1Char k7('7');
+
+    return c >= k0 && c <= k7;
+}
+
+inline bool isHexDigit(const QChar &c)
+{
+    static const QLatin1Char k0('0');
+    static const QLatin1Char k9('9');
+    static const QLatin1Char kA('A');
+    static const QLatin1Char kF('F');
+    static const QLatin1Char ka('a');
+    static const QLatin1Char kf('f');
+
+    if ((c >= k0 && c <= k9) || (c >= kA && c <= kF) || (c >= ka && c <= kf))
+        return true;
+
+    return false;
+}
+
+inline void setStartCharacter(QChar &c, const QString &character)
+{
+    if (!character.isEmpty())
+        c = character.at(0);
+}
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // REUSE_H
diff --git a/src/plugins/texteditor/generichighlighter/rule.cpp b/src/plugins/texteditor/generichighlighter/rule.cpp
new file mode 100644 (file)
index 0000000..1ca7349
--- /dev/null
@@ -0,0 +1,292 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "rule.h"
+#include "highlighterexception.h"
+#include "progressdata.h"
+#include "highlightdefinition.h"
+#include "reuse.h"
+
+#include <QtCore/QStringList>
+
+#include <functional>
+
+using namespace TextEditor;
+using namespace Internal;
+
+const QLatin1Char Rule::kBackSlash('\\');
+const QLatin1Char Rule::kUnderscore('_');
+const QLatin1Char Rule::kDot('.');
+const QLatin1Char Rule::kPlus('+');
+const QLatin1Char Rule::kMinus('-');
+const QLatin1Char Rule::kZero('0');
+const QLatin1Char Rule::kQuote('\"');
+const QLatin1Char Rule::kSingleQuote('\'');
+const QLatin1Char Rule::kQuestion('?');
+const QLatin1Char Rule::kX('x');
+const QLatin1Char Rule::kA('a');
+const QLatin1Char Rule::kB('b');
+const QLatin1Char Rule::kE('e');
+const QLatin1Char Rule::kF('f');
+const QLatin1Char Rule::kN('n');
+const QLatin1Char Rule::kR('r');
+const QLatin1Char Rule::kT('t');
+const QLatin1Char Rule::kV('v');
+
+Rule::Rule(bool consumesNonSpace) :
+    m_lookAhead(false), m_firstNonSpace(false), m_column(-1), m_consumesNonSpace(consumesNonSpace)
+{}
+
+Rule::~Rule()
+{}
+
+void Rule::setContext(const QString &context)
+{ m_context = context; }
+
+const QString &Rule::context() const
+{ return m_context; }
+
+void Rule::setItemData(const QString &itemData)
+{ m_itemData = itemData; }
+
+const QString &Rule::itemData() const
+{ return m_itemData; }
+
+void Rule::setBeginRegion(const QString &begin)
+{ m_beginRegion = begin; }
+
+const QString &Rule::beginRegion() const
+{ return m_beginRegion; }
+
+void Rule::setEndRegion(const QString &end)
+{ m_endRegion = end; }
+
+const QString &Rule::endRegion() const
+{ return m_endRegion; }
+
+void Rule::setLookAhead(const QString &lookAhead)
+{ m_lookAhead = toBool(lookAhead); }
+
+bool Rule::isLookAhead() const
+{ return m_lookAhead; }
+
+void Rule::setFirstNonSpace(const QString &firstNonSpace)
+{ m_firstNonSpace = toBool(firstNonSpace); }
+
+bool Rule::isFirstNonSpace() const
+{ return m_firstNonSpace; }
+
+void Rule::setColumn(const QString &column)
+{
+    bool ok;
+    m_column = column.toInt(&ok);
+    if (!ok)
+        m_column = -1;
+}
+
+int Rule::column() const
+{ return m_column; }
+
+void Rule::addChild(const QSharedPointer<Rule> &rule)
+{ m_childRules.append(rule); }
+
+bool Rule::hasChild() const
+{ return !m_childRules.isEmpty(); }
+
+const QList<QSharedPointer<Rule> > &Rule::childs() const
+{ return m_childRules; }
+
+void Rule::setDefinition(const QSharedPointer<HighlightDefinition> &definition)
+{ m_definition = definition; }
+
+const QSharedPointer<HighlightDefinition> &Rule::definition() const
+{ return m_definition; }
+
+template <class predicate_t>
+bool Rule::predicateMatchSucceed(const QString &text,
+                                 const int length,
+                                 ProgressData *progress,
+                                 const predicate_t &p) const
+{
+    int original = progress->offset();
+    while (progress->offset() < length && p(text.at(progress->offset())))
+        progress->incrementOffset();
+
+    if (original != progress->offset())
+        return true;
+
+    return false;
+}
+
+bool Rule::charPredicateMatchSucceed(const QString &text,
+                                     const int length,
+                                     ProgressData *progress,
+                                     bool (QChar::* predicate)() const) const
+{
+    return predicateMatchSucceed(text, length, progress, std::mem_fun_ref(predicate));
+}
+
+bool Rule::charPredicateMatchSucceed(const QString &text,
+                                     const int length,
+                                     ProgressData *progress,
+                                     bool (*predicate)(const QChar &)) const
+{
+    return predicateMatchSucceed(text, length, progress, std::ptr_fun(predicate));
+}
+
+bool Rule::matchSucceed(const QString &text, const int length, ProgressData *progress) const
+{ 
+    if (m_firstNonSpace && !progress->onlySpacesSoFar())
+        return false;
+
+    if (m_column != -1 && m_column != progress->offset())
+        return false;
+
+    int original = progress->offset();
+    if (doMatchSucceed(text, length, progress)) {
+        if (progress->onlySpacesSoFar() && !m_lookAhead && m_consumesNonSpace)
+            progress->setOnlySpacesSoFar(false);
+
+        if (m_lookAhead)
+            progress->setOffset(original);
+
+        return true;
+    }
+
+    return false;
+}
+
+Rule *Rule::clone() const
+{ return doClone(); }
+
+bool Rule::matchCharacter(const QString &text,
+                          const int length,
+                          ProgressData *progress,
+                          const QChar &c,
+                          bool saveRestoreOffset) const
+{
+    Q_UNUSED(length)
+    Q_ASSERT(progress->offset() < length);
+
+    if (text.at(progress->offset()) == c) {
+        if (saveRestoreOffset)
+            progress->saveOffset();
+        progress->incrementOffset();
+        return true;
+    }
+
+    return false;
+}
+
+bool Rule::matchEscapeSequence(const QString &text,
+                               const int length,
+                               ProgressData *progress,
+                               bool saveRestoreOffset) const
+{
+    if (matchCharacter(text, length, progress, kBackSlash, saveRestoreOffset)) {
+
+        if (progress->offset() < length) {
+            const QChar &c = text.at(progress->offset());
+            if (c == kA || c == kB || c == kE || c == kF || c == kN || c == kR || c == kT ||
+                c == kV || c == kV || c == kQuestion || c == kSingleQuote || c == kQuote ||
+                c == kBackSlash) {
+                progress->incrementOffset();
+                return true;
+            } else if (saveRestoreOffset) {
+                    progress->restoreOffset();
+            }
+        } else if (saveRestoreOffset) {
+            progress->restoreOffset();
+        }
+    }
+
+    return false;
+}
+
+bool Rule::matchOctalSequence(const QString &text,
+                              const int length,
+                              ProgressData *progress,
+                              bool saveRestoreOffset) const
+{
+    // An octal sequence is identified as in the C++ Standard.
+    // octal-escape-sequence:
+    //   \ octal-digit
+    //   \ octal-digit octal-digit
+    //   \ octal-digit octal-digit octal-digit
+
+    if (matchCharacter(text, length, progress, kBackSlash, saveRestoreOffset)) {
+
+        int count = 0;
+        while (progress->offset() < length &&
+               count < 3 &&
+               isOctalDigit(text.at(progress->offset()))) {
+            ++count;
+            progress->incrementOffset();
+        }
+
+        if (count > 0)
+            return true;
+        else if (saveRestoreOffset)
+            progress->restoreOffset();
+    }
+
+    return false;
+}
+
+bool Rule::matchHexSequence(const QString &text,
+                            const int length,
+                            ProgressData *progress,
+                            bool saveRestoreOffset) const
+{
+    // An hex sequence is identified as in the C++ Standard.
+    // hexadecimal-escape-sequence:
+    //   \x hexadecimal-digit
+    //   hexadecimal-escape-sequence hexadecimal-digit
+
+    if (matchCharacter(text, length, progress, kBackSlash, saveRestoreOffset)) {
+
+        if (progress->offset() < length && matchCharacter(text, length, progress, kX, false)) {
+            bool found = false;
+            while (progress->offset() < length && isHexDigit(text.at(progress->offset()))) {
+                if (!found)
+                    found = true;
+                progress->incrementOffset();
+            }
+
+            if (found)
+                return true;
+            else if (saveRestoreOffset)
+                progress->restoreOffset();
+        } else if (saveRestoreOffset) {
+            progress->restoreOffset();
+        }
+    }
+
+    return false;
+}
diff --git a/src/plugins/texteditor/generichighlighter/rule.h b/src/plugins/texteditor/generichighlighter/rule.h
new file mode 100644 (file)
index 0000000..a53b2f8
--- /dev/null
@@ -0,0 +1,160 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef RULE_H
+#define RULE_H
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QSharedPointer>
+
+namespace TextEditor {
+namespace Internal {
+
+class ProgressData;
+class HighlightDefinition;
+
+class Rule
+{
+public:
+    Rule(bool consumesNonSpace = true);
+    virtual ~Rule();
+
+    void setContext(const QString &context);
+    const QString &context() const;
+
+    void setItemData(const QString &itemData);
+    const QString &itemData() const;
+
+    void setBeginRegion(const QString &begin);
+    const QString &beginRegion() const;
+
+    void setEndRegion(const QString &end);
+    const QString &endRegion() const;
+
+    void setLookAhead(const QString &lookAhead);
+    bool isLookAhead() const;
+
+    void setFirstNonSpace(const QString &firstNonSpace);
+    bool isFirstNonSpace() const;
+
+    void setColumn(const QString &column);
+    int column() const;
+
+    void addChild(const QSharedPointer<Rule> &rule);
+    const QList<QSharedPointer<Rule> > &childs() const;
+    bool hasChild() const;
+
+    void setDefinition(const QSharedPointer<HighlightDefinition> &definition);
+    const QSharedPointer<HighlightDefinition> &definition() const;
+
+    bool matchSucceed(const QString &text, const int length, ProgressData *progress) const;
+
+    Rule *clone() const;
+
+protected:
+    bool charPredicateMatchSucceed(const QString &text,
+                                   const int length,
+                                   ProgressData *progress,
+                                   bool (QChar::* predicate)() const) const;
+    bool charPredicateMatchSucceed(const QString &text,
+                                   const int length,
+                                   ProgressData *progress,
+                                   bool (*predicate)(const QChar &)) const;
+
+    bool matchCharacter(const QString &text,
+                        const int length,
+                        ProgressData *progress,
+                        const QChar &c,
+                        bool saveRestoreOffset = true) const;
+    bool matchEscapeSequence(const QString &text,
+                             const int length,
+                             ProgressData *progress,
+                             bool saveRestoreOffset = true) const;
+    bool matchOctalSequence(const QString &text,
+                            const int length,
+                            ProgressData *progress,
+                            bool saveRestoreOffset = true) const;
+    bool matchHexSequence(const QString &text,
+                          const int length,
+                          ProgressData *progress,
+                          bool saveRestoreOffset = true) const;
+
+    static const QLatin1Char kBackSlash;
+    static const QLatin1Char kUnderscore;
+    static const QLatin1Char kDot;
+    static const QLatin1Char kPlus;
+    static const QLatin1Char kMinus;
+    static const QLatin1Char kZero;
+    static const QLatin1Char kQuote;
+    static const QLatin1Char kSingleQuote;
+    static const QLatin1Char kQuestion;
+    static const QLatin1Char kX;
+    static const QLatin1Char kA;
+    static const QLatin1Char kB;
+    static const QLatin1Char kE;
+    static const QLatin1Char kF;
+    static const QLatin1Char kN;
+    static const QLatin1Char kR;
+    static const QLatin1Char kT;
+    static const QLatin1Char kV;    
+
+private:
+    virtual bool doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const = 0;
+
+    virtual Rule *doClone() const = 0;
+
+    template <class predicate_t>
+    bool predicateMatchSucceed(const QString &text,
+                               const int length,
+                               ProgressData *progress,
+                               const predicate_t &p) const;
+
+    QString m_context;
+    QString m_itemData;
+    QString m_beginRegion;
+    QString m_endRegion;
+    bool m_lookAhead;
+    bool m_firstNonSpace;
+    int m_column;
+    bool m_consumesNonSpace;
+
+    QList<QSharedPointer<Rule> > m_childRules;
+
+    // Rules are represented within contexts. However, they have their own definition because
+    // of externally included rules.
+    QSharedPointer<HighlightDefinition> m_definition;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // RULE_H
diff --git a/src/plugins/texteditor/generichighlighter/specificrules.cpp b/src/plugins/texteditor/generichighlighter/specificrules.cpp
new file mode 100644 (file)
index 0000000..6fe4269
--- /dev/null
@@ -0,0 +1,467 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "specificrules.h"
+#include "highlightdefinition.h"
+#include "keywordlist.h"
+#include "progressdata.h"
+#include "reuse.h"
+
+#include <QLatin1Char>
+
+using namespace TextEditor;
+using namespace Internal;
+
+namespace {
+
+void replaceByCaptures(QChar *c, const QStringList &captures)
+{
+    int index = c->digitValue();
+    if (index > 0) {
+        const QString &capture = captures.at(index);
+        *c = capture.at(0);
+    }
+}
+
+void replaceByCaptures(QString *s, const QStringList &captures)
+{
+    static const QLatin1Char kPercent('%');
+
+    int index;
+    int from = 0;
+    while ((index = s->indexOf(kPercent, from)) != -1) {
+        from = index + 1;
+
+        QString accumulator;
+        while (from < s->length() && s->at(from).isDigit()) {
+            accumulator.append(s->at(from));
+            ++from;
+        }
+
+        bool ok;
+        int number = accumulator.toInt(&ok);
+        Q_ASSERT(ok);
+
+        s->replace(index, accumulator.length() + 1, captures.at(number));
+        index = from;
+    }
+}
+}
+
+// DetectChar
+void DetectCharRule::setChar(const QString &character)
+{ setStartCharacter(m_char, character); }
+
+void DetectCharRule::doReplaceExpressions(const QStringList &captures)
+{ replaceByCaptures(&m_char, captures); }
+
+bool DetectCharRule::doMatchSucceed(const QString &text,
+                                    const int length,
+                                    ProgressData *progress) const
+{
+    return matchCharacter(text, length, progress, m_char);
+}
+
+// Detect2Chars
+void Detect2CharsRule::setChar(const QString &character)
+{ setStartCharacter(m_char, character); }
+
+void Detect2CharsRule::setChar1(const QString &character)
+{ setStartCharacter(m_char1, character); }
+
+void Detect2CharsRule::doReplaceExpressions(const QStringList &captures)
+{
+    replaceByCaptures(&m_char, captures);
+    replaceByCaptures(&m_char1, captures);
+}
+
+bool Detect2CharsRule::doMatchSucceed(const QString &text,
+                                      const int length,
+                                      ProgressData *progress) const
+{
+    if (matchCharacter(text, length, progress, m_char)) {
+        if (progress->offset() < length && matchCharacter(text, length, progress, m_char1, false))
+            return true;
+        else
+            progress->restoreOffset();
+    }
+
+    return false;
+}
+
+// AnyChar
+void AnyCharRule::setCharacterSet(const QString &s)
+{ m_characterSet = s; }
+
+bool AnyCharRule::doMatchSucceed(const QString &text,
+                                 const int length,
+                                 ProgressData *progress) const
+{
+    Q_UNUSED(length)
+
+    if (m_characterSet.contains(text.at(progress->offset()))) {
+        progress->incrementOffset();
+        return true;
+    }
+
+    return false;
+}
+
+// StringDetect
+void StringDetectRule::setString(const QString &s)
+{
+    m_string = s;
+    m_length = m_string.length();
+}
+
+void StringDetectRule::setInsensitive(const QString &insensitive)
+{ m_caseSensitivity = toCaseSensitivity(!toBool(insensitive)); }
+
+void StringDetectRule::doReplaceExpressions(const QStringList &captures)
+{ replaceByCaptures(&m_string, captures); }
+
+bool StringDetectRule::doMatchSucceed(const QString &text,
+                                      const int length,
+                                      ProgressData *progress) const
+{
+    if (length - progress->offset() >= m_length) {
+        QString candidate = text.fromRawData(text.unicode() + progress->offset(), m_length);
+        if (candidate.compare(m_string, m_caseSensitivity) == 0) {
+            progress->incrementOffset(m_length);
+            return true;
+        }
+    }
+
+    return false;
+}
+
+// RegExpr
+void RegExprRule::setPattern(const QString &pattern)
+{ m_expression.setPattern(pattern); }
+
+void RegExprRule::setInsensitive(const QString &insensitive)
+{ m_expression.setCaseSensitivity(toCaseSensitivity(!toBool(insensitive))); }
+
+void RegExprRule::setMinimal(const QString &minimal)
+{ m_expression.setMinimal(toBool(minimal)); }
+
+void RegExprRule::doReplaceExpressions(const QStringList &captures)
+{
+    QString s = m_expression.pattern();
+    replaceByCaptures(&s, captures);
+    m_expression.setPattern(s);
+}
+
+bool RegExprRule::doMatchSucceed(const QString &text,
+                                 const int length,
+                                 ProgressData *progress) const
+{
+    Q_UNUSED(length)
+
+    // This is not documented but a regular expression match is considered valid if it starts
+    // at the current position and if the match length is not zero. Checked in Kate's source code
+    // after some unexpected problems.
+    const int offset = progress->offset();
+    if (m_expression.indexIn(text, offset, QRegExp::CaretAtZero) == offset) {
+        if (m_expression.matchedLength() == 0)
+            return false;
+        progress->incrementOffset(m_expression.matchedLength());
+        progress->setCaptures(m_expression.capturedTexts());
+        return true;
+    }
+
+    return false;
+}
+
+// Keyword
+KeywordRule::KeywordRule(const QSharedPointer<HighlightDefinition> &definition) :
+    m_overrideGlobal(false)
+{
+    setDefinition(definition);
+}
+
+KeywordRule::~KeywordRule()
+{}
+
+void KeywordRule::setInsensitive(const QString &insensitive)
+{
+    if (!insensitive.isEmpty()) {
+        m_overrideGlobal = true;
+        m_localCaseSensitivity = toCaseSensitivity(!toBool(insensitive));
+    }
+}
+
+void KeywordRule::setList(const QString &listName)
+{ m_list = definition()->keywordList(listName); }
+
+bool KeywordRule::doMatchSucceed(const QString &text,
+                                 const int length,
+                                 ProgressData *progress) const
+{
+    int current = progress->offset();
+
+    if (current > 0 && !definition()->isDelimiter(text.at(current - 1)))
+        return false;
+    if (definition()->isDelimiter(text.at(current)))
+        return false;
+
+    while (current < length && !definition()->isDelimiter(text.at(current)))
+        ++current;
+
+    QString candidate =
+        QString::fromRawData(text.unicode() + progress->offset(), current - progress->offset());
+    if ((m_overrideGlobal && m_list->isKeyword(candidate, m_localCaseSensitivity)) ||
+        (!m_overrideGlobal && m_list->isKeyword(candidate, definition()->keywordsSensitive()))) {
+        progress->setOffset(current);
+        return true;
+    }
+
+    return false;
+}
+
+// Int
+bool IntRule::doMatchSucceed(const QString &text,
+                             const int length,
+                             ProgressData *progress) const
+{
+    const int offset = progress->offset();
+
+    // This is necessary to correctly highlight an invalid octal like 09, for example.
+    if (offset > 0 && text.at(offset - 1).isDigit())
+        return false;
+
+    if (text.at(offset).isDigit() && text.at(offset) != kZero) {
+        progress->incrementOffset();
+        charPredicateMatchSucceed(text, length, progress, &QChar::isDigit);
+        return true;
+    }
+
+    return false;
+}
+
+// Float
+bool FloatRule::doMatchSucceed(const QString &text, const int length, ProgressData *progress) const
+{
+    progress->saveOffset();
+
+    bool integralPart = charPredicateMatchSucceed(text, length, progress, &QChar::isDigit);
+
+    bool decimalPoint = false;
+    if (progress->offset() < length && text.at(progress->offset()) == kDot) {
+        progress->incrementOffset();
+        decimalPoint = true;
+    }
+
+    bool fractionalPart = charPredicateMatchSucceed(text, length, progress, &QChar::isDigit);
+
+    bool exponentialPart = false;
+    int offset = progress->offset();
+    if (offset < length && (text.at(offset) == kE || text.at(offset).toLower() == kE)) {
+        progress->incrementOffset();
+
+        offset = progress->offset();
+        if (offset < length && (text.at(offset) == kPlus || text.at(offset) == kMinus))
+            progress->incrementOffset();
+
+        if (charPredicateMatchSucceed(text, length, progress, &QChar::isDigit)) {
+            exponentialPart = true;
+        } else {
+            progress->restoreOffset();
+            return false;
+        }
+    }
+
+    if ((integralPart || fractionalPart) && (decimalPoint || exponentialPart))
+        return true;
+
+    progress->restoreOffset();
+    return false;
+}
+
+// COctal
+bool HlCOctRule::doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const
+{
+    if (matchCharacter(text, length, progress, kZero)) {
+        // In the definition files the number matching rules which are more restrictive should
+        // appear before the rules which are least resctritive. Although this happens in general
+        // there is at least one case where this is not strictly followed for existent definition
+        // files (specifically, HlCHex comes before HlCOct). So the condition below.
+        const int offset = progress->offset();
+        if (offset < length && (text.at(offset) == kX || text.at(offset).toLower() == kX)) {
+            progress->restoreOffset();
+            return false;
+        }
+
+        charPredicateMatchSucceed(text, length, progress, &isOctalDigit);
+        return true;
+    }
+
+    return false;
+}
+
+// CHex
+bool HlCHexRule::doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const
+{
+    if (matchCharacter(text, length, progress, kZero)) {
+        const int offset = progress->offset();
+        if (offset < length && text.at(offset) != kX && text.at(offset).toLower() != kX) {
+            progress->restoreOffset();
+            return false;
+        }
+
+        progress->incrementOffset();
+        if (charPredicateMatchSucceed(text, length, progress, &isHexDigit))
+            return true;
+        else
+            progress->restoreOffset();
+    }
+
+    return false;
+}
+
+// CString
+bool HlCStringCharRule::doMatchSucceed(const QString &text,
+                                       const int length,
+                                       ProgressData *progress) const
+{
+    if (matchEscapeSequence(text, length, progress))
+        return true;
+
+    if (matchOctalSequence(text, length, progress))
+        return true;
+
+    if (matchHexSequence(text, length, progress))
+        return true;
+
+    return false;
+}
+
+// CChar
+bool HlCCharRule::doMatchSucceed(const QString &text,
+                                 const int length,
+                                 ProgressData *progress) const
+{
+    if (matchCharacter(text, length, progress, kSingleQuote)) {
+        if (progress->offset() < length) {
+            if (text.at(progress->offset()) != kBackSlash &&
+                text.at(progress->offset()) != kSingleQuote) {
+                progress->incrementOffset();
+            } else if (!matchEscapeSequence(text, length, progress, false)) {
+                progress->restoreOffset();
+                return false;
+            }
+
+            if (progress->offset() < length &&
+                matchCharacter(text, length, progress, kSingleQuote, false)) {
+                return true;
+            } else {
+                progress->restoreOffset();
+            }
+        } else {
+            progress->restoreOffset();
+        }
+    }
+
+    return false;
+}
+
+// RangeDetect
+void RangeDetectRule::setChar(const QString &character)
+{ setStartCharacter(m_char, character); }
+
+void RangeDetectRule::setChar1(const QString &character)
+{ setStartCharacter(m_char1, character); }
+
+bool RangeDetectRule::doMatchSucceed(const QString &text,
+                                     const int length,
+                                     ProgressData *progress) const
+{
+    if (matchCharacter(text, length, progress, m_char)) {
+        while (progress->offset() < length) {
+            if (matchCharacter(text, length, progress, m_char1, false))
+                return true;
+            progress->incrementOffset();
+        }
+        progress->restoreOffset();
+    }
+
+    return false;
+}
+
+// LineContinue
+bool LineContinueRule::doMatchSucceed(const QString &text,
+                                      const int length,
+                                      ProgressData *progress) const
+{
+    if (progress->offset() != length - 1)
+        return false;
+
+    if (text.at(progress->offset()) == kBackSlash) {
+        progress->setWillContinueLine(true);
+        return true;
+    }
+
+    return false;
+}
+
+// DetectSpaces
+DetectSpacesRule::DetectSpacesRule() : Rule(false)
+{}
+
+bool DetectSpacesRule::doMatchSucceed(const QString &text,
+                                      const int length,
+                                      ProgressData *progress) const
+{
+    return charPredicateMatchSucceed(text, length, progress, &QChar::isSpace);
+}
+
+// DetectIdentifier
+bool DetectIdentifierRule::doMatchSucceed(const QString &text,
+                                          const int length,
+                                          ProgressData *progress) const
+{
+    // Identifiers are characterized by a letter or underscore as the first character and then
+    // zero or more word characters (\w*).
+    if (text.at(progress->offset()).isLetter() || text.at(progress->offset()) == kUnderscore) {
+        progress->incrementOffset();
+        while (progress->offset() < length) {
+            const QChar &current = text.at(progress->offset());
+            if (current.isLetterOrNumber() || current.isMark() || current == kUnderscore)
+                progress->incrementOffset();
+            else
+                break;
+        }
+        return true;
+    }
+    return false;
+}
diff --git a/src/plugins/texteditor/generichighlighter/specificrules.h b/src/plugins/texteditor/generichighlighter/specificrules.h
new file mode 100644 (file)
index 0000000..7ec2552
--- /dev/null
@@ -0,0 +1,288 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef SPECIFICRULES_H
+#define SPECIFICRULES_H
+
+#include "rule.h"
+#include "dynamicrule.h"
+
+#include <QtCore/QChar>
+#include <QtCore/QString>
+#include <QtCore/QRegExp>
+#include <QtCore/QSharedPointer>
+
+namespace TextEditor {
+namespace Internal {
+
+class KeywordList;
+class HighlightDefinition;
+
+class DetectCharRule : public DynamicRule
+{
+public:
+    virtual ~DetectCharRule() {}
+
+    void setChar(const QString &character);
+
+private:
+    virtual bool doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const;
+    virtual DetectCharRule *doClone() const { return new DetectCharRule(*this); }
+    virtual void doReplaceExpressions(const QStringList &captures);
+
+    QChar m_char;
+};
+
+class Detect2CharsRule : public DynamicRule
+{
+public:
+    virtual ~Detect2CharsRule() {}
+
+    void setChar(const QString &character);
+    void setChar1(const QString &character);    
+
+private:
+    virtual bool doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const;
+    virtual Detect2CharsRule *doClone() const { return new Detect2CharsRule(*this); }
+    virtual void doReplaceExpressions(const QStringList &captures);
+
+    QChar m_char;
+    QChar m_char1;
+};
+
+class AnyCharRule : public Rule
+{
+public:
+    virtual ~AnyCharRule() {}
+
+    void setCharacterSet(const QString &s);
+
+private:
+    virtual bool doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const;
+    virtual AnyCharRule *doClone() const { return new AnyCharRule(*this); }
+
+    QString m_characterSet;
+};
+
+class StringDetectRule : public DynamicRule
+{
+public:
+    virtual ~StringDetectRule() {}
+
+    void setString(const QString &s);
+    void setInsensitive(const QString &insensitive);
+
+private:
+    virtual bool doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const;
+    virtual StringDetectRule *doClone() const { return new StringDetectRule(*this); }
+    virtual void doReplaceExpressions(const QStringList &captures);
+
+    QString m_string;
+    int m_length;
+    Qt::CaseSensitivity m_caseSensitivity;
+};
+
+class RegExprRule : public DynamicRule
+{
+public:
+    virtual ~RegExprRule() {}
+
+    void setPattern(const QString &pattern);
+    void setInsensitive(const QString &insensitive);
+    void setMinimal(const QString &minimal);    
+
+private:
+    virtual bool doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const;
+    virtual RegExprRule *doClone() const { return new RegExprRule(*this); }
+    virtual void doReplaceExpressions(const QStringList &captures);
+
+    QRegExp m_expression;
+};
+
+class KeywordRule : public Rule
+{
+public:
+    KeywordRule(const QSharedPointer<HighlightDefinition> &definition);
+    virtual ~KeywordRule();
+
+    void setInsensitive(const QString &insensitive);
+    void setList(const QString &listName);
+
+private:
+    virtual bool doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const;
+    virtual KeywordRule *doClone() const { return new KeywordRule(*this); }
+
+    bool m_overrideGlobal;
+    Qt::CaseSensitivity m_localCaseSensitivity;
+    QSharedPointer<KeywordList> m_list;
+};
+
+class IntRule : public Rule
+{
+public:
+    virtual ~IntRule() {}
+
+private:
+    virtual bool doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const;
+    virtual IntRule *doClone() const { return new IntRule(*this); }
+};
+
+class FloatRule : public Rule
+{
+public:
+    virtual ~FloatRule() {}
+
+private:
+    virtual bool doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const;
+    virtual FloatRule *doClone() const { return new FloatRule(*this); }
+};
+
+class HlCOctRule : public Rule
+{
+public:
+    virtual ~HlCOctRule() {}
+
+private:
+    virtual bool doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const;
+    virtual HlCOctRule *doClone() const { return new HlCOctRule(*this); }
+};
+
+class HlCHexRule : public Rule
+{
+public:
+    virtual ~HlCHexRule() {}
+
+private:
+    virtual bool doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const;
+    virtual HlCHexRule *doClone() const { return new HlCHexRule(*this); }
+};
+
+class HlCStringCharRule : public Rule
+{
+public:
+    virtual ~HlCStringCharRule() {}
+
+private:
+    virtual bool doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const;
+    virtual HlCStringCharRule *doClone() const { return new HlCStringCharRule(*this); }
+};
+
+class HlCCharRule : public Rule
+{
+public:
+    virtual ~HlCCharRule() {}
+
+private:
+    virtual bool doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const;
+    virtual HlCCharRule *doClone() const { return new HlCCharRule(*this); }
+};
+
+class RangeDetectRule : public Rule
+{
+public:
+    virtual ~RangeDetectRule() {}
+
+    void setChar(const QString &character);
+    void setChar1(const QString &character);
+
+private:
+    virtual bool doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const;
+    virtual RangeDetectRule *doClone() const { return new RangeDetectRule(*this); }
+
+    QChar m_char;
+    QChar m_char1;
+};
+
+class LineContinueRule : public Rule
+{
+public:
+    virtual ~LineContinueRule() {}
+
+private:
+    virtual bool doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const;
+    virtual LineContinueRule *doClone() const { return new LineContinueRule(*this); }
+};
+
+class DetectSpacesRule : public Rule
+{
+public:
+    DetectSpacesRule();
+    virtual ~DetectSpacesRule() {}
+
+private:
+    virtual bool doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const;
+    virtual DetectSpacesRule *doClone() const { return new DetectSpacesRule(*this); }
+};
+
+class DetectIdentifierRule : public Rule
+{
+public:
+    virtual ~DetectIdentifierRule() {}
+
+private:
+    virtual bool doMatchSucceed(const QString &text,
+                                const int length,
+                                ProgressData *progress) const;
+    virtual DetectIdentifierRule *doClone() const { return new DetectIdentifierRule(*this); }
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // SPECIFICRULES_H
diff --git a/src/plugins/texteditor/indenter.cpp b/src/plugins/texteditor/indenter.cpp
new file mode 100644 (file)
index 0000000..ee2edc6
--- /dev/null
@@ -0,0 +1,47 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "indenter.h"
+#include "tabsettings.h"
+
+using namespace TextEditor;
+
+Indenter::Indenter()
+{}
+
+Indenter::~Indenter()
+{}
+
+void Indenter::indentBlock(QTextDocument *doc,
+                           QTextBlock block,
+                           QChar typedChar,
+                           const TabSettings &ts)
+{
+    doIndentBlock(doc, block, typedChar, ts);
+}
diff --git a/src/plugins/texteditor/indenter.h b/src/plugins/texteditor/indenter.h
new file mode 100644 (file)
index 0000000..c6aff2a
--- /dev/null
@@ -0,0 +1,63 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef INDENTER_H
+#define INDENTER_H
+
+#include "texteditor_global.h"
+
+#include <QtCore/QChar>
+#include <QtGui/QTextBlock>
+
+QT_BEGIN_NAMESPACE
+class QTextDocument;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+
+struct TabSettings;
+
+class TEXTEDITOR_EXPORT Indenter
+{
+public:
+    Indenter();
+    virtual ~Indenter();
+
+    void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar, const TabSettings &ts);
+
+private:
+    virtual void doIndentBlock(QTextDocument *doc,
+                               QTextBlock block,
+                               QChar typedChar,
+                               const TabSettings &ts) = 0;
+};
+
+} // namespace TextEditor
+
+#endif // INDENTER_H
diff --git a/src/plugins/texteditor/normalindenter.cpp b/src/plugins/texteditor/normalindenter.cpp
new file mode 100644 (file)
index 0000000..7a6eb13
--- /dev/null
@@ -0,0 +1,89 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "normalindenter.h"
+#include "tabsettings.h"
+
+#include <QtGui/QTextDocument>
+
+using namespace TextEditor;
+
+NormalIndenter::NormalIndenter()
+{}
+
+NormalIndenter::~NormalIndenter()
+{}
+
+// Indent a text block based on previous line.
+// Simple text paragraph layout:
+// aaaa aaaa
+//
+//   bbb bb
+//   bbb bb
+//
+//  - list
+//    list line2
+//
+//  - listn
+//
+// ccc
+//
+// @todo{Add formatting to wrap paragraphs. This requires some
+// hoops as the current indentation routines are not prepared
+// for additional block being inserted. It might be possible
+// to do in 2 steps (indenting/wrapping)}
+//
+void NormalIndenter::doIndentBlock(QTextDocument *doc,
+                                   QTextBlock block,
+                                   QChar typedChar,
+                                   const TextEditor::TabSettings &ts)
+{
+    Q_UNUSED(typedChar)
+
+    // At beginning: Leave as is.
+    if (block == doc->begin())
+        return;
+
+    const QTextBlock previous = block.previous();
+    const QString previousText = previous.text();
+    // Empty line indicates a start of a new paragraph. Leave as is.
+    if (previousText.isEmpty() || previousText.trimmed().isEmpty())
+        return;
+
+    // Just use previous line.
+    // Skip blank characters when determining the indentation
+    int i = 0;
+    while (i < previousText.size()) {
+        if (!previousText.at(i).isSpace()) {
+            ts.indentLine(block, ts.columnAt(previousText, i));
+            break;
+        }
+        ++i;
+    }
+}
diff --git a/src/plugins/texteditor/normalindenter.h b/src/plugins/texteditor/normalindenter.h
new file mode 100644 (file)
index 0000000..7014f9c
--- /dev/null
@@ -0,0 +1,52 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef NORMALINDENTER_H
+#define NORMALINDENTER_H
+
+#include "indenter.h"
+
+namespace TextEditor {
+
+class TEXTEDITOR_EXPORT NormalIndenter : public Indenter
+{
+public:
+    NormalIndenter();
+    virtual ~NormalIndenter();
+
+private:
+    virtual void doIndentBlock(QTextDocument *doc,
+                               QTextBlock block,
+                               QChar typedChar,
+                               const TabSettings &ts);
+};
+
+} // namespace TextEditor
+
+#endif // NORMALINDENTER_H
index 5fdd113..2c748b0 100644 (file)
 #include "tabsettings.h"
 #include "texteditorconstants.h"
 #include "texteditorplugin.h"
+#include "texteditorsettings.h"
+#include "basetextdocument.h"
+#include "highlightdefinition.h"
+#include "highlighter.h"
+#include "highlighterexception.h"
+#include "manager.h"
 
 #include <coreplugin/coreconstants.h>
 #include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/mimedatabase.h>
+
+#include <QtCore/QSharedPointer>
+#include <QtCore/QFileInfo>
 
 using namespace TextEditor;
 using namespace TextEditor::Internal;
@@ -54,8 +65,11 @@ PlainTextEditor::PlainTextEditor(QWidget *parent)
     setRequestMarkEnabled(false);
     setLineSeparatorsAllowed(true);
 
-    setMimeType(QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_TEXT));
     setDisplayName(tr(Core::Constants::K_DEFAULT_TEXT_EDITOR_DISPLAY_NAME));
+
+    m_commentDefinition.clearCommentStyles();
+
+    connect(file(), SIGNAL(changed()), this, SLOT(configure()));
 }
 
 QList<int> PlainTextEditorEditable::context() const
@@ -76,49 +90,56 @@ QString PlainTextEditorEditable::id() const
     return QLatin1String(Core::Constants::K_DEFAULT_TEXT_EDITOR_ID);
 }
 
-// Indent a text block based on previous line.
-// Simple text paragraph layout:
-// aaaa aaaa
-//
-//   bbb bb
-//   bbb bb
-//
-//  - list
-//    list line2
-//
-//  - listn
-//
-// ccc
-//
-// @todo{Add formatting to wrap paragraphs. This requires some
-// hoops as the current indentation routines are not prepared
-// for additional block being inserted. It might be possible
-// to do in 2 steps (indenting/wrapping)}
-//
+void PlainTextEditor::unCommentSelection()
+{
+    Utils::unCommentSelection(this, m_commentDefinition);
+}
 
-void PlainTextEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar)
+void PlainTextEditor::setFontSettings(const TextEditor::FontSettings & fs)
 {
-    Q_UNUSED(typedChar)
+    TextEditor::BaseTextEditor::setFontSettings(fs);
 
-    // At beginning: Leave as is.
-    if (block == doc->begin())
+    Highlighter *highlighter = static_cast<Highlighter *>(baseTextDocument()->syntaxHighlighter());
+    if (!highlighter)
         return;
 
-    const QTextBlock previous = block.previous();
-    const QString previousText = previous.text();
-    // Empty line indicates a start of a new paragraph. Leave as is.
-    if (previousText.isEmpty() || previousText.trimmed().isEmpty())
-        return;
+    highlighter->configureFormats(fs);
+    highlighter->rehighlight();
+}
+
+void PlainTextEditor::configure()
+{
+    const QString &mimeType = Core::ICore::instance()->mimeDatabase()->findByFile(
+            QFileInfo(file()->fileName())).type();
+    baseTextDocument()->setMimeType(mimeType);
+
+    const QString &definitionId = Manager::instance()->definitionIdByMimeType(mimeType);
+    if (!definitionId.isEmpty()) {
+        try {
+            const QSharedPointer<HighlightDefinition> &definition =
+                    Manager::instance()->definition(definitionId);
+
+            Highlighter *highlighter = new Highlighter(definition->initialContext());
+            highlighter->configureFormats(TextEditor::TextEditorSettings::instance()->fontSettings());
 
-    // Just use previous line.
-    // Skip blank characters when determining the indentation
-    int i = 0;
-    while (i < previousText.size()) {
-        if (!previousText.at(i).isSpace()) {
-            const TextEditor::TabSettings &ts = tabSettings();
-            ts.indentLine(block, ts.columnAt(previousText, i));
-            break;
+            baseTextDocument()->setSyntaxHighlighter(highlighter);
+
+            m_commentDefinition.setAfterWhiteSpaces(definition->isCommentAfterWhiteSpaces());
+            m_commentDefinition.setSingleLine(definition->singleLineComment());
+            m_commentDefinition.setMultiLineStart(definition->multiLineCommentStart());
+            m_commentDefinition.setMultiLineEnd(definition->multiLineCommentEnd());
+        } catch (const HighlighterException &) {
         }
-        ++i;
     }
+
+    // @todo: Indentation specification through the definition files is not really being
+    // used because Kate recommends to configure indentation  through another feature.
+    // Maybe we should provide something similar in Creator? For now, only normal
+    // indentation is supported.
+    m_indenter.reset(new TextEditor::NormalIndenter);
+}
+
+void PlainTextEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar)
+{
+    m_indenter->indentBlock(doc, block, typedChar, tabSettings());
 }
index 181d4c4..fdc8542 100644 (file)
 #define PLAINTEXTEDITOR_H
 
 #include "basetexteditor.h"
+#include "normalindenter.h"
+
+#include <utils/uncommentselection.h>
 
 #include <QtCore/QList>
+#include <QtCore/QScopedPointer>
 
 namespace TextEditor {
 
@@ -60,10 +64,20 @@ class TEXTEDITOR_EXPORT PlainTextEditor : public BaseTextEditor
 public:
     PlainTextEditor(QWidget *parent);
 
+public slots:
+    virtual void unCommentSelection();
+    virtual void setFontSettings(const TextEditor::FontSettings &);
+
+private slots:
+    void configure();
+
 protected:
-    virtual BaseTextEditorEditable *createEditableInterface() { return new PlainTextEditorEditable(this); }
-    // Indent a text block based on previous line.
+    virtual BaseTextEditorEditable *createEditableInterface() { return new PlainTextEditorEditable(this); }    
     virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
+
+private:
+    Utils::CommentDefinition m_commentDefinition;
+    QScopedPointer<TextEditor::Indenter> m_indenter;
 };
 
 } // namespace TextEditor
index 5dc62f4..7a21997 100644 (file)
@@ -44,9 +44,9 @@ PlainTextEditorFactory::PlainTextEditorFactory(QObject *parent)
 {
     m_actionHandler = new TextEditorActionHandler(
         QLatin1String(TextEditor::Constants::C_TEXTEDITOR),
-        TextEditorActionHandler::Format);
-    m_mimeTypes << QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_TEXT)
-                << QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_XML);
+        TextEditorActionHandler::Format |
+        TextEditorActionHandler::UnCommentSelection);
+    m_mimeTypes << QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_TEXT);
 }
 
 PlainTextEditorFactory::~PlainTextEditorFactory()
@@ -77,6 +77,11 @@ Core::IEditor *PlainTextEditorFactory::createEditor(QWidget *parent)
     return rc->editableInterface();
 }
 
+void PlainTextEditorFactory::addMimeType(const QString &type)
+{
+    m_mimeTypes.append(type);
+}
+
 QStringList PlainTextEditorFactory::mimeTypes() const
 {
     return m_mimeTypes;
index d55f480..a01a80f 100644 (file)
@@ -50,6 +50,7 @@ public:
     PlainTextEditorFactory(QObject *parent = 0);
     virtual ~PlainTextEditorFactory();
 
+    void addMimeType(const QString &type);
     virtual QStringList mimeTypes() const;
     //Core::IEditorFactory
     QString id() const;
index a27f857..4892ff2 100644 (file)
@@ -1,8 +1,11 @@
 TEMPLATE = lib
 TARGET = TextEditor
 DEFINES += TEXTEDITOR_LIBRARY
+QT += xml
 include(../../qtcreatorplugin.pri)
 include(texteditor_dependencies.pri)
+INCLUDEPATH += generichighlighter
+DEPENDPATH += generichighlighter
 SOURCES += texteditorplugin.cpp \
     textfilewizard.cpp \
     plaintexteditor.cpp \
@@ -35,7 +38,21 @@ SOURCES += texteditorplugin.cpp \
     texteditoroverlay.cpp \
     texteditoroptionspage.cpp \
     basetextdocumentlayout.cpp \
-    completionsettings.cpp
+    completionsettings.cpp \
+    normalindenter.cpp \
+    indenter.cpp \
+    generichighlighter/itemdata.cpp \
+    generichighlighter/specificrules.cpp \
+    generichighlighter/rule.cpp \
+    generichighlighter/dynamicrule.cpp \
+    generichighlighter/context.cpp \
+    generichighlighter/includerulesinstruction.cpp \
+    generichighlighter/progressdata.cpp \
+    generichighlighter/keywordlist.cpp \
+    generichighlighter/highlightdefinition.cpp \
+    generichighlighter/highlighter.cpp \
+    generichighlighter/manager.cpp \
+    generichighlighter/highlightdefinitionhandler.cpp
 
 HEADERS += texteditorplugin.h \
     textfilewizard.h \
@@ -73,7 +90,24 @@ HEADERS += texteditorplugin.h \
     texteditoroverlay.h \
     texteditoroptionspage.h \
     basetextdocumentlayout.h \
-    completionsettings.h
+    completionsettings.h \
+    normalindenter.h \
+    indenter.h \
+    generichighlighter/reuse.h \
+    generichighlighter/itemdata.h \
+    generichighlighter/specificrules.h \
+    generichighlighter/rule.h \
+    generichighlighter/reuse.h \
+    generichighlighter/dynamicrule.h \
+    generichighlighter/context.h \
+    generichighlighter/includerulesinstruction.h \
+    generichighlighter/progressdata.h \
+    generichighlighter/keywordlist.h \
+    generichighlighter/highlighterexception.h \
+    generichighlighter/highlightdefinition.h \
+    generichighlighter/highlighter.h \
+    generichighlighter/manager.h \
+    generichighlighter/highlightdefinitionhandler.h
 
 
 FORMS += behaviorsettingspage.ui \
index 81ab291..6043191 100644 (file)
@@ -69,9 +69,9 @@ TextEditorActionHandler::TextEditorActionHandler(const QString &context,
     m_cleanWhitespaceAction(0),
     m_textWrappingAction(0),
     m_unCommentSelectionAction(0),
-    m_unCollapseAllAction(0),
-    m_collapseAction(0),
-    m_expandAction(0),
+    m_unfoldAllAction(0),
+    m_foldAction(0),
+    m_unfoldAction(0),
     m_cutLineAction(0),
     m_deleteLineAction(0),
     m_selectEncodingAction(0),
@@ -198,21 +198,21 @@ void TextEditorActionHandler::createActions()
     command = am->registerAction(m_deleteLineAction, Constants::DELETE_LINE, m_contextId);
     connect(m_deleteLineAction, SIGNAL(triggered()), this, SLOT(deleteLine()));
 
-    m_collapseAction = new QAction(tr("Collapse"), this);
-    command = am->registerAction(m_collapseAction, Constants::COLLAPSE, m_contextId);
+    m_foldAction = new QAction(tr("Fold"), this);
+    command = am->registerAction(m_foldAction, Constants::FOLD, m_contextId);
     command->setDefaultKeySequence(QKeySequence(tr("Ctrl+<")));
-    connect(m_collapseAction, SIGNAL(triggered()), this, SLOT(collapse()));
+    connect(m_foldAction, SIGNAL(triggered()), this, SLOT(fold()));
     advancedMenu->addAction(command, Core::Constants::G_EDIT_COLLAPSING);
 
-    m_expandAction = new QAction(tr("Expand"), this);
-    command = am->registerAction(m_expandAction, Constants::EXPAND, m_contextId);
+    m_unfoldAction = new QAction(tr("Unfold"), this);
+    command = am->registerAction(m_unfoldAction, Constants::UNFOLD, m_contextId);
     command->setDefaultKeySequence(QKeySequence(tr("Ctrl+>")));
-    connect(m_expandAction, SIGNAL(triggered()), this, SLOT(expand()));
+    connect(m_unfoldAction, SIGNAL(triggered()), this, SLOT(unfold()));
     advancedMenu->addAction(command, Core::Constants::G_EDIT_COLLAPSING);
 
-    m_unCollapseAllAction = new QAction(tr("(Un)&Collapse All"), this);
-    command = am->registerAction(m_unCollapseAllAction, Constants::UN_COLLAPSE_ALL, m_contextId);
-    connect(m_unCollapseAllAction, SIGNAL(triggered()), this, SLOT(unCollapseAll()));
+    m_unfoldAllAction = new QAction(tr("(Un)&Collapse All"), this);
+    command = am->registerAction(m_unfoldAllAction, Constants::UNFOLD_ALL, m_contextId);
+    connect(m_unfoldAllAction, SIGNAL(triggered()), this, SLOT(unfoldAll()));
     advancedMenu->addAction(command, Core::Constants::G_EDIT_COLLAPSING);
 
     m_increaseFontSizeAction = new QAction(tr("Increase Font Size"), this);
@@ -293,6 +293,15 @@ void TextEditorActionHandler::createActions()
     command->setDefaultKeySequence(QKeySequence(tr("Ctrl+J")));
     connect(m_joinLinesAction, SIGNAL(triggered()), this, SLOT(joinLines()));
 
+    m_insertLineAboveAction = new QAction(tr("Insert Line Above Current Line"), this);
+    command = am->registerAction(m_insertLineAboveAction, Constants::INSERT_LINE_ABOVE, m_contextId);
+    command->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+Return")));
+    connect(m_insertLineAboveAction, SIGNAL(triggered()), this, SLOT(insertLineAbove()));
+
+    m_insertLineBelowAction = new QAction(tr("Insert Line Below Current Line"), this);
+    command = am->registerAction(m_insertLineBelowAction, Constants::INSERT_LINE_BELOW, m_contextId);
+    command->setDefaultKeySequence(QKeySequence(tr("Ctrl+Return")));
+    connect(m_insertLineBelowAction, SIGNAL(triggered()), this, SLOT(insertLineBelow()));
 
     QAction *a = 0;
     a = new QAction(tr("Goto Line Start"), this);
@@ -397,7 +406,7 @@ void TextEditorActionHandler::updateActions(UpdateMode um)
     m_moveLineDownAction->setEnabled(um != ReadOnlyMode);
 
     m_formatAction->setEnabled((m_optionalActions & Format));
-    m_unCollapseAllAction->setEnabled((m_optionalActions & UnCollapseAll));
+    m_unfoldAllAction->setEnabled((m_optionalActions & UnCollapseAll));
     m_visualizeWhitespaceAction->setChecked(m_currentEditor->displaySettings().m_visualizeWhitespace);
     if (m_textWrappingAction) {
         m_textWrappingAction->setChecked(m_currentEditor->displaySettings().m_textWrapping);
@@ -489,9 +498,9 @@ FUNCTION(cleanWhitespace)
 FUNCTION(unCommentSelection)
 FUNCTION(cutLine)
 FUNCTION(deleteLine)
-FUNCTION(unCollapseAll)
-FUNCTION(collapse)
-FUNCTION(expand)
+FUNCTION(unfoldAll)
+FUNCTION(fold)
+FUNCTION(unfold)
 FUNCTION2(increaseFontSize, zoomIn)
 FUNCTION2(decreaseFontSize, zoomOut)
 FUNCTION2(resetFontSize, zoomReset)
@@ -507,6 +516,8 @@ FUNCTION(moveLineDown)
 FUNCTION(copyLineUp)
 FUNCTION(copyLineDown)
 FUNCTION(joinLines)
+FUNCTION(insertLineAbove)
+FUNCTION(insertLineBelow)
 
 FUNCTION(gotoLineStart)
 FUNCTION(gotoLineStartWithSelection)
index 667ce57..331c788 100644 (file)
@@ -96,9 +96,9 @@ private slots:
     void cleanWhitespace();
     void setTextWrapping(bool);
     void unCommentSelection();
-    void unCollapseAll();
-    void collapse();
-    void expand();
+    void unfoldAll();
+    void fold();
+    void unfold();
     void cutLine();
     void deleteLine();
     void selectEncoding();
@@ -116,6 +116,8 @@ private slots:
     void copyLineUp();
     void copyLineDown();
     void joinLines();
+    void insertLineAbove();
+    void insertLineBelow();
     void updateCurrentEditor(Core::IEditor *editor);
 
     void gotoLineStart();
@@ -151,9 +153,9 @@ private:
     QAction *m_cleanWhitespaceAction;
     QAction *m_textWrappingAction;
     QAction *m_unCommentSelectionAction;
-    QAction *m_unCollapseAllAction;
-    QAction *m_collapseAction;
-    QAction *m_expandAction;
+    QAction *m_unfoldAllAction;
+    QAction *m_foldAction;
+    QAction *m_unfoldAction;
     QAction *m_cutLineAction;
     QAction *m_deleteLineAction;
     QAction *m_selectEncodingAction;
@@ -171,6 +173,8 @@ private:
     QAction *m_copyLineUpAction;
     QAction *m_copyLineDownAction;
     QAction *m_joinLinesAction;
+    QAction *m_insertLineAboveAction;
+    QAction *m_insertLineBelowAction;
 
     uint m_optionalActions;
     QPointer<BaseTextEditor> m_currentEditor;
index b0af1e7..d4e4650 100644 (file)
@@ -43,9 +43,9 @@ const char * const CLEAN_WHITESPACE      = "TextEditor.CleanWhitespace";
 const char * const TEXT_WRAPPING         = "TextEditor.TextWrapping";
 const char * const UN_COMMENT_SELECTION  = "TextEditor.UnCommentSelection";
 const char * const REFORMAT              = "TextEditor.Reformat";
-const char * const COLLAPSE              = "TextEditor.Collapse";
-const char * const EXPAND                = "TextEditor.Expand";
-const char * const UN_COLLAPSE_ALL       = "TextEditor.UnCollapseAll";
+const char * const FOLD              = "TextEditor.Fold";
+const char * const UNFOLD                = "TextEditor.Unfold";
+const char * const UNFOLD_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";
@@ -61,6 +61,8 @@ const char * const MOVE_LINE_DOWN        = "TextEditor.MoveLineDown";
 const char * const COPY_LINE_UP          = "TextEditor.CopyLineUp";
 const char * const COPY_LINE_DOWN        = "TextEditor.CopyLineDown";
 const char * const JOIN_LINES            = "TextEditor.JoinLines";
+const char * const INSERT_LINE_ABOVE     = "TextEditor.InsertLineAboveCurrentLine";
+const char * const INSERT_LINE_BELOW     = "TextEditor.InsertLineBelowCurrentLine";
 const char * const CUT_LINE              = "TextEditor.CutLine";
 const char * const DELETE_LINE           = "TextEditor.DeleteLine";
 const char * const DELETE_WORD           = "TextEditor.DeleteWord";
@@ -85,7 +87,6 @@ const char * const GOTO_NEXT_CHARACTER_WITH_SELECTION = "TextEditor.GotoNextChar
 const char * const GOTO_PREVIOUS_WORD_WITH_SELECTION = "TextEditor.GotoPreviousWordWithSelection";
 const char * const GOTO_NEXT_WORD_WITH_SELECTION = "TextEditor.GotoNextWordWithSelection";
 const char * const C_TEXTEDITOR_MIMETYPE_TEXT = "text/plain";
-const char * const C_TEXTEDITOR_MIMETYPE_XML = "application/xml";
 
 
 // Text color and style categories
index dca81be..058fcd6 100644 (file)
@@ -39,6 +39,7 @@
 #include "plaintexteditorfactory.h"
 #include "plaintexteditor.h"
 #include "storagesettings.h"
+#include "manager.h"
 
 #include <coreplugin/icore.h>
 #include <coreplugin/coreconstants.h>
@@ -70,6 +71,9 @@ TextEditorPlugin::TextEditorPlugin()
 {
     QTC_ASSERT(!m_instance, return);
     m_instance = this;
+
+    connect(Core::ICore::instance(), SIGNAL(coreOpened()),
+            Manager::instance(), SLOT(registerMimeTypes()));
 }
 
 TextEditorPlugin::~TextEditorPlugin()
index 1fc4c10..93f8870 100644 (file)
@@ -64,6 +64,7 @@ public:
 
     void initializeEditor(PlainTextEditor *editor);
 
+    PlainTextEditorFactory *editorFactory() { return m_editorFactory; }
     LineNumberFilter *lineNumberFilter() { return m_lineNumberFilter; }
 
 private slots:
index c5ec96a..5ac48de 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="VCSBase" version="1.3.84" compatVersion="1.3.84">
+<plugin name="VCSBase" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,8 +14,8 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Version Control System Base Plugin</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="Core" version="1.3.84"/>
-        <dependency name="TextEditor" version="1.3.84"/>
-        <dependency name="ProjectExplorer" version="1.3.84"/>
+        <dependency name="Core" version="2.0.80"/>
+        <dependency name="TextEditor" version="2.0.80"/>
+        <dependency name="ProjectExplorer" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 949e30c..01eb9dc 100644 (file)
@@ -39,6 +39,13 @@ SubmitEditorFile::SubmitEditorFile(const QString &mimeType, QObject *parent) :
 {
 }
 
+void SubmitEditorFile::rename(const QString &newName)
+{
+    Q_UNUSED(newName);
+    // We can't be renamed
+    return;
+}
+
 void SubmitEditorFile::setFileName(const QString name)
 {
      m_fileName = name;
index e5c489c..6e5402c 100644 (file)
@@ -54,7 +54,7 @@ public:
     bool save(const QString &fileName);
     ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
     void reload(ReloadFlag flag, ChangeType type);
-
+    void rename(const QString &newName);
 
     void setFileName(const QString name);
     void setModified(bool modified = true);
index 67b3e80..815a062 100644 (file)
@@ -821,8 +821,8 @@ QString VCSBaseEditor::findDiffFile(const QString &f, Core::IVersionControl *con
     // Try to locate via repository.
     if (!control)
         return QString();
-    const QString topLevel = control->findTopLevelForDirectory(sourceDir);
-    if (topLevel.isEmpty())
+    QString topLevel;
+    if (!control->managesDirectory(sourceDir, &topLevel))
         return QString();
     const QFileInfo topLevelFileInfo(topLevel + slash + f);
     if (topLevelFileInfo.isFile())
index ece093e..14ecc57 100644 (file)
@@ -1,4 +1,4 @@
-<plugin name="Welcome" version="1.3.84" compatVersion="1.3.84">
+<plugin name="Welcome" version="2.0.80" compatVersion="2.0.80">
     <vendor>Nokia Corporation</vendor>
     <copyright>(C) 2010 Nokia Corporation</copyright>
     <license>
@@ -14,6 +14,6 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
     <description>Default Welcome Screen Plugin</description>
     <url>http://qt.nokia.com</url>
     <dependencyList>
-        <dependency name="Core" version="1.3.84"/>
+        <dependency name="Core" version="2.0.80"/>
     </dependencyList>
 </plugin>
index 1d6dd6f..5dc0609 100644 (file)
@@ -119,6 +119,7 @@ class Argument;
 class TypenameArgument;
 class Function;
 class Namespace;
+class NamespaceAlias;
 class BaseClass;
 class Block;
 class Class;
index 01a1022..ec8ddfc 100644 (file)
@@ -174,9 +174,13 @@ bool CheckDeclaration::visit(SimpleDeclarationAST *ast)
                 symbol->setTemplateParameters(_templateParameters);
                 _templateParameters = 0;
             }
+
             if (ty.isDeprecated())
                 symbol->setDeprecated(true);
 
+            if (ty.isFriend())
+                symbol->setStorage(Symbol::Friend);
+
             _scope->enterSymbol(symbol);
             return false;
         }
@@ -202,7 +206,7 @@ bool CheckDeclaration::visit(SimpleDeclarationAST *ast)
 
         Function *fun = 0;
         if (declTy && 0 != (fun = declTy->asFunctionType())) {
-            fun->setSourceLocation(location);
+            fun->setSourceLocation(location, translationUnit());
             fun->setScope(_scope);
             fun->setName(name);
             fun->setMethodKey(semantic()->currentMethodKey());
@@ -337,7 +341,7 @@ bool CheckDeclaration::visit(FunctionDefinitionAST *ast)
     fun->setStartOffset(tokenAt(ast->firstToken()).offset);
     fun->setEndOffset(tokenAt(ast->lastToken()).offset);
     if (ast->declarator)
-        fun->setSourceLocation(ast->declarator->firstToken());
+        fun->setSourceLocation(ast->declarator->firstToken(), translationUnit());
     fun->setName(name);
     fun->setTemplateParameters(_templateParameters);
     fun->setVisibility(semantic()->currentVisibility());
@@ -409,8 +413,27 @@ bool CheckDeclaration::visit(NamespaceAST *ast)
     return false;
 }
 
-bool CheckDeclaration::visit(NamespaceAliasDefinitionAST *)
+bool CheckDeclaration::visit(NamespaceAliasDefinitionAST *ast)
 {
+    const Name *name = 0;
+
+    if (const Identifier *id = identifier(ast->namespace_name_token))
+        name = control()->nameId(id);
+
+    unsigned sourceLocation = ast->firstToken();
+
+    if (ast->namespace_name_token)
+        sourceLocation = ast->namespace_name_token;
+
+    const Name *namespaceName = semantic()->check(ast->name, _scope);
+
+    NamespaceAlias *namespaceAlias = control()->newNamespaceAlias(sourceLocation, name);
+    namespaceAlias->setNamespaceName(namespaceName);
+    namespaceAlias->setStartOffset(tokenAt(ast->firstToken()).offset);
+    namespaceAlias->setEndOffset(tokenAt(ast->lastToken()).offset);
+    //ast->symbol = namespaceAlias;
+    _scope->enterSymbol(namespaceAlias);
+
     return false;
 }
 
index 46afb78..d98c9b9 100644 (file)
@@ -367,11 +367,15 @@ bool CheckName::visit(TemplateIdAST *ast)
 bool CheckName::visit(ObjCSelectorAST *ast)
 {
     std::vector<const Name *> names;
+    bool hasArgs = false;
     for (ObjCSelectorArgumentListAST *it = ast->selector_argument_list; it; it = it->next) {
         if (it->value->name_token) {
             const Identifier *id = control()->findOrInsertIdentifier(spell(it->value->name_token));
             const NameId *nameId = control()->nameId(id);
             names.push_back(nameId);
+
+            if (!hasArgs && it->value->colon_token)
+                hasArgs = true;
         } else {
             // we have an incomplete name due, probably due to error recovery. So, back out completely
             return false;
@@ -379,7 +383,7 @@ bool CheckName::visit(ObjCSelectorAST *ast)
     }
 
     if (!names.empty()) {
-        _name = control()->selectorNameId(&names[0], names.size(), true);
+        _name = control()->selectorNameId(&names[0], names.size(), hasArgs);
         ast->name = _name;
     }
 
index 20f622a..a456bcc 100644 (file)
@@ -385,6 +385,14 @@ public:
         return ns;
     }
 
+    NamespaceAlias *newNamespaceAlias(unsigned sourceLocation, const Name *name)
+    {
+        NamespaceAlias *ns = new NamespaceAlias(translationUnit,
+                                                sourceLocation, name);
+        symbols.push_back(ns);
+        return ns;
+    }
+
     UsingNamespaceDirective *newUsingNamespaceDirective(unsigned sourceLocation, const Name *name)
     {
         UsingNamespaceDirective *u = new UsingNamespaceDirective(translationUnit,
@@ -672,6 +680,9 @@ Function *Control::newFunction(unsigned sourceLocation, const Name *name)
 Namespace *Control::newNamespace(unsigned sourceLocation, const Name *name)
 { return d->newNamespace(sourceLocation, name); }
 
+NamespaceAlias *Control::newNamespaceAlias(unsigned sourceLocation, const Name *name)
+{ return d->newNamespaceAlias(sourceLocation, name); }
+
 BaseClass *Control::newBaseClass(unsigned sourceLocation, const Name *name)
 { return d->newBaseClass(sourceLocation, name); }
 
index 791d24c..d46c709 100644 (file)
@@ -131,6 +131,9 @@ public:
     /// Creates a new Namespace symbol.
     Namespace *newNamespace(unsigned sourceLocation, const Name *name = 0);
 
+    /// Creates a new Namespace symbol.
+    NamespaceAlias *newNamespaceAlias(unsigned sourceLocation, const Name *name = 0);
+
     /// Creates a new BaseClass symbol.
     BaseClass *newBaseClass(unsigned sourceLocation, const Name *name = 0);
 
index ca1a4f7..b4f46ac 100644 (file)
@@ -2501,10 +2501,10 @@ bool Parser::parseExpressionList(ExpressionListAST *&node)
 {
     DEBUG_THIS_RULE();
 
+#ifdef CPLUSPLUS_WITH_CXXOX_INITIALIZER_LIST
     if (_cxx0xEnabled)
         return parseInitializerList0x(node);
-
-
+#endif
 
     // ### remove me
     ExpressionListAST **expression_list_ptr = &node;
index 792cbb8..22edded 100644 (file)
@@ -179,6 +179,13 @@ bool Scope::isObjCClassScope() const
     return false;
 }
 
+bool Scope::isObjCProtocolScope() const
+{
+    if (_owner)
+        return _owner->isObjCProtocol();
+    return false;
+}
+
 bool Scope::isFunctionScope() const
 {
     Function *f = 0;
index 2ffd145..7ad6ecf 100644 (file)
@@ -114,6 +114,9 @@ public:
     /// Returns true if this scope's owner is an ObjCClass Symbol.
     bool isObjCClassScope() const;
 
+    /// Returns true if this scope's owner is an ObjCProtocol Symbol.
+    bool isObjCProtocolScope() const;
+
     /// Returns true if this scope's owner is an ObjCMethod symbol.
     bool isObjCMethodScope() const;
 
index 2da2aa9..63672f1 100644 (file)
@@ -161,10 +161,7 @@ private:
 };
 
 Symbol::Symbol(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name)
-    : _control(translationUnit->control()),
-      _sourceLocation(sourceLocation),
-      _sourceOffset(0),
-      _startOffset(0),
+    : _startOffset(0),
       _endOffset(0),
       _name(0),
       _hashCode(0),
@@ -175,19 +172,13 @@ Symbol::Symbol(TranslationUnit *translationUnit, unsigned sourceLocation, const
       _next(0),
       _isGenerated(false)
 {
-    setSourceLocation(sourceLocation);
+    setSourceLocation(sourceLocation, translationUnit);
     setName(name);
 }
 
 Symbol::~Symbol()
 { }
 
-Control *Symbol::control() const
-{ return _control; }
-
-TranslationUnit *Symbol::translationUnit() const
-{ return _control->translationUnit(); }
-
 void Symbol::visitSymbol(SymbolVisitor *visitor)
 {
     if (visitor->preVisit(this))
@@ -206,9 +197,6 @@ void Symbol::visitSymbol(Symbol *symbol, SymbolVisitor *visitor)
 unsigned Symbol::sourceLocation() const
 { return _sourceLocation; }
 
-unsigned Symbol::sourceOffset() const
-{ return _sourceOffset; }
-
 bool Symbol::isGenerated() const
 { return _isGenerated; }
 
@@ -218,56 +206,37 @@ bool Symbol::isDeprecated() const
 void Symbol::setDeprecated(bool isDeprecated)
 { _isDeprecated = isDeprecated; }
 
-void Symbol::setSourceLocation(unsigned sourceLocation)
+void Symbol::setSourceLocation(unsigned sourceLocation, TranslationUnit *translationUnit)
 {
     _sourceLocation = sourceLocation;
 
-    if (! _sourceLocation) {
-        _isGenerated = false;
-        _sourceOffset = 0;
-    } else {
-        TranslationUnit *unit = translationUnit();
-
-        const Token &tk = unit->tokenAt(sourceLocation);
-
+    if (translationUnit) {
+        const Token &tk = translationUnit->tokenAt(sourceLocation);
         _isGenerated = tk.f.generated;
-        _sourceOffset = tk.offset;
+        translationUnit->getPosition(tk.offset, &_line, &_column, &_fileId);
+    } else {
+        _isGenerated = false;
+        _line = 0;
+        _column = 0;
+        _fileId = 0;
     }
 }
 
 unsigned Symbol::line() const
 {
-    unsigned line = 0, column = 0;
-    const StringLiteral *fileId = 0;
-    translationUnit()->getPosition(_sourceOffset, &line, &column, &fileId);
-    return line;
+    return _line;
 }
 
 unsigned Symbol::column() const
 {
-    unsigned line = 0, column = 0;
-    const StringLiteral *fileId = 0;
-    translationUnit()->getPosition(_sourceOffset, &line, &column, &fileId);
-    return column;
+    return _column;
 }
 
 const StringLiteral *Symbol::fileId() const
 {
-    unsigned line = 0, column = 0;
-    const StringLiteral *fileId = 0;
-    translationUnit()->getPosition(_sourceOffset, &line, &column, &fileId);
-    return fileId;
+    return _fileId;
 }
 
-void Symbol::getPosition(unsigned *line, unsigned *column, const StringLiteral **fileId) const
-{ translationUnit()->getPosition(_sourceOffset, line, column, fileId); }
-
-void Symbol::getStartPosition(unsigned *line, unsigned *column, const StringLiteral **fileId) const
-{ translationUnit()->getPosition(_startOffset, line, column, fileId); }
-
-void Symbol::getEndPosition(unsigned *line, unsigned *column, const StringLiteral **fileId) const
-{ translationUnit()->getPosition(_endOffset, line, column, fileId); }
-
 const char *Symbol::fileName() const
 { return fileId()->chars(); }
 
@@ -498,3 +467,23 @@ bool Symbol::isObjCMethod() const
 
 bool Symbol::isObjCPropertyDeclaration() const
 { return asObjCPropertyDeclaration() != 0; }
+
+void Symbol::copy(Symbol *other)
+{
+    _sourceLocation = other->_sourceLocation;
+    _startOffset = other->_startOffset;
+    _endOffset = other->_endOffset;
+    _name = other->_name;
+    _hashCode = other->_hashCode;
+    _storage = other->_storage;
+    _visibility = other->_visibility;
+    _scope = other->_scope;
+    _index = other->_index;
+    _next = other->_next;
+    _fileId = other->_fileId;
+    _line = other->_line;
+    _column = other->_column;
+
+    _isGenerated = other->_isGenerated;
+    _isDeprecated = other->_isDeprecated;
+}
index 46d81ed..e0fe2b0 100644 (file)
@@ -87,15 +87,9 @@ public:
     /// Destroy this Symbol.
     virtual ~Symbol();
 
-    /// Returns this Symbol's Control object.
-    Control *control() const;
-
     /// Returns this Symbol's source location.
     unsigned sourceLocation() const;
 
-    /// Returns this Symbol's source offset.
-    unsigned sourceOffset() const;
-
     /// Returns this Symbol's line number.
     unsigned line() const;
 
@@ -117,10 +111,6 @@ public:
     unsigned endOffset() const;
     void setEndOffset(unsigned offset);
 
-    void getPosition(unsigned *line, unsigned *column = 0, const StringLiteral **fileId = 0) const;
-    void getStartPosition(unsigned *line, unsigned *column = 0, const StringLiteral **fileId = 0) const;
-    void getEndPosition(unsigned *line, unsigned *column = 0, const StringLiteral **fileId = 0) const;
-
     /// Returns this Symbol's name.
     const Name *name() const;
 
@@ -239,6 +229,7 @@ public:
     virtual const Enum *asEnum() const { return 0; }
     virtual const Function *asFunction() const { return 0; }
     virtual const Namespace *asNamespace() const { return 0; }
+    virtual const NamespaceAlias *asNamespaceAlias() const { return 0; }
     virtual const Class *asClass() const { return 0; }
     virtual const Block *asBlock() const { return 0; }
     virtual const UsingNamespaceDirective *asUsingNamespaceDirective() const { return 0; }
@@ -261,6 +252,7 @@ public:
     virtual Enum *asEnum() { return 0; }
     virtual Function *asFunction() { return 0; }
     virtual Namespace *asNamespace() { return 0; }
+    virtual NamespaceAlias *asNamespaceAlias() { return 0; }
     virtual Class *asClass() { return 0; }
     virtual Block *asBlock() { return 0; }
     virtual UsingNamespaceDirective *asUsingNamespaceDirective() { return 0; }
@@ -313,20 +305,18 @@ public:
     Scope *enclosingBlockScope() const;
 
     void setScope(Scope *scope); // ### make me private
-    void setSourceLocation(unsigned sourceLocation); // ### make me private
+    void setSourceLocation(unsigned sourceLocation, TranslationUnit *translationUnit); // ### make me private
 
     void visitSymbol(SymbolVisitor *visitor);
     static void visitSymbol(Symbol *symbol, SymbolVisitor *visitor);
 
+    virtual void copy(Symbol *other);
+
 protected:
     virtual void visitSymbol0(SymbolVisitor *visitor) = 0;
 
-    TranslationUnit *translationUnit() const;
-
 private:
-    Control *_control;
     unsigned _sourceLocation;
-    unsigned _sourceOffset;
     unsigned _startOffset;
     unsigned _endOffset;
     const Name *_name;
@@ -336,6 +326,9 @@ private:
     Scope *_scope;
     unsigned _index;
     Symbol *_next;
+    const StringLiteral *_fileId;
+    unsigned _line;
+    unsigned _column;
 
     bool _isGenerated: 1;
     bool _isDeprecated: 1;
index a249f52..9e66b45 100644 (file)
@@ -70,6 +70,7 @@ public:
 
     virtual bool visit(UsingNamespaceDirective *) { return true; }
     virtual bool visit(UsingDeclaration *) { return true; }
+    virtual bool visit(NamespaceAlias *) { return true; }
     virtual bool visit(Declaration *) { return true; }
     virtual bool visit(Argument *) { return true; }
     virtual bool visit(TypenameArgument *) { return true; }
index c7226bd..e82a60a 100644 (file)
@@ -89,6 +89,27 @@ FullySpecifiedType UsingNamespaceDirective::type() const
 void UsingNamespaceDirective::visitSymbol0(SymbolVisitor *visitor)
 { visitor->visit(this); }
 
+NamespaceAlias::NamespaceAlias(TranslationUnit *translationUnit,
+                               unsigned sourceLocation, const Name *name)
+    : Symbol(translationUnit, sourceLocation, name), _namespaceName(0)
+{ }
+
+NamespaceAlias::~NamespaceAlias()
+{ }
+
+const Name *NamespaceAlias::namespaceName() const
+{ return _namespaceName; }
+
+void NamespaceAlias::setNamespaceName(const Name *namespaceName)
+{ _namespaceName = namespaceName; }
+
+FullySpecifiedType NamespaceAlias::type() const
+{ return FullySpecifiedType(); }
+
+void NamespaceAlias::visitSymbol0(SymbolVisitor *visitor)
+{ visitor->visit(this); }
+
+
 UsingDeclaration::UsingDeclaration(TranslationUnit *translationUnit,
                                    unsigned sourceLocation, const Name *name)
     : Symbol(translationUnit, sourceLocation, name)
index 48356b2..46be950 100644 (file)
@@ -110,6 +110,31 @@ protected:
     virtual void visitSymbol0(SymbolVisitor *visitor);
 };
 
+class CPLUSPLUS_EXPORT NamespaceAlias: public Symbol
+{
+public:
+    NamespaceAlias(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name);
+    virtual ~NamespaceAlias();
+
+    const Name *namespaceName() const;
+    void setNamespaceName(const Name *namespaceName);
+
+    // Symbol's interface
+    virtual FullySpecifiedType type() const;
+
+    virtual const NamespaceAlias *asNamespaceAlias() const
+    { return this; }
+
+    virtual NamespaceAlias *asNamespaceAlias()
+    { return this; }
+
+protected:
+    virtual void visitSymbol0(SymbolVisitor *visitor);
+
+private:
+    const Name *_namespaceName;
+};
+
 class CPLUSPLUS_EXPORT Declaration: public Symbol
 {
 public:
index fdb18d0..94b0034 100644 (file)
@@ -7,7 +7,8 @@ SUBDIRS += \
 #    profilereader \
     aggregation \
     changeset \
-       icheckbuild
+    icheckbuild \
+    generichighlighter
 
 contains (QT_CONFIG, declarative) {
 SUBDIRS += qml
index 7e1ceda..fdf4327 100644 (file)
@@ -85,21 +85,19 @@ void tst_Lookup::base_class_defined_1()
     Snapshot snapshot;
     snapshot.insert(doc);
 
-    Document::Ptr emptyDoc = Document::create("<empty>");
-
     Class *baseClass = doc->globalSymbolAt(0)->asClass();
     QVERIFY(baseClass);
 
     Class *derivedClass = doc->globalSymbolAt(1)->asClass();
     QVERIFY(derivedClass);
 
-    LookupContext ctx(derivedClass, emptyDoc, doc, snapshot);
+    const LookupContext ctx(doc, snapshot);
 
-    const QList<Symbol *> candidates =
-        ctx.resolveClass(derivedClass->baseClassAt(0)->name());
+    ClassOrNamespace *klass = ctx.lookupType(derivedClass->baseClassAt(0)->name(), derivedClass->scope());
+    QVERIFY(klass != 0);
 
-    QCOMPARE(candidates.size(), 1);
-    QCOMPARE(candidates.at(0), baseClass);
+    QCOMPARE(klass->symbols().size(), 1);
+    QCOMPARE(klass->symbols().first(), baseClass);
 
     TranslationUnit *unit = doc->translationUnit();
     QVERIFY(unit != 0);
@@ -136,8 +134,6 @@ void tst_Lookup::simple_class_1()
     Snapshot snapshot;
     snapshot.insert(doc);
 
-    Document::Ptr emptyDoc = Document::create("<empty>");
-
     ObjCClass *iface = doc->globalSymbolAt(0)->asObjCClass();
     QVERIFY(iface);
     QVERIFY(iface->isInterface());
@@ -148,40 +144,39 @@ void tst_Lookup::simple_class_1()
     QVERIFY(!impl->isInterface());
     QCOMPARE(impl->memberCount(), 3U);
 
-    ObjCMethod *allocMethod = impl->memberAt(0)->asObjCMethod();
-    QVERIFY(allocMethod);
-    QVERIFY(allocMethod->name() && allocMethod->name()->identifier());
-    QCOMPARE(QLatin1String(allocMethod->name()->identifier()->chars()), QLatin1String("alloc"));
+    Declaration *allocMethodIface = iface->memberAt(0)->asDeclaration();
+    QVERIFY(allocMethodIface);
+    QVERIFY(allocMethodIface->name() && allocMethodIface->name()->identifier());
+    QCOMPARE(QLatin1String(allocMethodIface->name()->identifier()->chars()), QLatin1String("alloc"));
+
+    ObjCMethod *allocMethodImpl = impl->memberAt(0)->asObjCMethod();
+    QVERIFY(allocMethodImpl);
+    QVERIFY(allocMethodImpl->name() && allocMethodImpl->name()->identifier());
+    QCOMPARE(QLatin1String(allocMethodImpl->name()->identifier()->chars()), QLatin1String("alloc"));
 
     ObjCMethod *deallocMethod = impl->memberAt(2)->asObjCMethod();
     QVERIFY(deallocMethod);
     QVERIFY(deallocMethod->name() && deallocMethod->name()->identifier());
     QCOMPARE(QLatin1String(deallocMethod->name()->identifier()->chars()), QLatin1String("dealloc"));
 
-    const LookupContext ctxt(impl, emptyDoc, doc, snapshot);
+    const LookupContext context(doc, snapshot);
 
     // check class resolving:
-    const QList<Symbol *> candidates = ctxt.resolveObjCClass(impl->name());
-    QCOMPARE(candidates.size(), 2);
-    QVERIFY(candidates.contains(iface));
-    QVERIFY(candidates.contains(impl));
-
-    // check scope expansion:
-    QList<Scope *> expandedScopes;
-    ctxt.expand(impl->members(), ctxt.visibleScopes(), &expandedScopes);
-    QCOMPARE(expandedScopes.size(), 2);
-
-    const ResolveExpression resolver(ctxt);
+    ClassOrNamespace *klass = context.lookupType(impl->name(), impl->scope());
+    QVERIFY(klass != 0);
+    QCOMPARE(klass->symbols().size(), 2);
+    QVERIFY(klass->symbols().contains(iface));
+    QVERIFY(klass->symbols().contains(impl));
 
     // check method resolving:
-    QList<LookupItem> results = resolver.resolveMember(allocMethod->name(), impl);
+    QList<Symbol *> results = context.lookup(allocMethodImpl->name(), impl->members());
     QCOMPARE(results.size(), 2);
-    QVERIFY(results.at(0).lastVisibleSymbol() == allocMethod || results.at(1).lastVisibleSymbol() == allocMethod);
-    QVERIFY(results.at(0).lastVisibleSymbol()->asDeclaration() || results.at(1).lastVisibleSymbol()->asDeclaration());
+    QCOMPARE(results.at(0), allocMethodIface);
+    QCOMPARE(results.at(1), allocMethodImpl);
 
-    results = resolver.resolveMember(deallocMethod->name(), impl);
+    results = context.lookup(deallocMethod->name(), impl->members());
     QCOMPARE(results.size(), 1);
-    QCOMPARE(results.at(0).lastVisibleSymbol(), deallocMethod);
+    QCOMPARE(results.at(0), deallocMethod);
 }
 
 void tst_Lookup::class_with_baseclass()
@@ -229,25 +224,19 @@ void tst_Lookup::class_with_baseclass()
     QVERIFY(baseMethod->name() && baseMethod->name()->identifier());
     QCOMPARE(QLatin1String(baseMethod->name()->identifier()->chars()), QLatin1String("baseMethod"));
 
-    const LookupContext ctxt(zooImpl, emptyDoc, doc, snapshot);
-
-    const QList<Symbol *> candidates = ctxt.resolveObjCClass(baseZoo->name());
-    QCOMPARE(candidates.size(), 1);
-    QVERIFY(candidates.contains(baseZoo));
-
-    QList<Scope *> expandedScopes;
-    ctxt.expand(zooImpl->members(), ctxt.visibleScopes(), &expandedScopes);
-    QCOMPARE(expandedScopes.size(), 3);
+    const LookupContext context(doc, snapshot);
 
-    const ResolveExpression resolver(ctxt);
+    ClassOrNamespace *objClass = context.lookupType(baseZoo->name(), zooImpl->scope());
+    QVERIFY(objClass != 0);
+    QVERIFY(objClass->symbols().contains(baseZoo));
 
-    QList<LookupItem> results = resolver.resolveMember(baseDecl->name(), zooImpl);
+    QList<Symbol *> results = context.lookup(baseDecl->name(), zooImpl->members());
     QCOMPARE(results.size(), 1);
-    QCOMPARE(results.at(0).lastVisibleSymbol(), baseDecl);
+    QCOMPARE(results.at(0), baseDecl);
 
-    results = resolver.resolveMember(baseMethod->name(), zooImpl);
+    results = context.lookup(baseMethod->name(), zooImpl->members());
     QCOMPARE(results.size(), 1);
-    QCOMPARE(results.at(0).lastVisibleSymbol(), baseMethod);
+    QCOMPARE(results.at(0), baseMethod);
 }
 
 void tst_Lookup::class_with_protocol_with_protocol()
@@ -269,8 +258,6 @@ void tst_Lookup::class_with_protocol_with_protocol()
     Snapshot snapshot;
     snapshot.insert(doc);
 
-    Document::Ptr emptyDoc = Document::create("<empty>");
-
     ObjCProtocol *P1 = doc->globalSymbolAt(0)->asObjCProtocol();
     QVERIFY(P1);
     QCOMPARE(P1->memberCount(), 1U);
@@ -289,29 +276,23 @@ void tst_Lookup::class_with_protocol_with_protocol()
     ObjCClass *zooImpl = doc->globalSymbolAt(3)->asObjCClass();
     QVERIFY(zooImpl);
 
-    const LookupContext ctxt(zooImpl, emptyDoc, doc, snapshot);
+    const LookupContext context(doc, snapshot);
 
     {
-        const QList<Symbol *> candidates = ctxt.resolveObjCProtocol(P1->name());
+        const QList<Symbol *> candidates = context.lookup(P1->name(), zooImpl->scope());
         QCOMPARE(candidates.size(), 1);
         QVERIFY(candidates.contains(P1));
     }
 
     {
-        const QList<Symbol *> candidates = ctxt.resolveObjCProtocol(P2->protocolAt(0)->name());
+        const QList<Symbol *> candidates = context.lookup(P2->protocolAt(0)->name(), zooImpl->scope());
         QCOMPARE(candidates.size(), 1);
         QVERIFY(candidates.contains(P1));
     }
 
-    QList<Scope *> expandedScopes;
-    ctxt.expand(zooImpl->members(), ctxt.visibleScopes(), &expandedScopes);
-    QCOMPARE(expandedScopes.size(), 4);
-
-    const ResolveExpression resolver(ctxt);
-
-    QList<LookupItem> results = resolver.resolveMember(p1method->name(), zooImpl);
+    QList<Symbol *> results = context.lookup(p1method->name(), zooImpl->members());
     QCOMPARE(results.size(), 1);
-    QCOMPARE(results.at(0).lastVisibleSymbol(), p1method);
+    QCOMPARE(results.at(0), p1method);
 }
 
 void tst_Lookup::iface_impl_scoping()
@@ -331,7 +312,6 @@ void tst_Lookup::iface_impl_scoping()
     Snapshot snapshot;
     snapshot.insert(doc);
 
-    Document::Ptr emptyDoc = Document::create("<empty>");
     ObjCClass *iface = doc->globalSymbolAt(0)->asObjCClass();
     QVERIFY(iface);
     QVERIFY(iface->isInterface());
@@ -351,7 +331,7 @@ void tst_Lookup::iface_impl_scoping()
     Block *method1Body = method1Impl->memberAt(0)->asBlock();
     QVERIFY(method1Body);
 
-    const LookupContext ctxt(method1Body, emptyDoc, doc, snapshot);
+    const LookupContext context(doc, snapshot);
 
     { // verify if we can resolve "arg" in the body
         QCOMPARE(method1Impl->argumentCount(), 1U);
@@ -361,7 +341,7 @@ void tst_Lookup::iface_impl_scoping()
         QVERIFY(arg->name()->identifier());
         QCOMPARE(arg->name()->identifier()->chars(), "arg");
 
-        const QList<Symbol *> candidates = ctxt.resolve(arg->name());
+        const QList<Symbol *> candidates = context.lookup(arg->name(), method1Body->scope());
         QCOMPARE(candidates.size(), 1);
         QVERIFY(candidates.at(0)->type()->asIntegerType());
     }
@@ -371,19 +351,10 @@ void tst_Lookup::iface_impl_scoping()
     QCOMPARE(method2->identifier()->chars(), "method2");
 
     { // verify if we can resolve "method2" in the body
-        const QList<Symbol *> candidates = ctxt.resolve(method2->name());
+        const QList<Symbol *> candidates = context.lookup(method2->name(), method1Body->scope());
         QCOMPARE(candidates.size(), 1);
         QCOMPARE(candidates.at(0), method2);
     }
-
-    { // now let's see if the resolver can do the same for method2
-        const ResolveExpression resolver(ctxt);
-
-        const QList<LookupItem> results = resolver.resolveMember(method2->name(),
-                                                                 impl);
-        QCOMPARE(results.size(), 1);
-        QCOMPARE(results.at(0).lastVisibleSymbol(), method2);
-    }
 }
 
 QTEST_APPLESS_MAIN(tst_Lookup)
index 8823faf..85e7004 100644 (file)
@@ -15,7 +15,7 @@
 #include <Names.h>
 #include <Literals.h>
 #include <DiagnosticClient.h>
-#include <GenTemplateInstance.h>
+#include <DeprecatedGenTemplateInstance.h>
 #include <Overview.h>
 #include <ExpressionUnderCursor.h>
 #include <Names.h>
@@ -426,26 +426,23 @@ void tst_Semantic::pointer_to_function_1()
 
 void tst_Semantic::template_instance_1()
 {
-    QSharedPointer<Document> doc = document("void append(const _Tp &value);");
+    QSharedPointer<Document> doc = document("template <typename _Tp> class QList { void append(const _Tp &value); };");
     QCOMPARE(doc->errorCount, 0U);
     QCOMPARE(doc->globals->symbolCount(), 1U);
 
-    Declaration *decl = doc->globals->symbolAt(0)->asDeclaration();
+    Declaration *decl = doc->globals->symbolAt(0)->asClass()->memberAt(0)->asDeclaration();
     QVERIFY(decl);
 
-    GenTemplateInstance::Substitution subst;
-    const Identifier *nameTp = control.findOrInsertIdentifier("_Tp");
-    FullySpecifiedType intTy(control.integerType(IntegerType::Int));
-    subst.append(qMakePair(nameTp, intTy));
+    FullySpecifiedType templArgs[] = { control.integerType(IntegerType::Int) };
+    const Name *templId = control.templateNameId(control.findOrInsertIdentifier("QList"), templArgs, 1);
 
-    GenTemplateInstance inst(&control, subst);
-    FullySpecifiedType genTy = inst(decl);
+    FullySpecifiedType genTy = DeprecatedGenTemplateInstance::instantiate(templId, decl, &control);
 
     Overview oo;
     oo.setShowReturnTypes(true);
 
     const QString genDecl = oo.prettyType(genTy);
-    QCOMPARE(genDecl, QString::fromLatin1("void(const int &)"));
+    QCOMPARE(genDecl, QString::fromLatin1("void (const int &)"));
 }
 
 void tst_Semantic::expression_under_cursor_1()
index 7e69829..201c36c 100644 (file)
@@ -6,6 +6,7 @@ MACROSDIR   = ../../../share/qtcreator/gdbmacros
 
 SOURCES += \
     $$DEBUGGERDIR/gdb/gdbmi.cpp \
+    $$DEBUGGERDIR/tcf/json.cpp \
     $$MACROSDIR/gdbmacros.cpp \
     tst_dumpers.cpp \
 
index 48e0510..26eb1aa 100644 (file)
@@ -1,4 +1,5 @@
 #include "gdb/gdbmi.h"
+#include "tcf/json.h"
 #include "gdbmacros.h"
 #include "gdbmacros_p.h"
 
@@ -91,6 +92,10 @@ static const char gdbmi12[] =
      "numchild=\"0\"}]";
 
 
+static const char jsont1[] =
+    "{\"Size\":100564,\"UID\":0,\"GID\":0,\"Permissions\":33261,"
+     "\"ATime\":1242370878000,\"MTime\":1239154689000}";
+
 struct Int3 {
     Int3() { i1 = 42; i2 = 43; i3 = 44; }
     int i1, i2, i3;
@@ -116,6 +121,12 @@ public:
             '\n' + QString(input));
     }
 
+    void testJson(const char* input)
+    {
+        QCOMPARE('\n' + QString::fromLatin1(JsonValue(input).toString(false)),
+            '\n' + QString(input));
+    }
+
 private slots:
     void mi1()  { testMi(gdbmi1);  }
     void mi2()  { testMi(gdbmi2);  }
@@ -128,6 +139,8 @@ private slots:
     void mi11() { testMi(gdbmi11); }
     //void mi12() { testMi(gdbmi12); }
 
+    void json1() { testJson(jsont1); }
+
     void infoBreak();
     void niceType();
     void niceType_data();
diff --git a/tests/auto/generichighlighter/generichighlighter.pro b/tests/auto/generichighlighter/generichighlighter.pro
new file mode 100644 (file)
index 0000000..97a6f0b
--- /dev/null
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS += specificrules
diff --git a/tests/auto/generichighlighter/specificrules/specificrules.pro b/tests/auto/generichighlighter/specificrules/specificrules.pro
new file mode 100644 (file)
index 0000000..889ff8a
--- /dev/null
@@ -0,0 +1,17 @@
+QT += testlib
+
+PLUGINSDIR = ../../../../src/plugins
+
+SOURCES += tst_specificrules.cpp \
+    $$PLUGINSDIR/texteditor/generichighlighter/context.cpp \
+    $$PLUGINSDIR/texteditor/generichighlighter/dynamicrule.cpp \
+    $$PLUGINSDIR/texteditor/generichighlighter/rule.cpp \
+    $$PLUGINSDIR/texteditor/generichighlighter/specificrules.cpp \
+    $$PLUGINSDIR/texteditor/generichighlighter/progressdata.cpp \
+    $$PLUGINSDIR/texteditor/generichighlighter/highlightdefinition.cpp \
+    $$PLUGINSDIR/texteditor/generichighlighter/keywordlist.cpp \
+    $$PLUGINSDIR/texteditor/generichighlighter/itemdata.cpp
+
+INCLUDEPATH += $$PLUGINSDIR
+
+TARGET=tst_$$TARGET
diff --git a/tests/auto/generichighlighter/specificrules/tst_specificrules.cpp b/tests/auto/generichighlighter/specificrules/tst_specificrules.cpp
new file mode 100644 (file)
index 0000000..7fa6c50
--- /dev/null
@@ -0,0 +1,784 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include <texteditor/generichighlighter/highlightdefinition.h>
+#include <texteditor/generichighlighter/keywordlist.h>
+#include <texteditor/generichighlighter/specificrules.h>
+#include <texteditor/generichighlighter/progressdata.h>
+
+#include <QtTest/QtTest>
+
+using namespace TextEditor;
+using namespace Internal;
+
+class tst_SpecificRules : public QObject
+{
+    Q_OBJECT
+public:
+    tst_SpecificRules() : m_definition(new HighlightDefinition) {}
+
+private slots:
+    void initTestCase();
+
+    void testDetectChar();
+    void testDetectChar_data();
+
+    void testDetect2Char();
+    void testDetect2Char_data();
+
+    void testAnyChar();
+    void testAnyChar_data();
+
+    void testStringDetect();
+    void testStringDetect_data();
+
+    void testRegExpr();
+    void testRegExpr_data();
+    void testRegExprOffsetIncremented();
+    void testRegExprOffsetIncremented_data();
+
+    void testKeywordGlobalSensitiveLocalSensitive();
+    void testKeywordGlobalSensitiveLocalSensitive_data();
+    void testKeywordGlobalSensitiveLocalInsensitive();
+    void testKeywordGlobalSensitiveLocalInsensitive_data();
+    void testKeywordGlobalInsensitiveLocalInsensitive();
+    void testKeywordGlobalInsensitiveLocalInsensitive_data();
+    void testKeywordGlobalInsensitiveLocalSensitive();
+    void testKeywordGlobalInsensitiveLocalSensitive_data();
+
+    void testInt();
+    void testInt_data();
+
+    void testFloat();
+    void testFloat_data();
+
+    void testCOctal();
+    void testCOctal_data();
+
+    void testCHex();
+    void testCHex_data();
+
+    void testCString();
+    void testCString_data();
+
+    void testCChar();
+    void testCChar_data();
+
+    void testRangeDetect();
+    void testRangeDetect_data();
+
+    void testLineContinue();
+    void testLineContinue_data();
+
+    void testDetectSpaces();
+    void testDetectSpaces_data();
+
+    void testDetectIdentifier();
+    void testDetectIdentifier_data();
+
+private:
+    void addCommonColumns() const;
+    void testMatch(const Rule &rule) const;
+    void testMatch(const Rule &rule, ProgressData *progress) const;
+
+    void noMatchForInt() const;
+    void noMatchForFloat() const;
+    void noMatchForCOctal() const;
+    void noMatchForCHex() const;
+    void noMatchForNumber() const;
+
+    void commonCasesForKeywords() const;
+
+    QSharedPointer<HighlightDefinition> m_definition;
+};
+
+void tst_SpecificRules::initTestCase()
+{
+    QSharedPointer<KeywordList> list = m_definition->createKeywordList("keywords");
+    list->addKeyword("for");
+    list->addKeyword("while");
+    list->addKeyword("BEGIN");
+    list->addKeyword("END");
+    list->addKeyword("WeIrD");
+}
+
+void tst_SpecificRules::addCommonColumns() const
+{
+    QTest::addColumn<QString>("s");
+    QTest::addColumn<bool>("match");
+    QTest::addColumn<int>("offset");
+    QTest::addColumn<bool>("only spaces");
+    QTest::addColumn<bool>("will continue");
+}
+
+void tst_SpecificRules::testMatch(const Rule &rule) const
+{
+    ProgressData progress;
+    testMatch(rule, &progress);
+}
+
+void tst_SpecificRules::testMatch(const Rule &rule, ProgressData *progress) const
+{    
+    QFETCH(QString, s);
+
+    QTEST(rule.matchSucceed(s, s.length(), progress), "match");
+    QTEST(progress->offset(), "offset");
+    QTEST(progress->onlySpacesSoFar(), "only spaces");
+    QTEST(progress->willContinueLine(), "will continue");
+}
+
+void tst_SpecificRules::testDetectChar()
+{
+    QFETCH(QString, c);
+    DetectCharRule rule;
+    rule.setChar(c);
+
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testDetectChar_data()
+{
+    QTest::addColumn<QString>("c");
+    addCommonColumns();
+
+    QTest::newRow("[#] against [#]") << "#" << "#" << true << 1 << false << false;
+    QTest::newRow("[#] against [##]") << "#" << "##" << true << 1 << false << false;
+    QTest::newRow("[#] against [ ]") << "#" << " " << false << 0 << true << false;
+    QTest::newRow("[#] against [a]") << "#" << "a" << false << 0 << true << false;
+    QTest::newRow("[#] against [abc]") << "#" << "abc" << false << 0 << true << false;
+    QTest::newRow("[#] against [x#]") << "#" << "x#" << false << 0 << true << false;
+    QTest::newRow("[ ] against [a]") << " " << "a" << false << 0 << true << false;
+    //QTest::newRow("[ ] against [ ]") << " " << " " << true << 1 << true << false;
+}
+
+void tst_SpecificRules::testDetect2Char()
+{
+    QFETCH(QString, c);
+    QFETCH(QString, c1);
+    Detect2CharsRule rule;
+    rule.setChar(c);
+    rule.setChar1(c1);
+
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testDetect2Char_data()
+{
+    QTest::addColumn<QString>("c");
+    QTest::addColumn<QString>("c1");
+    addCommonColumns();
+
+    QTest::newRow("[//] against [//]") << "/" << "/" << "//" << true << 2 << false << false;
+    QTest::newRow("[//] against [///]") << "/" << "/" << "///" << true << 2 << false << false;
+    QTest::newRow("[//] against [// ]") << "/" << "/" << "// " << true << 2 << false << false;
+    QTest::newRow("[//] against [ //]") << "/" << "/" << " //" << false << 0 << true << false;
+    QTest::newRow("[//] against [a]") << "/" << "/" << "a" << false << 0 << true << false;
+    QTest::newRow("[//] against [ a]") << "/" << "/" << " a" << false << 0 << true << false;
+    QTest::newRow("[//] against [abc]") << "/" << "/" << "abc" << false << 0 << true << false;
+    QTest::newRow("[//] against [/a]") << "/" << "/" << "/a" << false << 0 << true << false;
+    QTest::newRow("[//] against [a/]") << "/" << "/" << "a/" << false << 0 << true << false;
+    QTest::newRow("[  ] against [xx]") << " " << " " << "xx" << false << 0 << true << false;
+    //QTest::newRow("[  ] against [  ]") << " " << " " << " " << true << 3 << true << false;
+}
+
+void tst_SpecificRules::testAnyChar()
+{
+    QFETCH(QString, chars);
+    AnyCharRule rule;
+    rule.setCharacterSet(chars);
+
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testAnyChar_data()
+{
+    QTest::addColumn<QString>("chars");
+    addCommonColumns();
+
+    QTest::newRow("[:!<>?] against [:]") << ":!<>?" << ":" << true << 1 << false << false;
+    QTest::newRow("[:!<>?] against [!]") << ":!<>?" << "!" << true << 1 << false << false;
+    QTest::newRow("[:!<>?] against [<]") << ":!<>?" << "<" << true << 1 << false << false;
+    QTest::newRow("[:!<>?] against [>]") << ":!<>?" << ">" << true << 1 << false << false;
+    QTest::newRow("[:!<>?] against [?]") << ":!<>?" << "?" << true << 1 << false << false;
+    QTest::newRow("[:!<>?] against [:]") << ":!<>?" << ":" << true << 1 << false << false;
+    QTest::newRow("[:!<>?] against [ ]") << ":!<>?" << " " << false << 0 << true << false;
+    QTest::newRow("[:!<>?] against [#]") << ":!<>?" << "#" << false << 0 << true << false;
+    QTest::newRow("[:!<>?] against [!#]") << ":!<>?" << "!#" << true << 1 << false << false;
+    QTest::newRow("[:!<>?] against [#!]") << ":!<>?" << "#!" << false << 0 << true << false;
+    QTest::newRow("[:] against [:]") << ":" << ":" << true << 1 << false << false;
+    QTest::newRow("[:] against [#]") << ":" << "#" << false << 0 << true << false;
+    //QTest::newRow("[   ] against [ ]") << "   " << " " << true << 1 << true << false;
+}
+
+void tst_SpecificRules::testStringDetect()
+{
+    QFETCH(QString, referenceString);
+    QFETCH(QString, insensitive);
+    StringDetectRule rule;
+    rule.setString(referenceString);
+    rule.setInsensitive(insensitive);
+
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testStringDetect_data()
+{
+    QTest::addColumn<QString>("referenceString");
+    QTest::addColumn<QString>("insensitive");
+    addCommonColumns();
+
+    QTest::newRow("[LL] against [LL]") << "LL" << "0" << "LL" << true << 2 << false << false;
+    QTest::newRow("[LL] against [ll]") << "LL" << "0" << "ll" << false << 0 << true << false;
+    QTest::newRow("[LL] against [ll] i") << "LL" << "1" << "ll" << true << 2 << false << false;
+    QTest::newRow("[ll] against [ll] i") << "LL" << "1" << "LL" << true << 2 << false << false;
+    QTest::newRow("[LL] against [5LL]") << "LL" << "0" << "5LL" << false << 0 << true << false;
+    QTest::newRow("[LL] against [L]") << "LL" << "0" << "L" << false << 0 << true << false;
+    QTest::newRow("[LL] against [LLL]") << "LL" << "0" << "LLL" << true << 2 << false << false;
+    QTest::newRow("[LL] against [ ]") << "LL" << "0" << " " << false << 0 << true << false;
+    QTest::newRow("[LL] against [xLLx]") << "LL" << "0" << "xLLx" << false << 0 << true << false;
+    QTest::newRow("[\"\"\"] against [\"\"\"]") << "\"\"\"" << "0" << "\"\"\"" << true << 3
+            << false << false;
+}
+
+void tst_SpecificRules::testRegExpr()
+{
+    QFETCH(QString, pattern);
+    QFETCH(QString, insensitive);
+    QFETCH(QString, minimal);
+    RegExprRule rule;
+    rule.setPattern(pattern);
+    rule.setInsensitive(insensitive);
+    rule.setMinimal(minimal);
+
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testRegExpr_data()
+{
+    QTest::addColumn<QString>("pattern");
+    QTest::addColumn<QString>("insensitive");
+    QTest::addColumn<QString>("minimal");
+    addCommonColumns();
+
+    QTest::newRow("[#[a-z]+\\s+\\d] against [#as 9]") << "#[a-z]+\\s+\\d" << "0" << "0"
+            << "#as 9" << true << 5 << false << false;
+    QTest::newRow("[#[a-z]+\\s+\\d] against [#As 9]") << "#[a-z]+\\s+\\d" << "0" << "0"
+            << "#As 9" << false << 0 << true << false;
+    QTest::newRow("[#[a-z]+\\s+\\d] against [#As 9] i") << "#[a-z]+\\s+\\d" << "1" << "0"
+            << "#As 9" << true << 5 << false << false;
+    QTest::newRow("[#[a-z]+\\s+\\d] against [as 9]") << "#[a-z]+\\s+\\d" << "0" << "0"
+            << "as 9" << false << 0 << true << false;
+    QTest::newRow("[#[a-z]+\\s+\\d] against [w#as 9]") << "#[a-z]+\\s+\\d" << "0" << "0"
+            << "w#as 9" << false << 0 << true << false;
+    QTest::newRow("[^\\s+[a-z]] against [x]") << "^\\s+[a-z]" << "0" << "0"
+            << "x" << false << 0 << true << false;
+    QTest::newRow("[^\\s+[a-z]] against [  x]") << "^\\s+[a-z]" << "0" << "0"
+            << "  x" << true << 3 << false << false;
+    QTest::newRow("[0+] against [1001]") << "0+" << "0" << "0"
+            << "1001" << false << 0 << true << false;
+    QTest::newRow("[0+] against [001]") << "0+" << "0" << "0"
+            << "001" << true << 2 << false << false;
+    QTest::newRow("[0+] against [001]") << "0+" << "0" << "1"
+            << "001" << true << 1 << false << false;
+    QTest::newRow("[\\s*] against []") << "\\s*" << "0" << "0"
+            << "" << false << 0 << true << false;
+    //QTest::newRow("[\\s*] against []") << "\\s*" << "0" << "0"
+    //      << " " << true << 1 << true << false;
+}
+
+void tst_SpecificRules::testRegExprOffsetIncremented()
+{
+    QFETCH(QString, pattern);
+    RegExprRule rule;
+    rule.setPattern(pattern);
+
+    ProgressData progress;
+    progress.setOffset(1);
+
+    testMatch(rule, &progress);
+}
+
+void tst_SpecificRules::testRegExprOffsetIncremented_data()
+{
+    QTest::addColumn<QString>("pattern");
+    addCommonColumns();
+
+    // To make sure that QRegExp::CaretAtZero is set.
+    QTest::newRow("[^\\s+[a-z]] against [  x]") << "^\\s+[a-z]" << "  x" << false << 1
+            << true << false;
+}
+
+void tst_SpecificRules::commonCasesForKeywords() const
+{
+    QTest::newRow("[for]") << "for" << true << 3 << false << false;
+    QTest::newRow("[while]") << "while" << true << 5 << false << false;
+    QTest::newRow("[BEGIN]") << "BEGIN" << true << 5 << false << false;
+    QTest::newRow("[END]") << "END" << true << 3 << false << false;
+    QTest::newRow("[WeIrD]") << "WeIrD" << true << 5 << false << false;
+    QTest::newRow("[forr]") << "forr" << false << 0 << true << false;
+    QTest::newRow("[for#]") << "for#" << false << 0 << true << false;
+    QTest::newRow("[abc]") << "abc" << false << 0 << true << false;
+    QTest::newRow("[ ]") << " " << false << 0 << true << false;
+    QTest::newRow("[foe]") << "foe" << false << 0 << true << false;
+    QTest::newRow("[sor]") << "sor" << false << 0 << true << false;
+    QTest::newRow("[ffor]") << "ffor" << false << 0 << true << false;
+
+    // Valid default delimiters.
+    QTest::newRow("[for ]") << "for " << true << 3 << false << false;
+    QTest::newRow("[for.for]") << "for.for" << true << 3 << false << false;
+    QTest::newRow("[for(]") << "for(" << true << 3 << false << false;
+    QTest::newRow("[for)]") << "for)" << true << 3 << false << false;
+    QTest::newRow("[for:]") << "for:" << true << 3 << false << false;
+    QTest::newRow("[for!]") << "for!" << true << 3 << false << false;
+    QTest::newRow("[for+]") << "for+" << true << 3 << false << false;
+    QTest::newRow("[for,]") << "for," << true << 3 << false << false;
+    QTest::newRow("[for-]") << "for-" << true << 3 << false << false;
+    QTest::newRow("[for<]") << "for>" << true << 3 << false << false;
+    QTest::newRow("[for=]") << "for=" << true << 3 << false << false;
+    QTest::newRow("[for>]") << "for>" << true << 3 << false << false;
+    QTest::newRow("[for%]") << "for%" << true << 3 << false << false;
+    QTest::newRow("[for&]") << "for&" << true << 3 << false << false;
+    QTest::newRow("[for/]") << "for/" << true << 3 << false << false;
+    QTest::newRow("[for;]") << "for;" << true << 3 << false << false;
+    QTest::newRow("[for?]") << "for?" << true << 3 << false << false;
+    QTest::newRow("[for[]") << "for[" << true << 3 << false << false;
+    QTest::newRow("[for]]") << "for]" << true << 3 << false << false;
+    QTest::newRow("[for^]") << "for^" << true << 3 << false << false;
+    QTest::newRow("[for{]") << "for{" << true << 3 << false << false;
+    QTest::newRow("[for|]") << "for|" << true << 3 << false << false;
+    QTest::newRow("[for}]") << "for}" << true << 3 << false << false;
+    QTest::newRow("[for~]") << "for~" << true << 3 << false << false;
+    QTest::newRow("[for\\]") << "for\\" << true << 3 << false << false;
+    QTest::newRow("[for*]") << "for*" << true << 3 << false << false;
+    QTest::newRow("[for,for]") << "for,for" << true << 3 << false << false;
+    QTest::newRow("[for\t]") << "for\t" << true << 3 << false << false;
+}
+
+void tst_SpecificRules::testKeywordGlobalSensitiveLocalSensitive()
+{
+    m_definition->setKeywordsSensitive("true");
+    KeywordRule rule(m_definition);
+    rule.setInsensitive("false");
+    rule.setList("keywords");
+
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testKeywordGlobalSensitiveLocalSensitive_data()
+{
+    addCommonColumns();
+
+    commonCasesForKeywords();
+    QTest::newRow("[fOr]") << "fOr" << false << 0 << true << false;
+    QTest::newRow("[whilE") << "whilE" << false << 0 << true << false;
+    QTest::newRow("[bEGIN]") << "bEGIN" << false << 0 << true << false;
+    QTest::newRow("[end]") << "end" << false << 0 << true << false;
+    QTest::newRow("[weird]") << "weird" << false << 0 << true << false;
+}
+
+void tst_SpecificRules::testKeywordGlobalSensitiveLocalInsensitive()
+{
+    m_definition->setKeywordsSensitive("true");
+    KeywordRule rule(m_definition);
+    rule.setInsensitive("true");
+    rule.setList("keywords");
+
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testKeywordGlobalSensitiveLocalInsensitive_data()
+{
+    addCommonColumns();
+
+    commonCasesForKeywords();
+    QTest::newRow("[fOr]") << "fOr" << true << 3 << false << false;
+    QTest::newRow("[whilE") << "whilE" << true << 5 << false << false;
+    QTest::newRow("[bEGIN]") << "bEGIN" << true << 5 << false << false;
+    QTest::newRow("[end]") << "end" << true << 3 << false << false;
+    QTest::newRow("[weird]") << "weird" << true << 5 << false << false;
+}
+
+void tst_SpecificRules::testKeywordGlobalInsensitiveLocalInsensitive()
+{
+    m_definition->setKeywordsSensitive("false");
+    KeywordRule rule(m_definition);
+    rule.setInsensitive("true");
+    rule.setList("keywords");
+
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testKeywordGlobalInsensitiveLocalInsensitive_data()
+{
+    testKeywordGlobalSensitiveLocalInsensitive_data();
+}
+
+void tst_SpecificRules::testKeywordGlobalInsensitiveLocalSensitive()
+{
+    m_definition->setKeywordsSensitive("false");
+    KeywordRule rule(m_definition);
+    rule.setInsensitive("false");
+    rule.setList("keywords");
+
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testKeywordGlobalInsensitiveLocalSensitive_data()
+{
+    testKeywordGlobalSensitiveLocalSensitive_data();
+}
+
+void tst_SpecificRules::noMatchForInt() const
+{
+    QTest::newRow("[1]") << "1" << false << 0 << true << false;
+    QTest::newRow("[1299]") << "1299" << false << 0 << true << false;
+    QTest::newRow("[10]") << "10" << false << 0 << true << false;
+    QTest::newRow("[9]") << "9" << false << 0 << true << false;
+}
+
+void tst_SpecificRules::noMatchForFloat() const
+{
+    QTest::newRow("[4e-11]") << "4e-11" << false << 0 << true << false;
+    QTest::newRow("[1e+5]") << "1e+5" << false << 0 << true << false;
+    QTest::newRow("[7.321E-3]") << "7.321E-3" << false << 0 << true << false;
+    QTest::newRow("[3.2E+4]") << "3.2E+4" << false << 0 << true << false;
+    QTest::newRow("[0.5e-6]") << "0.5e-6" << false << 0 << true << false;
+    QTest::newRow("[0.45]") << "0.45" << false << 0 << true << false;
+    QTest::newRow("[6.e10]") << "6.e10" << false << 0 << true << false;
+    QTest::newRow("[.2e23]") << ".2e23" << false << 0 << true << false;
+    QTest::newRow("[23.]") << "23." << false << 0 << true << false;
+    QTest::newRow("[2.e23]") << "2.e23" << false << 0 << true << false;
+    QTest::newRow("[23e2]") << "23e2" << false << 0 << true << false;
+    QTest::newRow("[4.3e]") << "4.3e" << false << 0 << true << false;
+    QTest::newRow("[4.3ef]") << "4.3ef" << false << 0 << true << false;
+}
+
+void tst_SpecificRules::noMatchForCOctal() const
+{
+    QTest::newRow("[0]") << "0" << false << 0 << true << false;
+    QTest::newRow("[07]") << "07" << false << 0 << true << false;
+    QTest::newRow("[01234567]") << "01234567" << false << 0 << true << false;
+}
+
+void tst_SpecificRules::noMatchForCHex() const
+{
+    QTest::newRow("[0X934AF]") << "0X934AF" << false << 0 << true << false;
+    QTest::newRow("[0x934af]") << "0x934af" << false << 0 << true << false;
+}
+
+void tst_SpecificRules::noMatchForNumber() const
+{
+    QTest::newRow("[a]") << "a" << false << 0 << true << false;
+    QTest::newRow("[#]") << "#" << false << 0 << true << false;
+    QTest::newRow("[ ]") << " " << false << 0 << true << false;
+    QTest::newRow("[a1]") << "a1" << false << 0 << true << false;
+    QTest::newRow("[.e23]") << ".e23" << false << 0 << true << false;
+    QTest::newRow("[.e23]") << ".e23" << false << 0 << true << false;
+
+    // + and - are not directly matched by number rules.
+    QTest::newRow("[+1]") << "+1" << false << 0 << true << false;
+    QTest::newRow("[-1]") << "-1" << false << 0 << true << false;
+}
+
+void tst_SpecificRules::testInt()
+{
+    IntRule rule;
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testInt_data()
+{
+    addCommonColumns();
+
+    noMatchForCOctal();
+    noMatchForCHex();
+    noMatchForNumber();
+
+    QTest::newRow("[1]") << "1" << true << 1 << false << false;
+    QTest::newRow("[1299]") << "1299" << true << 4 << false << false;
+    QTest::newRow("[10]") << "10" << true << 2 << false << false;
+    QTest::newRow("[9]") << "9" << true << 1 << false << false;
+
+    // LL, U, and others are matched through child rules.
+    QTest::newRow("[234U]") << "234U" << true << 3 << false << false;
+    QTest::newRow("[234LL]") << "234LL" << true << 3 << false << false;
+}
+
+void tst_SpecificRules::testFloat()
+{
+    FloatRule rule;
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testFloat_data()
+{
+    addCommonColumns();
+
+    noMatchForInt();
+    noMatchForCOctal();
+    noMatchForCHex();
+    noMatchForNumber();
+
+    QTest::newRow("[4e-11]") << "4e-11" << true << 5 << false << false;
+    QTest::newRow("[1e+5]") << "1e+5" << true << 4 << false << false;
+    QTest::newRow("[7.321E-3]") << "7.321E-3" << true << 8 << false << false;
+    QTest::newRow("[3.2E+4]") << "3.2E+4" << true << 6 << false << false;
+    QTest::newRow("[0.5e-6]") << "0.5e-6" << true << 6 << false << false;
+    QTest::newRow("[0.45]") << "0.45" << true << 4 << false << false;
+    QTest::newRow("[6.e10]") << "6.e10" << true << 5 << false << false;
+    QTest::newRow("[.2e23]") << ".2e23" << true << 5 << false << false;
+    QTest::newRow("[23.]") << "23." << true << 3 << false << false;
+    QTest::newRow("[2.e23]") << "2.e23" << true << 5 << false << false;
+    QTest::newRow("[23e2]") << "23e2" << true << 4 << false << false;
+
+    // F, L, and others are matched through child rules.
+    QTest::newRow("[6.e10f]") << "6.e10f" << true << 5 << false << false;
+    QTest::newRow("[0.5e-6F]") << "0.5e-6F" << true << 6 << false << false;
+    QTest::newRow("[23.f]") << "23.f" << true << 3 << false << false;
+    QTest::newRow("[.2L]") << ".2L" << true << 2 << false << false;
+}
+
+void tst_SpecificRules::testCOctal()
+{
+    HlCOctRule rule;
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testCOctal_data()
+{
+    addCommonColumns();
+
+    noMatchForInt();
+    noMatchForCHex();
+    noMatchForNumber();
+
+    QTest::newRow("[0]") << "0" << true << 1 << false << false;
+    QTest::newRow("[07]") << "07" << true << 2 << false << false;
+    QTest::newRow("[01234567]") << "01234567" << true << 8 << false << false;
+    QTest::newRow("[012345678]") << "012345678" << true << 8 << false << false;
+    QTest::newRow("[0888]") << "0888" << true << 1 << false << false;
+}
+
+void tst_SpecificRules::testCHex()
+{
+    HlCHexRule rule;
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testCHex_data()
+{
+    addCommonColumns();
+
+    noMatchForInt();
+    noMatchForFloat();
+    noMatchForCOctal();
+    noMatchForNumber();
+
+    QTest::newRow("[0X934AF]") << "0X934AF" << true << 7 << false << false;
+    QTest::newRow("[0x934af]") << "0x934af" << true << 7 << false << false;
+    QTest::newRow("[0x2ik]") << "0x2ik" << true << 3 << false << false;
+}
+
+void tst_SpecificRules::testCString()
+{
+    HlCStringCharRule rule;
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testCString_data()
+{
+    addCommonColumns();
+
+    // Escape sequences
+    QTest::newRow("[\\a]") << "\\a" << true << 2 << false << false;
+    QTest::newRow("[\\b]") << "\\b" << true << 2 << false << false;
+    QTest::newRow("[\\e]") << "\\e" << true << 2 << false << false;
+    QTest::newRow("[\\f]") << "\\f" << true << 2 << false << false;
+    QTest::newRow("[\\n]") << "\\n" << true << 2 << false << false;
+    QTest::newRow("[\\r]") << "\\r" << true << 2 << false << false;
+    QTest::newRow("[\\t]") << "\\t" << true << 2 << false << false;
+    QTest::newRow("[\\v]") << "\\v" << true << 2 << false << false;
+    QTest::newRow("[\\?]") << "\\?" << true << 2 << false << false;
+    QTest::newRow("[\\']") << "\\'" << true << 2 << false << false;
+    QTest::newRow("[\\\"]") << "\\\"" << true << 2 << false << false;
+    QTest::newRow("[\\\\]") << "\\\\" << true << 2 << false << false;
+    QTest::newRow("[\\c]") << "\\c" << false << 0 << true << false;
+    QTest::newRow("[x]") << "x" << false << 0 << true << false;
+    QTest::newRow("[ ]") << " " << false << 0 << true << false;
+    QTest::newRow("[a]") << "x" << false << 0 << true << false;
+    QTest::newRow("[r]") << "r" << false << 0 << true << false;
+    QTest::newRow("[//]") << "//" << false << 0 << true << false;
+
+    // Octal values
+    QTest::newRow("[\\1]") << "\\1" << true << 2 << false << false;
+    QTest::newRow("[\\12]") << "\\12" << true << 3 << false << false;
+    QTest::newRow("[\\123]") << "\\123" << true << 4 << false << false;
+    QTest::newRow("[\\1234]") << "\\1234" << true << 4 << false << false;
+    QTest::newRow("[\\123x]") << "\\123x" << true << 4 << false << false;
+
+    // Hex values
+    QTest::newRow("[\\xa]") << "\\xa" << true << 3 << false << false;
+    QTest::newRow("[\\xA]") << "\\xA" << true << 3 << false << false;
+    QTest::newRow("[\\Xa]") << "\\Xa" << false << 0 << true << false;
+    QTest::newRow("[\\xA10]") << "\\xA10" << true << 5 << false << false;
+    QTest::newRow("[\\xA0123456789]") << "\\xA0123456789" << true << 13 << false << false;
+    QTest::newRow("[\\xABCDEF]") << "\\xABCDEF" << true << 8 << false << false;
+    QTest::newRow("[\\xABCDEFGHI]") << "\\xABCDEFGHI" << true << 8 << false << false;
+}
+
+void tst_SpecificRules::testCChar()
+{
+    HlCCharRule rule;
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testCChar_data()
+{
+    addCommonColumns();
+
+    // Escape sequences
+    QTest::newRow("[\'\\a\']") << "\'\\a\'" << true << 4 << false << false;
+    QTest::newRow("[\'\\b\']") << "\'\\b\'" << true << 4 << false << false;
+    QTest::newRow("[\'\\e\']") << "\'\\e\'" << true << 4 << false << false;
+    QTest::newRow("[\'\\f\']") << "\'\\f\'" << true << 4 << false << false;
+    QTest::newRow("[\'\\n\']") << "\'\\n\'" << true << 4 << false << false;
+    QTest::newRow("[\'\\r\']") << "\'\\r\'" << true << 4 << false << false;
+    QTest::newRow("[\'\\t\']") << "\'\\t\'" << true << 4 << false << false;
+    QTest::newRow("[\'\\v\']") << "\'\\v\'" << true << 4 << false << false;
+    QTest::newRow("[\'\\?\']") << "\'\\?\'" << true << 4 << false << false;
+    QTest::newRow("[\'\\'\']") << "\'\\'\'" << true << 4 << false << false;
+    QTest::newRow("[\'\\\"\']") << "\'\\\"\'" << true << 4 << false << false;
+    QTest::newRow("[\'\\\\\']") << "\'\\\\\'" << true << 4 << false << false;
+    QTest::newRow("[\'\\c\']") << "\'\\c\'" << false << 0 << true << false;
+    QTest::newRow("[x]") << "x" << false << 0 << true << false;
+    QTest::newRow("[ ]") << " " << false << 0 << true << false;
+    QTest::newRow("[a]") << "x" << false << 0 << true << false;
+    QTest::newRow("[r]") << "r" << false << 0 << true << false;
+    QTest::newRow("[//]") << "//" << false << 0 << true << false;
+}
+
+void tst_SpecificRules::testRangeDetect()
+{
+    QFETCH(QString, c);
+    QFETCH(QString, c1);
+    RangeDetectRule rule;
+    rule.setChar(c);
+    rule.setChar1(c1);
+
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testRangeDetect_data()
+{
+    QTest::addColumn<QString>("c");
+    QTest::addColumn<QString>("c1");
+    addCommonColumns();
+
+    QTest::newRow("[<>] against [<QString>]") << "<" << ">" << "<QString>"
+            << true << 9 << false << false;
+    QTest::newRow("[<>] against <x>") << "<" << ">" << "<x>" << true << 3 << false << false;
+    QTest::newRow("[<>] against <   >") << "<" << ">" << "<   >" << true << 5 << false << false;
+    QTest::newRow("[<>] against <x>abc") << "<" << ">" << "<x>abc" << true << 3 << false << false;
+    QTest::newRow("[<>] against <x> ") << "<" << ">" << "<x> " << true << 3 << false << false;
+    QTest::newRow("[<>] against abc") << "<" << ">" << "abc" << false << 0 << true << false;
+    QTest::newRow("[<>] against <abc") << "<" << ">" << "<abc" << false << 0 << true << false;
+    QTest::newRow("[<>] against abc<") << "<" << ">" << "abc<" << false << 0 << true << false;
+    QTest::newRow("[<>] against a<bc") << "<" << ">" << "a<bc" << false << 0 << true << false;
+    QTest::newRow("[<>] against abc<") << "<" << ">" << "abc<" << false << 0 << true << false;
+    QTest::newRow("[\"\"] against \"test.h\"") << "\"" << "\"" << "\"test.h\""
+            << true << 8 << false << false;
+}
+
+void tst_SpecificRules::testLineContinue()
+{
+    LineContinueRule rule;
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testLineContinue_data()
+{
+    addCommonColumns();
+
+    QTest::newRow("\\") << "\\" << true << 0 << false << true;
+    QTest::newRow("\\\\") << "\\\\" << false << 0 << true << false;
+    QTest::newRow("\\x") << "\\x" << false << 0 << true << false;
+    QTest::newRow("x\\") << "x\\" << false << 0 << true << false;
+    QTest::newRow("x") << "x" << false << 0 << true << false;
+    QTest::newRow("/") << "/" << false << 0 << true << false;
+}
+
+void tst_SpecificRules::testDetectSpaces()
+{
+    DetectSpacesRule rule;
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testDetectSpaces_data()
+{
+    addCommonColumns();
+
+    QTest::newRow(" ") << " " << true << 1 << true << false;
+    QTest::newRow("    ") << "    " << true << 4 << true << false;
+    QTest::newRow("\t") << "\t" << true << 1 << true << false;
+    QTest::newRow("x") << "x" << false << 0 << true << false;
+    QTest::newRow("#") << "#" << false << 0 << true << false;
+}
+
+void tst_SpecificRules::testDetectIdentifier()
+{
+    DetectIdentifierRule rule;
+    testMatch(rule);
+}
+
+void tst_SpecificRules::testDetectIdentifier_data()
+{
+    addCommonColumns();
+
+    QTest::newRow("name") << "name" << true << 4 << false << false;
+    QTest::newRow("x") << "x" << true << 1 << false << false;
+    QTest::newRow("x1") << "x1" << true << 2 << false << false;
+    QTest::newRow("1x") << "1x" << false << 0 << true << false;
+    QTest::newRow("_x") << "_x" << true << 2 << false << false;
+    QTest::newRow("___x") << "___x" << true << 4 << false << false;
+    QTest::newRow("-x") << "-x" << false << 0 << true << false;
+    QTest::newRow("@x") << "@x" << false << 0 << true << false;
+    QTest::newRow("+x") << "+x" << false << 0 << true << false;
+    QTest::newRow("#x") << "#x" << false << 0 << true << false;
+    QTest::newRow("x_x") << "x_x" << true << 3 << false << false;
+    QTest::newRow("x1x") << "x1x" << true << 3 << false << false;
+    QTest::newRow("x#x") << "x#x" << true << 1 << false << false;
+    QTest::newRow("x-x") << "x-x" << true << 1 << false << false;
+    QTest::newRow("abc_") << "abc_" << true << 4 << false << false;
+    QTest::newRow("abc____") << "abc____" << true << 7 << false << false;
+    QTest::newRow("abc-") << "abc-" << true << 3 << false << false;
+    QTest::newRow("abc$") << "abc$" << true << 3 << false << false;
+}
+
+QTEST_MAIN(tst_SpecificRules)
+#include "tst_specificrules.moc"
index 0bb6dec..2fbb474 100644 (file)
 
 using namespace CPlusPlus;
 
-class ForEachNode: protected ASTVisitor
-{
-    Document::Ptr doc;
-    AST *pattern;
-
-public:
-    ForEachNode(Document::Ptr doc)
-        : ASTVisitor(doc->translationUnit()),
-          matcher() {}
-
-    void operator()() { accept(doc->translationUnit()->ast()); }
-
-protected:
-    using ASTVisitor::visit;
-
-    virtual bool preVisit(AST *ast)
-    {
-        ir.reset();
-        IfStatementAST *pattern = ir.IfStatement(ir.SimpleName());
-
-        //CompoundStatementAST *pattern = ir.CompoundStatement();
-
-        if (ast->match(ast, pattern, &matcher))
-            translationUnit()->warning(ast->firstToken(), "matched");
-
-        return true;
-    }
-
-
-    ASTPatternBuilder ir;
-    ASTMatcher matcher;
-};
-
 int main(int argc, char *argv[])
 {
     QCoreApplication app(argc, argv);
@@ -107,9 +74,6 @@ int main(int argc, char *argv[])
         doc->control()->setDiagnosticClient(0);
         doc->setSource(source);
         doc->parse();
-
-        ForEachNode forEachNode(doc);
-        forEachNode();
     }
 
     return EXIT_SUCCESS;
index 732e2c8..b8cd6ce 100644 (file)
@@ -248,7 +248,7 @@ void testPeekAndPoke3()
             struct { int i; int b; };
             struct { float f; };
             double d;
-        } a = { 42, 43 };
+        } a = { { 42, 43 } };
         a.i = 1; // Break here. Expand a. Step.
         a.i = 2; // Change a.i in Locals view to 0. This changes f, d but expectedly not b. Step.
         a.i = 3; // Continue.
@@ -318,18 +318,19 @@ void testAnonymous()
 #endif
 }
 
-void testFunctionPointer()
+typedef void (*func_t)();
+func_t testFunctionPointer()
 {
-    typedef void (*func_t)();
     func_t f1 = testAnonymous;
-    func_t f2 = testFunctionPointer;
-    func_t f3 = testFunctionPointer;
+    func_t f2 = testPeekAndPoke3;
+    func_t f3 = testPeekAndPoke3;
     Q_UNUSED(f1);
     Q_UNUSED(f2);
     Q_UNUSED(f3);
+    return f1;
 }
 
-void testQByteArray()
+QByteArray testQByteArray()
 {
     QByteArray ba = "Hello";
     ba += '"';
@@ -345,6 +346,7 @@ void testQByteArray()
     ba += char(0);
     ba += 1;
     ba += 2;
+    return ba;
 }
 
 static void throwit1()
@@ -368,7 +370,7 @@ int testCatchThrow()
     return gotit;
 }
 
-void testQDateTime()
+QDateTime testQDateTime()
 {
     QDateTime date;
     date = QDateTime::currentDateTime();
@@ -376,18 +378,20 @@ void testQDateTime()
     date = date.addSecs(5);
     date = date.addSecs(5);
     date = date.addSecs(5);
+    return date;
 }
 
-void testQFileInfo()
+QFileInfo testQFileInfo()
 {
     QFileInfo fi("/tmp/t");
     QString s = fi.absoluteFilePath();
     s = fi.bundleName();
     s = fi.bundleName();
     s = fi.bundleName();
+    return fi;
 }
 
-void testQHash()
+QHash<int, float> testQHash()
 {
 #if 1
     QHash<int, float> hgg0;
@@ -439,6 +443,7 @@ void testQHash()
     hash.insert("Welt", QPointer<QObject>(&ob));
     hash.insert(".", QPointer<QObject>(&ob));
 #endif
+    return hgg0;
 }
 
 void testQImage()
@@ -908,7 +913,7 @@ void testStdHashSet()
 #endif
 }
 
-void testStdList()
+std::list<int> testStdList()
 {
     std::list<int> big;
     for (int i = 0; i < 10000; ++i)
@@ -948,6 +953,7 @@ void testStdList()
     vec.push_back(true);
     vec.push_back(false);
 #endif
+    return big;
 }
 
 void testStdMap()
@@ -1008,7 +1014,7 @@ void testStdMap()
 #endif
 }
 
-void testStdSet()
+std::set<int> testStdSet()
 {
     std::set<int> hgg0;
     hgg0.insert(11);
@@ -1022,9 +1028,10 @@ void testStdSet()
     std::set<QPointer<QObject> > hash;
     QPointer<QObject> ptr(&ob);
 #endif
+    return hgg0;
 }
 
-void testStdStack()
+std::stack<int> testStdStack()
 {
     std::stack<int *> plist1;
     plist1.push(new int(1));
@@ -1045,9 +1052,11 @@ void testStdStack()
     std::stack<Foo> flist;
     flist.push(1);
     flist.push(2);
+
+    return flist2;
 }
 
-void testStdString()
+std::string testStdString()
 {
     QString foo;
     std::string str;
@@ -1083,9 +1092,11 @@ void testStdString()
     v.push_back(str);
     v.push_back(str);
     v.push_back(str);
+
+    return str;
 }
 
-void testStdVector()
+std::vector<int> testStdVector()
 {
     std::vector<int *> plist1;
     plist1.push_back(new int(1));
@@ -1119,6 +1130,8 @@ void testStdVector()
     std::vector<bool> vec;
     vec.push_back(true);
     vec.push_back(false);
+
+    return flist2;
 }
 
 void testQStandardItemModel()
@@ -1140,7 +1153,7 @@ void testQStandardItemModel()
     ++i;
 }
 
-void testQStack()
+QStack<int> testQStack()
 {
     QVector<int> bigv;
     for (int i = 0; i < 10; ++i)
@@ -1162,9 +1175,10 @@ void testQStack()
     QStack<bool> vec;
     vec.append(true);
     vec.append(false);
+    return big;
 }
 
-void testQString()
+QString testQString()
 {
     QUrl url(QString("http://www.nokia.com"));
 
@@ -1176,6 +1190,7 @@ void testQString()
     str += " World ";
     str += " World ";
     str += " World ";
+    return str;
 }
 
 void testQString3()
@@ -1194,7 +1209,7 @@ void testQString3()
     delete pstring;
 }
 
-void testQStringList()
+QStringList testQStringList()
 {
     QStringList l;
     l << "Hello ";
@@ -1202,14 +1217,16 @@ void testQStringList()
     l << " fat ";
     l.takeFirst();
     l << " World ";
+    return l;
 }
 
-void testStruct()
+Foo testStruct()
 {
     Foo f(2);
     f.doit();
     f.doit();
     f.doit();
+    return f;
 }
 
 class Thread : public QThread
@@ -1219,10 +1236,13 @@ public:
 
     void run()
     {
+        int j = 2;
+        ++j;
         for (int i = 0; i != 100000; ++i) {
             //sleep(1);
             std::cerr << m_id;
         }
+        std::cerr << j;
     }
 
 private:
@@ -1246,10 +1266,12 @@ void testQVariant1()
     v = 1.0;
     v = "string";
     v = QRect(100, 200, 300, 400);
+    v = QRectF(100, 200, 300, 400);
     v = 1;
+    //return v;
 }
 
-void testQVariant2()
+QVariant testQVariant2()
 {
     QVariant value;
     QVariant::Type t = QVariant::String;
@@ -1292,18 +1314,28 @@ void testQVariant2()
     var.setValue(my);
     var.setValue(my);
 #endif
+    return QVariant("sss");
 }
 
-void testQVariant3()
+QVariant testQVariant3()
 {
+    QVariantList vl;
+    vl.append(QVariant(1));
+    vl.append(QVariant(2));
+    vl.append(QVariant("Some String"));
+    vl.append(QVariant(21));
+    vl.append(QVariant(22));
+    vl.append(QVariant("2Some String"));
+
     QList<int> list;
     list << 1 << 2 << 3;
     QVariant variant = qVariantFromValue(list);
     list.clear();
     list = qVariantValue<QList<int> >(variant);
+    return QVariant("xxx");
 }
 
-void testQVector()
+QVector<int> testQVector()
 {
     QVector<int> big(10000);
 
@@ -1323,15 +1355,18 @@ void testQVector()
     QVector<bool> vec;
     vec.append(true);
     vec.append(false);
+
+    return big;
 }
 
-void testQVectorOfQList()
+QVector<QList<int> > testQVectorOfQList()
 {
     QVector<QList<int> > v;
     QVector<QList<int> > *pv = &v;
     v.append(QList<int>() << 1);
     v.append(QList<int>() << 2 << 3);
     Q_UNUSED(pv);
+    return v;
 }
 
 
@@ -1524,6 +1559,7 @@ void testQHash1()
 void testPointer()
 {
     Foo *f = new Foo();
+    Q_UNUSED(f);
     int i = 0;
     ++i;
     ++i;
@@ -1591,8 +1627,35 @@ int testReference()
     return a.size() + b.size() + c.size();
 }
 
+struct Color
+{
+    int r,g,b,a;
+    Color() { r = 1, g = 2, b = 3, a = 4; }
+};
+
+Color testColor()
+{
+    Color c;
+    c.r = 5;
+    return c;
+}
+
+int fooii()
+{
+    return 3;
+}
+
+void testStuff()
+{
+    int i = 0;
+    int *p = &i;
+    ++*p;
+}
+
 int main(int argc, char *argv[])
 {
+    testColor();
+    testStuff();
     testPeekAndPoke3();
     testFunctionPointer();
     testAnonymous();
@@ -1641,8 +1704,8 @@ int main(int argc, char *argv[])
     testPlugin();
     testQList();
     testQLinkedList();
-       char *s = "aöa";
-       wchar_t *w = L"aöa";
+    const char *s = "aöa";
+    const wchar_t *w = L"aöa";
     testNamespace();
     //return 0;
     testQHash();
@@ -1656,7 +1719,7 @@ int main(int argc, char *argv[])
     #endif
     testQStringList();
     testStruct();
-    //testThreads();
+    testQThread();
     testQVariant1();
     testQVariant2();
     testQVariant3();